refactor source code

This commit is contained in:
2024-10-29 17:42:54 +07:00
parent 3b23d9e0b7
commit 152bb50da8
83 changed files with 8473 additions and 7577 deletions

View File

@@ -1,11 +1,11 @@
{ {
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false }, "vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
"files": { "ignoreUnknown": false, "ignore": [] }, "files": { "ignoreUnknown": false, "ignore": ["dist"] },
"formatter": { "formatter": {
"enabled": true, "enabled": true,
"useEditorconfig": true, "useEditorconfig": true,
"formatWithErrors": false, "formatWithErrors": true,
"indentStyle": "space", "indentStyle": "space",
"indentWidth": 2, "indentWidth": 2,
"lineEnding": "lf", "lineEnding": "lf",

View File

@@ -1,4 +1,4 @@
import type { CodegenConfig } from '@graphql-codegen/cli'; import type { CodegenConfig } from '@graphql-codegen/cli'
const config: CodegenConfig = { const config: CodegenConfig = {
overwrite: true, overwrite: true,
@@ -8,6 +8,6 @@ const config: CodegenConfig = {
plugins: ['typescript', 'typescript-resolvers'], plugins: ['typescript', 'typescript-resolvers'],
}, },
}, },
}; }
export default config; export default config

View File

@@ -20,7 +20,7 @@
"prisma:format": "npx prisma format --schema=./epess-database/prisma/schema.prisma", "prisma:format": "npx prisma format --schema=./epess-database/prisma/schema.prisma",
"prisma:studio": "npx prisma studio --schema=./epess-database/prisma/schema.prisma", "prisma:studio": "npx prisma studio --schema=./epess-database/prisma/schema.prisma",
"biome:check": "biome check", "biome:check": "biome check",
"biome:fix": "biome fix", "biome:fix": "biome fix --write",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"prettier": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "prettier": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"test": "jest", "test": "jest",
@@ -123,19 +123,13 @@
"ws": "^8.18.0" "ws": "^8.18.0"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": ["js", "json", "ts"],
"js",
"json",
"ts"
],
"rootDir": "src", "rootDir": "src",
"testRegex": ".*\\.spec\\.ts$", "testRegex": ".*\\.spec\\.ts$",
"transform": { "transform": {
"^.+\\.(t|j)s$": "ts-jest" "^.+\\.(t|j)s$": "ts-jest"
}, },
"collectCoverageFrom": [ "collectCoverageFrom": ["**/*.(t|j)s"],
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage", "coverageDirectory": "../coverage",
"testEnvironment": "node" "testEnvironment": "node"
}, },

View File

@@ -1,5 +1,5 @@
import { AdminNoteSchema } from './adminnote.schema'; import { AdminNoteSchema } from './adminnote.schema'
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
@Module({ @Module({
providers: [AdminNoteSchema], providers: [AdminNoteSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class AdminNoteSchema extends PothosSchema { export class AdminNoteSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class AdminNoteSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -71,7 +71,7 @@ export class AdminNoteSchema extends PothosSchema {
description: 'The resume the admin note is associated with.', description: 'The resume the admin note is associated with.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -81,18 +81,18 @@ export class AdminNoteSchema extends PothosSchema {
type: this.adminNote(), type: this.adminNote(),
args: this.builder.generator.findUniqueArgs('AdminNote'), args: this.builder.generator.findUniqueArgs('AdminNote'),
description: 'Retrieve a single admin note by its unique identifier.', description: 'Retrieve a single admin note by its unique identifier.',
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.adminNote.findUnique({ return await this.prisma.adminNote.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
adminNotes: t.prismaField({ adminNotes: t.prismaField({
type: [this.adminNote()], type: [this.adminNote()],
args: this.builder.generator.findManyArgs('AdminNote'), args: this.builder.generator.findManyArgs('AdminNote'),
description: 'Retrieve a list of admin notes.', description: 'Retrieve a list of admin notes.',
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.adminNote.findMany({ return await this.prisma.adminNote.findMany({
...query, ...query,
where: args.filter ?? undefined, where: args.filter ?? undefined,
@@ -100,10 +100,10 @@ export class AdminNoteSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
}); })
}, },
}), }),
})); }))
// Mutations // Mutations
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -115,11 +115,11 @@ export class AdminNoteSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.adminNote.create({ return await this.prisma.adminNote.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
@@ -135,12 +135,12 @@ export class AdminNoteSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.adminNote.update({ return await this.prisma.adminNote.update({
...query, ...query,
where: args.where, where: args.where,
data: args.data, data: args.data,
}); })
}, },
}), }),
@@ -152,13 +152,13 @@ export class AdminNoteSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.adminNote.delete({ return await this.prisma.adminNote.delete({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,7 +1,7 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { AppConfigSchema } from './appconfig.schema'; import { AppConfigSchema } from './appconfig.schema'
import { AppConfigService } from './appconfig.service'; import { AppConfigService } from './appconfig.service'
@Global() @Global()
@Module({ @Module({

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from 'src/Graphql/graphql.builder'; import { Builder } from 'src/Graphql/graphql.builder'
import { AppConfigService } from './appconfig.service'; import { AppConfigService } from './appconfig.service'
import { PrismaService } from 'src/Prisma/prisma.service'; import { PrismaService } from 'src/Prisma/prisma.service'
@Injectable() @Injectable()
export class AppConfigSchema extends PothosSchema { export class AppConfigSchema extends PothosSchema {
@@ -15,7 +15,7 @@ export class AppConfigSchema extends PothosSchema {
private readonly appConfigService: AppConfigService, private readonly appConfigService: AppConfigService,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -39,7 +39,7 @@ export class AppConfigSchema extends PothosSchema {
description: 'Whether the config is visible', description: 'Whether the config is visible',
}), }),
}), }),
}); })
} }
@PothosRef() @PothosRef()
@@ -57,7 +57,7 @@ export class AppConfigSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
}); })
}, },
}), }),
appConfig: t.prismaField({ appConfig: t.prismaField({
@@ -68,10 +68,10 @@ export class AppConfigSchema extends PothosSchema {
return await this.prisma.config.findUnique({ return await this.prisma.config.findUnique({
...query, ...query,
where: args.where ?? undefined, where: args.where ?? undefined,
}); })
}, },
}), }),
})); }))
// Mutations // Mutations
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -88,7 +88,7 @@ export class AppConfigSchema extends PothosSchema {
return await this.prisma.config.create({ return await this.prisma.config.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
createAppConfigs: t.prismaField({ createAppConfigs: t.prismaField({
@@ -104,9 +104,9 @@ export class AppConfigSchema extends PothosSchema {
return await this.prisma.config.createManyAndReturn({ return await this.prisma.config.createManyAndReturn({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { CategorySchema } from './category.schema'; import { CategorySchema } from './category.schema'
@Module({ @Module({
providers: [CategorySchema], providers: [CategorySchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class CategorySchema extends PothosSchema { export class CategorySchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class CategorySchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -32,7 +32,7 @@ export class CategorySchema extends PothosSchema {
description: 'The subcategory of the category.', description: 'The subcategory of the category.',
}), }),
}), }),
}); })
} }
@PothosRef() @PothosRef()
@@ -58,7 +58,7 @@ export class CategorySchema extends PothosSchema {
'The service and category that the subcategory belongs to.', 'The service and category that the subcategory belongs to.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -76,7 +76,7 @@ export class CategorySchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
category: t.prismaField({ category: t.prismaField({
@@ -87,7 +87,7 @@ export class CategorySchema extends PothosSchema {
return await this.prisma.category.findUnique({ return await this.prisma.category.findUnique({
...query, ...query,
where: args.where ?? undefined, where: args.where ?? undefined,
}); })
}, },
}), }),
subCategories: t.prismaField({ subCategories: t.prismaField({
@@ -102,10 +102,10 @@ export class CategorySchema extends PothosSchema {
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
}); })
}, },
}), }),
})); }))
// mutation // mutation
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -121,7 +121,7 @@ export class CategorySchema extends PothosSchema {
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.category.create({ return await this.prisma.category.create({
data: args.input, data: args.input,
}); })
}, },
}), }),
createManyCategories: t.prismaField({ createManyCategories: t.prismaField({
@@ -137,7 +137,7 @@ export class CategorySchema extends PothosSchema {
return await this.prisma.category.createManyAndReturn({ return await this.prisma.category.createManyAndReturn({
data: args.data, data: args.data,
skipDuplicates: true, skipDuplicates: true,
}); })
}, },
}), }),
@@ -153,9 +153,9 @@ export class CategorySchema extends PothosSchema {
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
return await this.prisma.subCategory.create({ return await this.prisma.subCategory.create({
data: args.input, data: args.input,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { CenterSchema } from './center.schema'; import { CenterSchema } from './center.schema'
@Module({ @Module({
providers: [CenterSchema], providers: [CenterSchema],

View File

@@ -1,15 +1,15 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { MinioService } from '../Minio/minio.service'; import { MinioService } from '../Minio/minio.service'
import { CenterStatus, Role } from '@prisma/client'; import { CenterStatus, Role } from '@prisma/client'
import { MailService } from '../Mail/mail.service'; import { MailService } from '../Mail/mail.service'
@Injectable() @Injectable()
export class CenterSchema extends PothosSchema { export class CenterSchema extends PothosSchema {
constructor( constructor(
@@ -18,7 +18,7 @@ export class CenterSchema extends PothosSchema {
private readonly minioService: MinioService, private readonly minioService: MinioService,
private readonly mailService: MailService, private readonly mailService: MailService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -85,7 +85,7 @@ export class CenterSchema extends PothosSchema {
description: 'The ID of the uploaded file.', description: 'The ID of the uploaded file.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -96,25 +96,25 @@ export class CenterSchema extends PothosSchema {
'Retrieve a list of centers with optional filtering, ordering, and pagination.', 'Retrieve a list of centers with optional filtering, ordering, and pagination.',
type: [this.center()], type: [this.center()],
args: this.builder.generator.findManyArgs('Center'), args: this.builder.generator.findManyArgs('Center'),
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.center.findMany({ return await this.prisma.center.findMany({
...query, ...query,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
center: t.prismaField({ center: t.prismaField({
type: this.center(), type: this.center(),
description: 'Retrieve a single center by its unique identifier.', description: 'Retrieve a single center by its unique identifier.',
args: this.builder.generator.findUniqueArgs('Center'), args: this.builder.generator.findUniqueArgs('Center'),
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.center.findUnique({ return await this.prisma.center.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
// get current center of centermentor by providing userId // get current center of centermentor by providing userId
@@ -124,7 +124,7 @@ export class CenterSchema extends PothosSchema {
args: { args: {
userId: t.arg({ type: 'String', required: true }), userId: t.arg({ type: 'String', required: true }),
}, },
resolve: async (query, root, args) => { resolve: async (_query, _root, args) => {
return await this.prisma.center.findFirst({ return await this.prisma.center.findFirst({
where: { where: {
centerMentors: { centerMentors: {
@@ -133,10 +133,10 @@ export class CenterSchema extends PothosSchema {
}, },
}, },
}, },
}); })
}, },
}), }),
})); }))
// mutation section // mutation section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -149,11 +149,11 @@ export class CenterSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.center.create({ return await this.prisma.center.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
updateCenter: t.prismaField({ updateCenter: t.prismaField({
@@ -169,12 +169,12 @@ export class CenterSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.center.update({ return await this.prisma.center.update({
...query, ...query,
where: args.where, where: args.where,
data: args.input, data: args.input,
}); })
}, },
}), }),
deleteCenter: t.prismaField({ deleteCenter: t.prismaField({
@@ -186,11 +186,11 @@ export class CenterSchema extends PothosSchema {
required: true, required: true,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.center.delete({ return await this.prisma.center.delete({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
approveOrRejectCenter: t.prismaField({ approveOrRejectCenter: t.prismaField({
@@ -210,33 +210,33 @@ export class CenterSchema extends PothosSchema {
required: false, required: false,
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, _root, args) => {
return await this.prisma.$transaction(async (prisma) => { return await this.prisma.$transaction(async (prisma) => {
const center = await prisma.center.findUnique({ const center = await prisma.center.findUnique({
...query, ...query,
where: { where: {
id: args.centerId, id: args.centerId,
}, },
}); })
if (!center) { if (!center) {
throw new Error('Center not found'); throw new Error('Center not found')
} }
// check if center is already approved or rejected // check if center is already approved or rejected
if (center.centerStatus !== CenterStatus.PENDING) { if (center.centerStatus !== CenterStatus.PENDING) {
throw new Error('Center is already approved or rejected'); throw new Error('Center is already approved or rejected')
} }
// find user and promote to center owner // find user and promote to center owner
const centerOwnerId = center.centerOwnerId; const centerOwnerId = center.centerOwnerId
if (!centerOwnerId) { if (!centerOwnerId) {
throw new Error('User not found'); throw new Error('User not found')
} }
const centerOwner = await prisma.user.findUnique({ const centerOwner = await prisma.user.findUnique({
where: { where: {
id: centerOwnerId, id: centerOwnerId,
}, },
}); })
if (!centerOwner) { if (!centerOwner) {
throw new Error('User not found'); throw new Error('User not found')
} }
await prisma.user.update({ await prisma.user.update({
where: { where: {
@@ -245,7 +245,7 @@ export class CenterSchema extends PothosSchema {
data: { data: {
role: Role.CENTER_OWNER, role: Role.CENTER_OWNER,
}, },
}); })
// update center status // update center status
const updatedCenter = await prisma.center.update({ const updatedCenter = await prisma.center.update({
...query, ...query,
@@ -257,7 +257,7 @@ export class CenterSchema extends PothosSchema {
? CenterStatus.APPROVED ? CenterStatus.APPROVED
: CenterStatus.REJECTED, : CenterStatus.REJECTED,
}, },
}); })
// mail to center owner if approved // mail to center owner if approved
if (args.approve) { if (args.approve) {
try { try {
@@ -268,9 +268,9 @@ export class CenterSchema extends PothosSchema {
{ {
CENTER_NAME: center.name, CENTER_NAME: center.name,
}, },
); )
} catch (error) { } catch (error) {
Logger.error(error, 'CenterSchema'); Logger.error(error, 'CenterSchema')
} }
} }
if (!args.approve) { if (!args.approve) {
@@ -284,15 +284,15 @@ export class CenterSchema extends PothosSchema {
CENTER_NAME: center.name, CENTER_NAME: center.name,
ADMIN_NOTE: args.adminNote, ADMIN_NOTE: args.adminNote,
}, },
); )
} catch (error) { } catch (error) {
Logger.error(error, 'CenterSchema'); Logger.error(error, 'CenterSchema')
} }
} }
return updatedCenter; return updatedCenter
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,6 +1,6 @@
import { CenterMentorSchema } from './centermentor.schema'; import { CenterMentorSchema } from './centermentor.schema'
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { UserModule } from 'src/User/user.module'; import { UserModule } from 'src/User/user.module'
@Module({ @Module({
imports: [UserModule], imports: [UserModule],

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ChatroomSchema } from './chatroom.schema'; import { ChatroomSchema } from './chatroom.schema'
@Module({ @Module({
providers: [ChatroomSchema], providers: [ChatroomSchema],

View File

@@ -1,13 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { ChatRoomType } from '@prisma/client'; import { ChatRoomType } from '@prisma/client'
@Injectable() @Injectable()
export class ChatroomSchema extends PothosSchema { export class ChatroomSchema extends PothosSchema {
@@ -15,7 +15,7 @@ export class ChatroomSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -59,7 +59,7 @@ export class ChatroomSchema extends PothosSchema {
description: 'The meeting room.', description: 'The meeting room.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -69,11 +69,11 @@ export class ChatroomSchema extends PothosSchema {
type: this.chatRoom(), type: this.chatRoom(),
description: 'Retrieve a single chat room by its unique identifier.', description: 'Retrieve a single chat room by its unique identifier.',
args: this.builder.generator.findUniqueArgs('ChatRoom'), args: this.builder.generator.findUniqueArgs('ChatRoom'),
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.chatRoom.findUnique({ return await this.prisma.chatRoom.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
@@ -82,16 +82,16 @@ export class ChatroomSchema extends PothosSchema {
description: description:
'Retrieve a list of chat rooms with optional filtering, ordering, and pagination.', 'Retrieve a list of chat rooms with optional filtering, ordering, and pagination.',
args: this.builder.generator.findManyArgs('ChatRoom'), args: this.builder.generator.findManyArgs('ChatRoom'),
resolve: async (query, root, args, ctx, info) => { resolve: async (query, _root, args, _ctx, _info) => {
return await this.prisma.chatRoom.findMany({ return await this.prisma.chatRoom.findMany({
...query, ...query,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -5,9 +5,9 @@ import {
ExecutionContext, ExecutionContext,
Inject, Inject,
UnauthorizedException, UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common'
import Clerk from '@clerk/express'; import Clerk from '@clerk/express'
import { GqlExecutionContext } from '@nestjs/graphql'; import { GqlExecutionContext } from '@nestjs/graphql'
@Injectable() @Injectable()
export class ClerkAuthGuard implements CanActivate { export class ClerkAuthGuard implements CanActivate {
@@ -15,36 +15,36 @@ export class ClerkAuthGuard implements CanActivate {
async canActivate(context: ExecutionContext): Promise<boolean> { async canActivate(context: ExecutionContext): Promise<boolean> {
// For GraphQL, get the request from the GQL context // For GraphQL, get the request from the GQL context
const ctx = GqlExecutionContext.create(context); const ctx = GqlExecutionContext.create(context)
const request = ctx.getContext().req; const request = ctx.getContext().req
// Get the token from the Authorization header // Get the token from the Authorization header
const authHeader = request.headers['authorization']; const authHeader = request.headers['authorization']
if (!authHeader) { if (!authHeader) {
throw new UnauthorizedException('Authorization header not found'); throw new UnauthorizedException('Authorization header not found')
} }
const token = authHeader.split(' ')[1]; // Assuming 'Bearer TOKEN' const token = authHeader.split(' ')[1] // Assuming 'Bearer TOKEN'
if (!token) { if (!token) {
throw new UnauthorizedException('Token not found'); throw new UnauthorizedException('Token not found')
} }
try { try {
// Verify the token with Clerk // Verify the token with Clerk
const session = await this.clerk.verifyToken(token, {}); const session = await this.clerk.verifyToken(token, {})
if (!session) { if (!session) {
throw new UnauthorizedException('Invalid session'); throw new UnauthorizedException('Invalid session')
} }
// Attach user info to the request context if needed // Attach user info to the request context if needed
request.user = session.user; request.user = session.user
return true; return true
} catch (error: any) { } catch (error: any) {
throw new UnauthorizedException(error.message); throw new UnauthorizedException(error.message)
} }
} }
} }

View File

@@ -7,9 +7,9 @@ import {
Param, Param,
Body, Body,
Headers, Headers,
} from '@nestjs/common'; } from '@nestjs/common'
import { ClerkService } from './clerk.service'; import { ClerkService } from './clerk.service'
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'
@ApiTags('Clerk') @ApiTags('Clerk')
@Controller('clerk') @Controller('clerk')
export class ClerkController { export class ClerkController {
@@ -19,8 +19,8 @@ export class ClerkController {
@ApiOperation({ summary: 'Clerk Webhook' }) @ApiOperation({ summary: 'Clerk Webhook' })
@ApiResponse({ status: 200, description: 'Webhook created successfully' }) @ApiResponse({ status: 200, description: 'Webhook created successfully' })
webhook(@Headers() headers: any, @Body() body: any) { webhook(@Headers() headers: any, @Body() body: any) {
return this.clerkService.webhook(body); return this.clerkService.webhook(body)
} }
} }
export default ClerkController; export default ClerkController

View File

@@ -1,7 +1,7 @@
import { Module, Global } from '@nestjs/common'; import { Module, Global } from '@nestjs/common'
import Clerk from '@clerk/express'; import Clerk from '@clerk/express'
import { ClerkService } from './clerk.service'; import { ClerkService } from './clerk.service'
import ClerkController from './clerk.controller'; import ClerkController from './clerk.controller'
@Global() @Global()
@Module({ @Module({
providers: [ providers: [

View File

@@ -1,17 +1,17 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { clerkClient } from '@clerk/express'; import { clerkClient } from '@clerk/express'
@Injectable() @Injectable()
export class ClerkService { export class ClerkService {
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) {}
webhook(body: any) { webhook(body: any) {
// get the event type // get the event type
const eventType = body.type; const eventType = body.type
// dispatch the event // dispatch the event
this.dispatchEvent(eventType, body.data); this.dispatchEvent(eventType, body.data)
return { message: `Webhook received: ${eventType}` }; return { message: `Webhook received: ${eventType}` }
} }
// dispatch the event // dispatch the event
dispatchEvent(eventType: string, data: any) { dispatchEvent(eventType: string, data: any) {
@@ -23,53 +23,53 @@ export class ClerkService {
// session.removed // session.removed
// session.ended // session.ended
// email.created // email.created
console.log(eventType, data); console.log(eventType, data)
if (eventType === 'user.created') { if (eventType === 'user.created') {
this.eventUserCreated(data); this.eventUserCreated(data)
} }
if (eventType === 'user.updated') { if (eventType === 'user.updated') {
this.eventUserUpdated(data); this.eventUserUpdated(data)
} }
if (eventType === 'session.created') { if (eventType === 'session.created') {
this.eventSessionCreated(data); this.eventSessionCreated(data)
} }
if (eventType === 'session.revoked') { if (eventType === 'session.revoked') {
this.eventSessionRevoked(data); this.eventSessionRevoked(data)
} }
if (eventType === 'session.removed') { if (eventType === 'session.removed') {
this.eventSessionRemoved(data); this.eventSessionRemoved(data)
} }
if (eventType === 'session.ended') { if (eventType === 'session.ended') {
this.eventSessionEnded(data); this.eventSessionEnded(data)
} }
if (eventType === 'email.created') { if (eventType === 'email.created') {
this.eventEmailCreated(data); this.eventEmailCreated(data)
} }
} }
async eventUserCreated(data: any) { async eventUserCreated(data: any) {
const primary_email_address_id = data.primary_email_address_id; const primary_email_address_id = data.primary_email_address_id
// get primary email address on email_addresses by querying email_addresses with primary_email_address_id // get primary email address on email_addresses by querying email_addresses with primary_email_address_id
let primary_email_address = data.email_addresses.find( let primary_email_address = data.email_addresses.find(
(email: any) => email.id === primary_email_address_id, (email: any) => email.id === primary_email_address_id,
); )
console.log(primary_email_address); console.log(primary_email_address)
if (!primary_email_address) { if (!primary_email_address) {
primary_email_address = ''; primary_email_address = ''
} }
// get user id // get user id
const user_id = data.id; const user_id = data.id
// get created at and convert to date // get created at and convert to date
const created_at = new Date(data.created_at); const created_at = new Date(data.created_at)
// get name by combining first_name and last_name // get name by combining first_name and last_name
const name = `${data.first_name} ${data.last_name}`; const name = `${data.first_name} ${data.last_name}`
const role = 'CUSTOMER'; const role = 'CUSTOMER'
const phoneNumber = ''; const phoneNumber = ''
// create user in database // create user in database
try { try {
await this.prisma.user.create({ await this.prisma.user.create({
@@ -81,32 +81,32 @@ export class ClerkService {
createdAt: created_at, createdAt: created_at,
phoneNumber: phoneNumber ?? '', phoneNumber: phoneNumber ?? '',
}, },
}); })
} catch (err) { } catch (err) {
Logger.error(err); Logger.error(err)
} }
} }
async eventUserUpdated(data: any) { async eventUserUpdated(data: any) {
console.log(data); console.log(data)
const user_id = data.id; const user_id = data.id
const name = `${data.first_name} ${data.last_name}`; const name = `${data.first_name} ${data.last_name}`
await this.prisma.user.update({ await this.prisma.user.update({
where: { id: user_id }, where: { id: user_id },
data: { name: name }, data: { name: name },
}); })
} }
async eventSessionCreated(data: any) { async eventSessionCreated(data: any) {
console.log(data); console.log(data)
// check if user exists in database or create user // check if user exists in database or create user
const user = await this.prisma.user.findUnique({ const user = await this.prisma.user.findUnique({
where: { id: data.user_id }, where: { id: data.user_id },
}); })
if (!user) { if (!user) {
// get user info from clerk // get user info from clerk
const userInfo = await clerkClient.users.getUser(data.user_id); const userInfo = await clerkClient.users.getUser(data.user_id)
console.log(userInfo); console.log(userInfo)
try { try {
await this.prisma.user.create({ await this.prisma.user.create({
data: { data: {
@@ -115,27 +115,27 @@ export class ClerkService {
name: `${userInfo.firstName} ${userInfo.lastName}`, name: `${userInfo.firstName} ${userInfo.lastName}`,
avatarUrl: userInfo.imageUrl, avatarUrl: userInfo.imageUrl,
}, },
}); })
} catch (err) { } catch (err) {
Logger.error(err); Logger.error(err)
} }
} }
// to do: get session info // to do: get session info
} }
eventSessionRevoked(data: any) { eventSessionRevoked(data: any) {
console.log(data); console.log(data)
} }
eventSessionRemoved(data: any) { eventSessionRemoved(data: any) {
console.log(data); console.log(data)
} }
eventSessionEnded(data: any) { eventSessionEnded(data: any) {
console.log(data); console.log(data)
} }
eventEmailCreated(data: any) { eventEmailCreated(data: any) {
console.log(data); console.log(data)
} }
} }

View File

@@ -1,82 +1,82 @@
import { DateTimeResolver, JSONObjectResolver } from 'graphql-scalars'; import { DateTimeResolver, JSONObjectResolver } from 'graphql-scalars'
import PrismaPlugin, { import PrismaPlugin, {
PothosPrismaDatamodel, PothosPrismaDatamodel,
PrismaClient, PrismaClient,
} from '@pothos/plugin-prisma'; } from '@pothos/plugin-prisma'
import { Request, Response } from 'express'; import { Request, Response } from 'express'
import SmartSubscriptionPlugin, { import SmartSubscriptionPlugin, {
subscribeOptionsFromIterator, subscribeOptionsFromIterator,
} from '@pothos/plugin-smart-subscriptions'; } from '@pothos/plugin-smart-subscriptions'
import AuthzPlugin from '@pothos/plugin-authz'; import AuthzPlugin from '@pothos/plugin-authz'
import ErrorsPlugin from '@pothos/plugin-errors'; import ErrorsPlugin from '@pothos/plugin-errors'
import type { FileUpload } from 'graphql-upload/processRequest.js'; import type { FileUpload } from 'graphql-upload/processRequest.js'
import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'; import GraphQLUpload from 'graphql-upload/GraphQLUpload.js'
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { PrismaCrudGenerator } from './graphql.generator'; import { PrismaCrudGenerator } from './graphql.generator'
import type PrismaTypes from '../types/pothos.generated'; import type PrismaTypes from '../types/pothos.generated'
import PrismaUtils from '@pothos/plugin-prisma-utils'; import PrismaUtils from '@pothos/plugin-prisma-utils'
import { PubSub } from 'graphql-subscriptions'; import { PubSub } from 'graphql-subscriptions'
import RelayPlugin from '@pothos/plugin-relay'; import RelayPlugin from '@pothos/plugin-relay'
import SchemaBuilder from '@pothos/core'; import SchemaBuilder from '@pothos/core'
import SimpleObjectPlugin from '@pothos/plugin-simple-objects'; import SimpleObjectPlugin from '@pothos/plugin-simple-objects'
import { User } from '@prisma/client'; import { User } from '@prisma/client'
import { getDatamodel } from '../types/pothos.generated'; import { getDatamodel } from '../types/pothos.generated'
// import { rules } from '../common/graphql/common.graphql.auth-rule'; // import { rules } from '../common/graphql/common.graphql.auth-rule';
export type SchemaContext = export type SchemaContext =
| { | {
isSubscription: true; isSubscription: true
websocket: { websocket: {
pubSub: PubSub; pubSub: PubSub
me: User; me: User
generator: PrismaCrudGenerator<BuilderTypes>; generator: PrismaCrudGenerator<BuilderTypes>
}; }
} }
| { | {
isSubscription: false; isSubscription: false
http: { http: {
req: Request; req: Request
res: Response; res: Response
me: User; me: User
pubSub: PubSub; pubSub: PubSub
generator: PrismaCrudGenerator<BuilderTypes>; generator: PrismaCrudGenerator<BuilderTypes>
}; }
}; }
// extend prisma types to contain string type // extend prisma types to contain string type
export interface SchemaBuilderOption { export interface SchemaBuilderOption {
Context: SchemaContext; Context: SchemaContext
PrismaTypes: PrismaTypes; PrismaTypes: PrismaTypes
DataModel: PothosPrismaDatamodel; DataModel: PothosPrismaDatamodel
Connection: { Connection: {
totalCount: number | (() => number | Promise<number>); totalCount: number | (() => number | Promise<number>)
}; }
// AuthZRule: keyof typeof rules; // AuthZRule: keyof typeof rules;
Scalars: { Scalars: {
DateTime: { DateTime: {
Input: Date; Input: Date
Output: Date; Output: Date
}; }
Json: { Json: {
Input: JSON; Input: JSON
Output: JSON; Output: JSON
}; }
Upload: { Upload: {
Input: FileUpload; Input: FileUpload
Output: FileUpload; Output: FileUpload
}; }
Int: { Int: {
Input: number; Input: number
Output: number | bigint | string; Output: number | bigint | string
}; }
}; }
} }
@Injectable() @Injectable()
export class Builder extends SchemaBuilder<SchemaBuilderOption> { export class Builder extends SchemaBuilder<SchemaBuilderOption> {
public generator: PrismaCrudGenerator<BuilderTypes>; public generator: PrismaCrudGenerator<BuilderTypes>
constructor(private readonly prisma: PrismaClient) { constructor(private readonly prisma: PrismaClient) {
super({ super({
@@ -93,9 +93,9 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
debounceDelay: 1000, debounceDelay: 1000,
...subscribeOptionsFromIterator((name, ctx) => { ...subscribeOptionsFromIterator((name, ctx) => {
if (ctx.isSubscription) { if (ctx.isSubscription) {
return ctx.websocket.pubSub.asyncIterator(name); return ctx.websocket.pubSub.asyncIterator(name)
} }
return ctx.http.pubSub.asyncIterator(name); return ctx.http.pubSub.asyncIterator(name)
}), }),
}, },
relay: {}, relay: {},
@@ -109,15 +109,15 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
errors: { errors: {
defaultTypes: [], defaultTypes: [],
}, },
}); })
this.generator = new PrismaCrudGenerator<BuilderTypes>(this); this.generator = new PrismaCrudGenerator<BuilderTypes>(this)
this.addScalarType('DateTime', DateTimeResolver); this.addScalarType('DateTime', DateTimeResolver)
this.addScalarType('Json', JSONObjectResolver); this.addScalarType('Json', JSONObjectResolver)
this.addScalarType('Upload', GraphQLUpload); this.addScalarType('Upload', GraphQLUpload)
this.queryType({}); this.queryType({})
this.mutationType({}); this.mutationType({})
this.subscriptionType({}); this.subscriptionType({})
this.globalConnectionField('totalCount', (t) => this.globalConnectionField('totalCount', (t) =>
t.int({ t.int({
@@ -127,10 +127,10 @@ export class Builder extends SchemaBuilder<SchemaBuilderOption> {
? parent.totalCount() ? parent.totalCount()
: parent.totalCount, : parent.totalCount,
}), }),
); )
// test print ManagedServiceWhereUniqueInput // test print ManagedServiceWhereUniqueInput
} }
} }
export type BuilderTypes = export type BuilderTypes =
PothosSchemaTypes.ExtendDefaultTypes<SchemaBuilderOption>; PothosSchemaTypes.ExtendDefaultTypes<SchemaBuilderOption>

View File

@@ -1,4 +1,4 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
type BaseEnum, type BaseEnum,
@@ -7,14 +7,14 @@ import {
type InputType, type InputType,
type InputTypeParam, type InputTypeParam,
type SchemaTypes, type SchemaTypes,
} from '@pothos/core'; } from '@pothos/core'
import { type PrismaModelTypes, getModel } from '@pothos/plugin-prisma'; import { type PrismaModelTypes, getModel } from '@pothos/plugin-prisma'
import type { FilterOps } from '@pothos/plugin-prisma-utils'; import type { FilterOps } from '@pothos/plugin-prisma-utils'
import * as Prisma from '@prisma/client'; import * as Prisma from '@prisma/client'
import { SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'; import { SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
const filterOps = ['equals', 'in', 'notIn', 'not'] as const; const filterOps = ['equals', 'in', 'notIn', 'not'] as const
const sortableFilterProps = ['lt', 'lte', 'gt', 'gte'] as const; const sortableFilterProps = ['lt', 'lte', 'gt', 'gte'] as const
const stringFilterOps = [ const stringFilterOps = [
...filterOps, ...filterOps,
'contains', 'contains',
@@ -22,26 +22,26 @@ const stringFilterOps = [
'endsWith', 'endsWith',
'mode', 'mode',
'search', 'search',
] as const; ] as const
const sortableTypes = ['String', 'Int', 'Float', 'DateTime', 'BigInt'] as const; const sortableTypes = ['String', 'Int', 'Float', 'DateTime', 'BigInt'] as const
const listOps = ['every', 'some', 'none'] as const; const listOps = ['every', 'some', 'none'] as const
const scalarListOps = [ const scalarListOps = [
'has', 'has',
'hasSome', 'hasSome',
'hasEvery', 'hasEvery',
'isEmpty', 'isEmpty',
'equals', 'equals',
] as const; ] as const
const JsonFilterOps = ['equals', 'in', 'notIn', 'not'] as const; const JsonFilterOps = ['equals', 'in', 'notIn', 'not'] as const
const EnumFilterOps = ['equals', 'not'] as const; const EnumFilterOps = ['equals', 'not'] as const
@Injectable() @Injectable()
export class PrismaCrudGenerator<Types extends SchemaTypes> { export class PrismaCrudGenerator<Types extends SchemaTypes> {
private refCache = new Map< private refCache = new Map<
InputType<Types> | string, InputType<Types> | string,
Map<string, InputObjectRef<Types, unknown>> Map<string, InputObjectRef<Types, unknown>>
>(); >()
private enumRefs = new Map<string, EnumRef<Types, unknown>>(); private enumRefs = new Map<string, EnumRef<Types, unknown>>()
constructor( constructor(
// //
@@ -75,7 +75,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
type: 'Int', type: 'Int',
required: false, required: false,
}), }),
})); }))
} }
findUniqueArgs<Name extends string & keyof Types['PrismaTypes']>( findUniqueArgs<Name extends string & keyof Types['PrismaTypes']>(
@@ -86,7 +86,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
type: this.getWhereUnique(modelName), type: this.getWhereUnique(modelName),
required: true, required: true,
}), }),
})); }))
} }
getWhere<Name extends string & keyof Types['PrismaTypes']>( getWhere<Name extends string & keyof Types['PrismaTypes']>(
@@ -95,19 +95,19 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) { ) {
const withoutName = (without ?? []) const withoutName = (without ?? [])
.map((name) => `Without${capitalize(name)}`) .map((name) => `Without${capitalize(name)}`)
.join(''); .join('')
const fullName = `${modelName}${withoutName}Filter`; const fullName = `${modelName}${withoutName}Filter`
return this.getRef(modelName, fullName, () => { return this.getRef(modelName, fullName, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaWhere(modelName, { return this.builder.prismaWhere(modelName, {
name: fullName, name: fullName,
fields: (() => { fields: (() => {
const fields: Record<string, InputType<Types>> = {}; const fields: Record<string, InputType<Types>> = {}
const withoutFields = model.fields.filter((field) => const withoutFields = model.fields.filter((field) =>
without?.includes(field.name), without?.includes(field.name),
); )
model.fields model.fields
.filter( .filter(
@@ -119,7 +119,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
), ),
) )
.forEach((field) => { .forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
type = field.isList type = field.isList
@@ -128,49 +128,49 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) )
: this.getFilter( : this.getFilter(
this.mapScalarType(field.type) as InputType<Types>, this.mapScalarType(field.type) as InputType<Types>,
); )
break; break
case 'enum': case 'enum':
type = field.isList type = field.isList
? this.getScalarListFilter(this.getEnum(field.type)) ? this.getScalarListFilter(this.getEnum(field.type))
: this.getFilter(this.getEnum(field.type)); : this.getFilter(this.getEnum(field.type))
break; break
case 'object': case 'object':
type = field.isList type = field.isList
? this.getListFilter(this.getWhere(field.type as Name)) ? this.getListFilter(this.getWhere(field.type as Name))
: this.getWhere(field.type as Name); : this.getWhere(field.type as Name)
break; break
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (!type) { if (!type) {
return; return
} }
fields[field.name] = type; fields[field.name] = type
}); })
return fields; return fields
}) as never, }) as never,
}) as InputObjectRef< }) as InputObjectRef<
Types, Types,
(PrismaModelTypes & Types['PrismaTypes'][Name])['Where'] (PrismaModelTypes & Types['PrismaTypes'][Name])['Where']
>; >
}); })
} }
getWhereUnique<Name extends string & keyof Types['PrismaTypes']>( getWhereUnique<Name extends string & keyof Types['PrismaTypes']>(
modelName: Name, modelName: Name,
) { ) {
const name = `${modelName}UniqueFilter`; const name = `${modelName}UniqueFilter`
return this.getRef(modelName, name, () => { return this.getRef(modelName, name, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaWhereUnique(modelName, { return this.builder.prismaWhereUnique(modelName, {
name, name,
fields: (() => { fields: (() => {
const fields: Record<string, InputType<Types>> = {}; const fields: Record<string, InputType<Types>> = {}
model.fields model.fields
.filter( .filter(
@@ -183,73 +183,73 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
model.primaryKey?.fields.includes(field.name), model.primaryKey?.fields.includes(field.name),
) )
.forEach((field) => { .forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
type = this.mapScalarType(field.type) as InputType<Types>; type = this.mapScalarType(field.type) as InputType<Types>
break; break
case 'enum': case 'enum':
type = this.getEnum(field.type); type = this.getEnum(field.type)
break; break
case 'object': case 'object':
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (!type) { if (!type) {
return; return
} }
fields[field.name] = type; fields[field.name] = type
}); })
return fields; return fields
}) as never, }) as never,
}) as InputObjectRef< }) as InputObjectRef<
Types, Types,
(PrismaModelTypes & Types['PrismaTypes'][Name])['WhereUnique'] (PrismaModelTypes & Types['PrismaTypes'][Name])['WhereUnique']
>; >
}); })
} }
getOrderBy<Name extends string & keyof Types['PrismaTypes']>( getOrderBy<Name extends string & keyof Types['PrismaTypes']>(
modelName: Name, modelName: Name,
) { ) {
const name = `${modelName}OrderBy`; const name = `${modelName}OrderBy`
return this.getRef(modelName, name, () => { return this.getRef(modelName, name, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaOrderBy(modelName, { return this.builder.prismaOrderBy(modelName, {
name, name,
fields: () => { fields: () => {
const fields: Record<string, InputType<Types> | boolean> = {}; const fields: Record<string, InputType<Types> | boolean> = {}
model.fields.forEach((field) => { model.fields.forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
case 'enum': case 'enum':
type = true; type = true
break; break
case 'object': case 'object':
type = this.getOrderBy(field.type as Name); type = this.getOrderBy(field.type as Name)
break; break
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (type) { if (type) {
fields[field.name] = type; fields[field.name] = type
} }
}); })
// eslint-disable-next-line @typescript-eslint/no-empty-object-type // eslint-disable-next-line @typescript-eslint/no-empty-object-type
return fields as {}; return fields as {}
}, },
}); })
}); })
} }
getCreateInput<Name extends string & keyof Types['PrismaTypes']>( getCreateInput<Name extends string & keyof Types['PrismaTypes']>(
@@ -258,21 +258,21 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) { ) {
const withoutName = (without ?? []) const withoutName = (without ?? [])
.map((name) => `Without${capitalize(name)}`) .map((name) => `Without${capitalize(name)}`)
.join(''); .join('')
const fullName = `${modelName}Create${withoutName}Input`; const fullName = `${modelName}Create${withoutName}Input`
return this.getRef(modelName, fullName, () => { return this.getRef(modelName, fullName, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaCreate(modelName, { return this.builder.prismaCreate(modelName, {
name: fullName, name: fullName,
fields: (() => { fields: (() => {
const fields: Record<string, InputTypeParam<Types>> = {}; const fields: Record<string, InputTypeParam<Types>> = {}
const withoutFields = model.fields.filter((field) => const withoutFields = model.fields.filter((field) =>
without?.includes(field.name), without?.includes(field.name),
); )
const relationIds = model.fields.flatMap( const relationIds = model.fields.flatMap(
(field) => field.relationFromFields ?? [], (field) => field.relationFromFields ?? [],
); )
model.fields model.fields
.filter( .filter(
@@ -284,35 +284,35 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) && !relationIds.includes(field.name), ) && !relationIds.includes(field.name),
) )
.forEach((field) => { .forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
type = this.mapScalarType(field.type) as InputType<Types>; type = this.mapScalarType(field.type) as InputType<Types>
break; break
case 'enum': case 'enum':
type = this.getEnum(field.type); type = this.getEnum(field.type)
break; break
case 'object': case 'object':
type = this.getCreateRelationInput(modelName, field.name); type = this.getCreateRelationInput(modelName, field.name)
break; break
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (type) { if (type) {
fields[field.name] = type; fields[field.name] = type
} }
}); })
return fields; return fields
}) as never, }) as never,
}) as InputObjectRef< }) as InputObjectRef<
Types, Types,
(PrismaModelTypes & Types['PrismaTypes'][Name])['Create'] (PrismaModelTypes & Types['PrismaTypes'][Name])['Create']
>; >
}); })
} }
getCreateRelationInput< getCreateRelationInput<
@@ -327,30 +327,30 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
`${modelName}${capitalize(relation)}`, `${modelName}${capitalize(relation)}`,
'CreateRelationInput', 'CreateRelationInput',
() => { () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaCreateRelation(modelName, relation, { return this.builder.prismaCreateRelation(modelName, relation, {
fields: () => { fields: () => {
const relationField = model.fields.find( const relationField = model.fields.find(
(field) => field.name === relation, (field) => field.name === relation,
)!; )!
const relatedModel = getModel(relationField.type, this.builder); const relatedModel = getModel(relationField.type, this.builder)
const relatedFieldName = relatedModel.fields.find( const relatedFieldName = relatedModel.fields.find(
(field) => field.relationName === relationField.relationName, (field) => field.relationName === relationField.relationName,
)!; )!
return { return {
create: this.getCreateInput(relationField.type as Name, [ create: this.getCreateInput(relationField.type as Name, [
relatedFieldName.name, relatedFieldName.name,
]), ]),
connect: this.getWhereUnique(relationField.type as Name), connect: this.getWhereUnique(relationField.type as Name),
}; }
}, },
} as never) as InputObjectRef< } as never) as InputObjectRef<
Types, Types,
NonNullable<Model['Create'][Relation & keyof Model['Update']]> NonNullable<Model['Create'][Relation & keyof Model['Update']]>
>; >
}, },
); )
} }
getCreateManyInput<Name extends string & keyof Types['PrismaTypes']>( getCreateManyInput<Name extends string & keyof Types['PrismaTypes']>(
@@ -359,22 +359,22 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) { ) {
const withoutName = (without ?? []) const withoutName = (without ?? [])
.map((name) => `Without${capitalize(name)}`) .map((name) => `Without${capitalize(name)}`)
.join(''); .join('')
const fullName = `${modelName}Create${withoutName}Input`; const fullName = `${modelName}Create${withoutName}Input`
return this.getRef(modelName, fullName, () => { return this.getRef(modelName, fullName, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaCreateMany(modelName, { return this.builder.prismaCreateMany(modelName, {
name: fullName, name: fullName,
fields: (() => { fields: (() => {
const fields: Record<string, InputTypeParam<Types>> = {}; const fields: Record<string, InputTypeParam<Types>> = {}
const withoutFields = model.fields.filter((field) => const withoutFields = model.fields.filter((field) =>
without?.includes(field.name), without?.includes(field.name),
); )
const relationIds = model.fields.flatMap( const relationIds = model.fields.flatMap(
(field) => field.relationFromFields ?? [], (field) => field.relationFromFields ?? [],
); )
model.fields model.fields
.filter( .filter(
@@ -386,32 +386,32 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) && !relationIds.includes(field.name), ) && !relationIds.includes(field.name),
) )
.forEach((field) => { .forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
type = this.mapScalarType(field.type) as InputType<Types>; type = this.mapScalarType(field.type) as InputType<Types>
break; break
case 'enum': case 'enum':
type = this.getEnum(field.type); type = this.getEnum(field.type)
break; break
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (type) { if (type) {
fields[field.name] = type; fields[field.name] = type
} }
}); })
return fields; return fields
}) as never, }) as never,
}) as InputObjectRef< }) as InputObjectRef<
Types, Types,
(PrismaModelTypes & Types['PrismaTypes'][Name])['Create'] (PrismaModelTypes & Types['PrismaTypes'][Name])['Create']
>; >
}); })
} }
getUpdateInput<Name extends string & keyof Types['PrismaTypes']>( getUpdateInput<Name extends string & keyof Types['PrismaTypes']>(
@@ -420,21 +420,21 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) { ) {
const withoutName = (without ?? []) const withoutName = (without ?? [])
.map((name) => `Without${capitalize(name)}`) .map((name) => `Without${capitalize(name)}`)
.join(''); .join('')
const fullName = `${modelName}Update${withoutName}Input`; const fullName = `${modelName}Update${withoutName}Input`
return this.getRef(modelName, fullName, () => { return this.getRef(modelName, fullName, () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaUpdate(modelName, { return this.builder.prismaUpdate(modelName, {
name: fullName, name: fullName,
fields: (() => { fields: (() => {
const fields: Record<string, InputTypeParam<Types>> = {}; const fields: Record<string, InputTypeParam<Types>> = {}
const withoutFields = model.fields.filter((field) => const withoutFields = model.fields.filter((field) =>
without?.includes(field.name), without?.includes(field.name),
); )
const relationIds = model.fields.flatMap( const relationIds = model.fields.flatMap(
(field) => field.relationFromFields ?? [], (field) => field.relationFromFields ?? [],
); )
model.fields model.fields
.filter( .filter(
@@ -446,35 +446,35 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
) && !relationIds.includes(field.name), ) && !relationIds.includes(field.name),
) )
.forEach((field) => { .forEach((field) => {
let type; let type
switch (field.kind) { switch (field.kind) {
case 'scalar': case 'scalar':
type = this.mapScalarType(field.type) as InputType<Types>; type = this.mapScalarType(field.type) as InputType<Types>
break; break
case 'enum': case 'enum':
type = this.getEnum(field.type); type = this.getEnum(field.type)
break; break
case 'object': case 'object':
type = this.getUpdateRelationInput(modelName, field.name); type = this.getUpdateRelationInput(modelName, field.name)
break; break
case 'unsupported': case 'unsupported':
break; break
default: default:
throw new Error(`Unknown field kind ${field.kind}`); throw new Error(`Unknown field kind ${field.kind}`)
} }
if (type) { if (type) {
fields[field.name] = type; fields[field.name] = type
} }
}); })
return fields; return fields
}) as never, }) as never,
}) as InputObjectRef< }) as InputObjectRef<
Types, Types,
(PrismaModelTypes & Types['PrismaTypes'][Name])['Update'] (PrismaModelTypes & Types['PrismaTypes'][Name])['Update']
>; >
}); })
} }
getUpdateRelationInput< getUpdateRelationInput<
Name extends string & keyof Types['PrismaTypes'], Name extends string & keyof Types['PrismaTypes'],
@@ -488,16 +488,16 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
`${modelName}${capitalize(relation)}`, `${modelName}${capitalize(relation)}`,
'UpdateRelationInput', 'UpdateRelationInput',
() => { () => {
const model = getModel(modelName, this.builder); const model = getModel(modelName, this.builder)
return this.builder.prismaUpdateRelation(modelName, relation, { return this.builder.prismaUpdateRelation(modelName, relation, {
fields: () => { fields: () => {
const relationField = model.fields.find( const relationField = model.fields.find(
(field) => field.name === relation, (field) => field.name === relation,
)!; )!
const relatedModel = getModel(relationField.type, this.builder); const relatedModel = getModel(relationField.type, this.builder)
const relatedFieldName = relatedModel.fields.find( const relatedFieldName = relatedModel.fields.find(
(field) => field.relationName === relationField.relationName, (field) => field.relationName === relationField.relationName,
)!.name; )!.name
if (relationField.isList) { if (relationField.isList) {
return { return {
@@ -531,7 +531,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
deleteMany: this.getWhere(relationField.type as Name, [ deleteMany: this.getWhere(relationField.type as Name, [
relatedFieldName, relatedFieldName,
]), ]),
}; }
} }
return { return {
@@ -544,38 +544,38 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
connect: this.getWhereUnique(relationField.type as Name), connect: this.getWhereUnique(relationField.type as Name),
disconnect: relationField.isRequired ? undefined : 'Boolean', disconnect: relationField.isRequired ? undefined : 'Boolean',
delete: relationField.isRequired ? undefined : 'Boolean', delete: relationField.isRequired ? undefined : 'Boolean',
}; }
}, },
} as never) as InputObjectRef< } as never) as InputObjectRef<
Types, Types,
NonNullable<Model['Update'][Relation & keyof Model['Update']]> NonNullable<Model['Update'][Relation & keyof Model['Update']]>
>; >
}, },
); )
} }
private getFilter(type: InputType<Types>) { private getFilter(type: InputType<Types>) {
return this.getRef(type, `${String(type)}Filter`, () => { return this.getRef(type, `${String(type)}Filter`, () => {
const ops: FilterOps[] = [...filterOps]; const ops: FilterOps[] = [...filterOps]
if (type === 'String') { if (type === 'String') {
ops.push(...stringFilterOps); ops.push(...stringFilterOps)
} }
if (sortableTypes.includes(type as never)) { if (sortableTypes.includes(type as never)) {
ops.push(...sortableFilterProps); ops.push(...sortableFilterProps)
} }
if (type === 'Json') { if (type === 'Json') {
ops.push(...JsonFilterOps); ops.push(...JsonFilterOps)
} }
// type enum // type enum
if (type === 'Enum') { if (type === 'Enum') {
ops.push(...EnumFilterOps); ops.push(...EnumFilterOps)
} }
return this.builder.prismaFilter(type, { return this.builder.prismaFilter(type, {
ops, ops,
}); })
}); })
} }
private getScalarListFilter(type: InputType<Types>) { private getScalarListFilter(type: InputType<Types>) {
@@ -583,7 +583,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
this.builder.prismaScalarListFilter(type, { this.builder.prismaScalarListFilter(type, {
ops: scalarListOps, ops: scalarListOps,
}), }),
); )
} }
private getListFilter(type: InputType<Types>) { private getListFilter(type: InputType<Types>) {
@@ -591,7 +591,7 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
this.builder.prismaListFilter(type, { this.builder.prismaListFilter(type, {
ops: listOps, ops: listOps,
}), }),
); )
} }
private getEnum(name: string) { private getEnum(name: string) {
@@ -601,12 +601,12 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
{ {
name, name,
}, },
); )
this.enumRefs.set(name, enumRef); this.enumRefs.set(name, enumRef)
} }
return this.enumRefs.get(name)!; return this.enumRefs.get(name)!
} }
private mapScalarType(type: string) { private mapScalarType(type: string) {
@@ -617,9 +617,9 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
case 'Float': case 'Float':
case 'DateTime': case 'DateTime':
case 'Json': case 'Json':
return type; return type
default: default:
return null; return null
} }
} }
@@ -629,24 +629,24 @@ export class PrismaCrudGenerator<Types extends SchemaTypes> {
create: () => T, create: () => T,
): T { ): T {
if (!this.refCache.has(key)) { if (!this.refCache.has(key)) {
this.refCache.set(key, new Map()); this.refCache.set(key, new Map())
} }
const cache = this.refCache.get(key)!; const cache = this.refCache.get(key)!
if (cache.has(name)) { if (cache.has(name)) {
return cache.get(name)! as T; return cache.get(name)! as T
} }
const ref = new InputObjectRef<Types, unknown>(name); const ref = new InputObjectRef<Types, unknown>(name)
cache.set(name, ref); cache.set(name, ref)
this.builder.configStore.associateParamWithRef(ref, create()); this.builder.configStore.associateParamWithRef(ref, create())
return ref as T; return ref as T
} }
} }
function capitalize(str: string) { function capitalize(str: string) {
return str[0].toUpperCase() + str.slice(1); return str[0].toUpperCase() + str.slice(1)
} }

View File

@@ -1,44 +1,44 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { AdminNoteModule } from '../AdminNote/adminnote.module'; import { AdminNoteModule } from '../AdminNote/adminnote.module'
import { ApolloDriverConfig } from '@nestjs/apollo'; import { ApolloDriverConfig } from '@nestjs/apollo'
import { AppConfigModule } from '../AppConfig/appconfig.module'; import { AppConfigModule } from '../AppConfig/appconfig.module'
import { Builder } from './graphql.builder'; import { Builder } from './graphql.builder'
import { CategoryModule } from '../Category/category.module'; import { CategoryModule } from '../Category/category.module'
import { CenterMentorModule } from '../CenterMentor/centermentor.module'; import { CenterMentorModule } from '../CenterMentor/centermentor.module'
import { CenterModule } from '../Center/center.module'; import { CenterModule } from '../Center/center.module'
import { ChatroomModule } from '../ChatRoom/chatroom.module'; import { ChatroomModule } from '../ChatRoom/chatroom.module'
import { CommonModule } from '../common/common.module'; import { CommonModule } from '../common/common.module'
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config'
import { GraphQLModule } from '@nestjs/graphql'; import { GraphQLModule } from '@nestjs/graphql'
import { GraphqlService } from './graphql.service'; import { GraphqlService } from './graphql.service'
import { ManagedServiceModule } from '../ManagedService/managedservice.module'; import { ManagedServiceModule } from '../ManagedService/managedservice.module'
import { MessageModule } from '../Message/message.module'; import { MessageModule } from '../Message/message.module'
import { MilestoneModule } from '../Milestone/milestone.module'; import { MilestoneModule } from '../Milestone/milestone.module'
import { OrderModule } from '../Order/order.module'; import { OrderModule } from '../Order/order.module'
import { PaymentModule } from '../Payment/payment.module'; import { PaymentModule } from '../Payment/payment.module'
import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver'; import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver'
import { PothosModule } from '@smatch-corp/nestjs-pothos'; import { PothosModule } from '@smatch-corp/nestjs-pothos'
import { PrismaCrudGenerator } from './graphql.generator'; import { PrismaCrudGenerator } from './graphql.generator'
import { PrismaModule } from '../Prisma/prisma.module'; import { PrismaModule } from '../Prisma/prisma.module'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { RedisModule } from 'src/Redis/redis.module'; import { RedisModule } from 'src/Redis/redis.module'
import { RedisService } from 'src/Redis/redis.service'; import { RedisService } from 'src/Redis/redis.service'
import { RefundTicketModule } from '../RefundTicket/refundticket.module'; import { RefundTicketModule } from '../RefundTicket/refundticket.module'
import { Request } from 'express'; import { Request } from 'express'
import { ResumeModule } from '../Resume/resume.module'; import { ResumeModule } from '../Resume/resume.module'
import { ScheduleModule } from '../Schedule/schedule.module'; import { ScheduleModule } from '../Schedule/schedule.module'
import { ServiceAndCategoryModule } from '../ServiceAndCategory/serviceandcategory.module'; import { ServiceAndCategoryModule } from '../ServiceAndCategory/serviceandcategory.module'
import { ServiceFeedbackModule } from '../ServiceFeedback/servicefeedback.module'; import { ServiceFeedbackModule } from '../ServiceFeedback/servicefeedback.module'
import { ServiceMeetingRoomModule } from '../ServiceMeetingRoom/servicemeetingroom.module'; import { ServiceMeetingRoomModule } from '../ServiceMeetingRoom/servicemeetingroom.module'
import { ServiceModule } from '../Service/service.module'; import { ServiceModule } from '../Service/service.module'
import { UploadedFileModule } from '../UploadedFile/uploadedfile.module'; import { UploadedFileModule } from '../UploadedFile/uploadedfile.module'
import { UserModule } from '../User/user.module'; import { UserModule } from '../User/user.module'
import { WorkshopMeetingRoomModule } from '../WorkshopMeetingRoom/workshopmeetingroom.module'; import { WorkshopMeetingRoomModule } from '../WorkshopMeetingRoom/workshopmeetingroom.module'
import { WorkshopModule } from '../Workshop/workshop.module'; import { WorkshopModule } from '../Workshop/workshop.module'
import { WorkshopOrganizationModule } from '../WorkshopOrganization/workshoporganization.module'; import { WorkshopOrganizationModule } from '../WorkshopOrganization/workshoporganization.module'
import { WorkshopSubscriptionModule } from '../WorkshopSubscription/workshopsubscription.module'; import { WorkshopSubscriptionModule } from '../WorkshopSubscription/workshopsubscription.module'
import { initContextCache } from '@pothos/core'; import { initContextCache } from '@pothos/core'
@Global() @Global()
@Module({ @Module({

View File

@@ -3,13 +3,13 @@ import {
Injectable, Injectable,
Logger, Logger,
UnauthorizedException, UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { Request } from 'express'; import { Request } from 'express'
import { clerkClient } from '@clerk/express'; import { clerkClient } from '@clerk/express'
import { RedisService } from '../Redis/redis.service'; import { RedisService } from '../Redis/redis.service'
@Injectable() @Injectable()
export class GraphqlService { export class GraphqlService {
@@ -20,37 +20,37 @@ export class GraphqlService {
async acquireContext(req: Request) { async acquireContext(req: Request) {
// get x-session-id from headers // get x-session-id from headers
let sessionId: string; let sessionId: string
const disableAuth = process.env.DISABLE_AUTH === 'true'; const disableAuth = process.env.DISABLE_AUTH === 'true'
try { try {
sessionId = req.headers['x-session-id'] as string; sessionId = req.headers['x-session-id'] as string
} catch (error) { } catch (error) {
Logger.error('Error acquiring context', error); Logger.error('Error acquiring context', error)
if (disableAuth) { if (disableAuth) {
return null; return null
} }
throw new UnauthorizedException('Must provide a session ID'); throw new UnauthorizedException('Must provide a session ID')
} }
if (disableAuth) { if (disableAuth) {
return null; return null
} }
// redis context cache // redis context cache
const cachedUser = await this.redis.getUser(sessionId); const cachedUser = await this.redis.getUser(sessionId)
if (cachedUser) { if (cachedUser) {
return cachedUser; return cachedUser
} }
// check if the token is valid // check if the token is valid
const session = await clerkClient.sessions.getSession(sessionId as string); const session = await clerkClient.sessions.getSession(sessionId as string)
if (!session) { if (!session) {
throw new UnauthorizedException('Invalid session'); throw new UnauthorizedException('Invalid session')
} }
const user = await this.prisma.user.findUnique({ const user = await this.prisma.user.findUnique({
where: { id: session.userId }, where: { id: session.userId },
}); })
if (!user) { if (!user) {
throw new UnauthorizedException('User not found'); throw new UnauthorizedException('User not found')
} }
await this.redis.setUser(sessionId, user, session.expireAt); await this.redis.setUser(sessionId, user, session.expireAt)
return user; return user
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,11 @@
import * as path from 'path'; import * as path from 'path'
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { MailService } from './mail.service'; import { MailService } from './mail.service'
import { MailerModule } from '@nestjs-modules/mailer'; import { MailerModule } from '@nestjs-modules/mailer'
import { OpenaiModule } from '../OpenAI/openai.module'; import { OpenaiModule } from '../OpenAI/openai.module'
import { PugAdapter } from '@nestjs-modules/mailer/dist/adapters/pug.adapter'; import { PugAdapter } from '@nestjs-modules/mailer/dist/adapters/pug.adapter'
@Global() @Global()
@Module({ @Module({

View File

@@ -1,8 +1,8 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common'
import { MailerService } from '@nestjs-modules/mailer'; import { MailerService } from '@nestjs-modules/mailer'
import { OpenaiService } from '../OpenAI/openai.service'; import { OpenaiService } from '../OpenAI/openai.service'
import { User } from '@prisma/client'; import { User } from '@prisma/client'
@Injectable() @Injectable()
export class MailService { export class MailService {
@@ -16,16 +16,16 @@ export class MailService {
const mailContent = ` const mailContent = `
<h1>${subject}</h1> <h1>${subject}</h1>
<p>${text}</p> <p>${text}</p>
`; `
const result = await this.mailerService.sendMail({ const result = await this.mailerService.sendMail({
to, to,
subject, subject,
text: mailContent ?? text, text: mailContent ?? text,
}); })
Logger.log(result, 'MailService'); Logger.log(result, 'MailService')
} catch (error) { } catch (error) {
Logger.error(error, 'MailService'); Logger.error(error, 'MailService')
} }
} }
@@ -41,10 +41,10 @@ export class MailService {
subject, subject,
template, template,
context, context,
}); })
Logger.log(result, 'MailService'); Logger.log(result, 'MailService')
} catch (error) { } catch (error) {
Logger.error(error, 'MailService'); Logger.error(error, 'MailService')
} }
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ManagedServiceSchema } from './managedservice.schema'; import { ManagedServiceSchema } from './managedservice.schema'
@Module({ @Module({
providers: [ManagedServiceSchema], providers: [ManagedServiceSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class ManagedServiceSchema extends PothosSchema { export class ManagedServiceSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class ManagedServiceSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -41,7 +41,7 @@ export class ManagedServiceSchema extends PothosSchema {
description: 'The service.', description: 'The service.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -53,7 +53,7 @@ export class ManagedServiceSchema extends PothosSchema {
resolve: async (parent, args, ctx) => { resolve: async (parent, args, ctx) => {
return this.prisma.managedService.findUnique({ return this.prisma.managedService.findUnique({
where: args.where, where: args.where,
}); })
}, },
}), }),
@@ -67,10 +67,10 @@ export class ManagedServiceSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
}); })
}, },
}), }),
})); }))
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
createManagedService: t.prismaField({ createManagedService: t.prismaField({
@@ -87,9 +87,9 @@ export class ManagedServiceSchema extends PothosSchema {
return await this.prisma.managedService.create({ return await this.prisma.managedService.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { MessageSchema } from './message.schema'; import { MessageSchema } from './message.schema'
@Module({ @Module({
providers: [MessageSchema], providers: [MessageSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class MessageSchema extends PothosSchema { export class MessageSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class MessageSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -47,7 +47,7 @@ export class MessageSchema extends PothosSchema {
description: 'The chat room.', description: 'The chat room.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -61,7 +61,7 @@ export class MessageSchema extends PothosSchema {
return await this.prisma.message.findUnique({ return await this.prisma.message.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
messages: t.prismaField({ messages: t.prismaField({
@@ -76,7 +76,7 @@ export class MessageSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
messagesByChatRoomId: t.prismaField({ messagesByChatRoomId: t.prismaField({
@@ -87,10 +87,10 @@ export class MessageSchema extends PothosSchema {
return await this.prisma.message.findMany({ return await this.prisma.message.findMany({
...query, ...query,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
// mutations // mutations
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -108,15 +108,15 @@ export class MessageSchema extends PothosSchema {
const message = await this.prisma.message.create({ const message = await this.prisma.message.create({
...query, ...query,
data: args.input, data: args.input,
}); })
if (ctx.isSubscription) { if (ctx.isSubscription) {
throw new Error('Not allowed'); throw new Error('Not allowed')
} }
ctx.http.pubSub.publish('MESSAGE_SENT', message); ctx.http.pubSub.publish('MESSAGE_SENT', message)
return message; return message
}, },
}), }),
})); }))
// subscriptions // subscriptions
/* The code snippet `subscriptions` is currently commented out in the provided TypeScript class. It /* The code snippet `subscriptions` is currently commented out in the provided TypeScript class. It
@@ -128,23 +128,23 @@ export class MessageSchema extends PothosSchema {
messageSent: t.field({ messageSent: t.field({
subscribe: (_, __, ctx) => { subscribe: (_, __, ctx) => {
if (!ctx.isSubscription) { if (!ctx.isSubscription) {
throw new Error('Not allowed'); throw new Error('Not allowed')
} }
return { return {
[Symbol.asyncIterator]: () => [Symbol.asyncIterator]: () =>
ctx.websocket.pubSub.asyncIterator('MESSAGE_SENT'), ctx.websocket.pubSub.asyncIterator('MESSAGE_SENT'),
}; }
}, },
type: this.message(), // Add the type property type: this.message(), // Add the type property
resolve: (payload) => resolve: (payload) =>
payload as { payload as {
message: 'Json'; message: 'Json'
id: string; id: string
senderId: string; senderId: string
chatRoomId: string; chatRoomId: string
sentAt: Date; sentAt: Date
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { MilestoneSchema } from './milestone.schema'; import { MilestoneSchema } from './milestone.schema'
@Module({ @Module({
providers: [MilestoneSchema], providers: [MilestoneSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class MilestoneSchema extends PothosSchema { export class MilestoneSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class MilestoneSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -47,7 +47,7 @@ export class MilestoneSchema extends PothosSchema {
description: 'The date and time the milestone was last updated.', description: 'The date and time the milestone was last updated.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -66,7 +66,7 @@ export class MilestoneSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
milestone: t.prismaField({ milestone: t.prismaField({
@@ -77,9 +77,9 @@ export class MilestoneSchema extends PothosSchema {
return await this.prisma.milestone.findUnique({ return await this.prisma.milestone.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,6 +1,6 @@
import { Module, Global } from '@nestjs/common'; import { Module, Global } from '@nestjs/common'
import { MinioService } from './minio.service'; import { MinioService } from './minio.service'
import { NestMinioModule } from 'nestjs-minio'; import { NestMinioModule } from 'nestjs-minio'
@Global() @Global()
@Module({ @Module({
imports: [ imports: [

View File

@@ -1,9 +1,9 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config'
import { FileUpload } from 'graphql-upload/processRequest.js'; import { FileUpload } from 'graphql-upload/processRequest.js'
import { Client } from 'minio'; import { Client } from 'minio'
import { MINIO_CONNECTION } from 'nestjs-minio'; import { MINIO_CONNECTION } from 'nestjs-minio'
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid'
@Injectable() @Injectable()
export class MinioService { export class MinioService {
constructor( constructor(
@@ -13,10 +13,10 @@ export class MinioService {
async uploadFile(file: FileUpload, category: string) { async uploadFile(file: FileUpload, category: string) {
// sonar ignore next // sonar ignore next
const { mimetype, createReadStream, filename: actualFileName } = await file; const { mimetype, createReadStream, filename: actualFileName } = await file
const filename = this.fileName(); const filename = this.fileName()
const Name = `${category}/${filename}`; const Name = `${category}/${filename}`
const fileBuffer = createReadStream(); const fileBuffer = createReadStream()
const result = await this.minioClient.putObject( const result = await this.minioClient.putObject(
this.configService.get('BUCKET_NAME') ?? 'epess', this.configService.get('BUCKET_NAME') ?? 'epess',
@@ -26,15 +26,15 @@ export class MinioService {
{ {
'Content-Type': mimetype, 'Content-Type': mimetype,
}, },
); )
return { result, filename, mimetype, actualFileName }; return { result, filename, mimetype, actualFileName }
} }
async getFileUrl(id: string, category: string) { async getFileUrl(id: string, category: string) {
if (!id) { if (!id) {
return null; return null
} }
let url = null; let url = null
try { try {
url = await this.minioClient.presignedUrl( url = await this.minioClient.presignedUrl(
@@ -42,23 +42,23 @@ export class MinioService {
this.configService.get('BUCKET_NAME') ?? 'epess', this.configService.get('BUCKET_NAME') ?? 'epess',
`${category}/${id}`, `${category}/${id}`,
60 * 60 * 24 * 7, 60 * 60 * 24 * 7,
); )
} catch (error) { } catch (error) {
console.log(error); console.log(error)
} }
console.log(url); console.log(url)
return url; return url
} }
async deleteFile(id: string, category: string) { async deleteFile(id: string, category: string) {
return await this.minioClient.removeObject( return await this.minioClient.removeObject(
this.configService.get('BUCKET_NAME') ?? 'epess', this.configService.get('BUCKET_NAME') ?? 'epess',
`${category}/${id}`, `${category}/${id}`,
); )
} }
fileName() { fileName() {
// generate a unique file name using uuid // generate a unique file name using uuid
return uuidv4(); return uuidv4()
} }
} }

View File

@@ -1,13 +1,13 @@
import { ClientOptions, OpenAI } from 'openai'; import { ClientOptions, OpenAI } from 'openai'
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { OpenaiService } from './openai.service'; import { OpenaiService } from './openai.service'
const openaiOptions: ClientOptions = { const openaiOptions: ClientOptions = {
apiKey: process.env.OPENAI_API_KEY, apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL, baseURL: process.env.OPENAI_BASE_URL,
maxRetries: parseInt(process.env.OPENAI_MAX_RETRIES as string) ?? 3, maxRetries: parseInt(process.env.OPENAI_MAX_RETRIES as string) ?? 3,
}; }
@Module({ @Module({
imports: [OpenAI], imports: [OpenAI],

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { OpenAI } from 'openai'; import { OpenAI } from 'openai'
@Injectable() @Injectable()
export class OpenaiService { export class OpenaiService {
@@ -12,13 +12,13 @@ export class OpenaiService {
) { ) {
const prompt = ` const prompt = `
give me mail content for invitation to a workshop to EPESS and replace {{ mail }} with ${mail}, {{ username }} with ${username} and {{ url }} with ${url} give me mail content for invitation to a workshop to EPESS and replace {{ mail }} with ${mail}, {{ username }} with ${username} and {{ url }} with ${url}
`; `
const response = await this.openai.chat.completions.create({ const response = await this.openai.chat.completions.create({
model: 'gpt-4o', model: 'gpt-4o',
messages: [{ role: 'user', content: prompt }], messages: [{ role: 'user', content: prompt }],
}); })
return response.choices[0].message.content; return response.choices[0].message.content
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { OrderSchema } from './order.schema'; import { OrderSchema } from './order.schema'
@Module({ @Module({
providers: [OrderSchema], providers: [OrderSchema],

View File

@@ -1,20 +1,20 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { OrderStatus } from '@prisma/client'; import { OrderStatus } from '@prisma/client'
@Injectable() @Injectable()
export class OrderSchema extends PothosSchema { export class OrderSchema extends PothosSchema {
constructor( constructor(
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
// Types section // Types section
@@ -69,7 +69,7 @@ export class OrderSchema extends PothosSchema {
description: 'The schedule for the order.', description: 'The schedule for the order.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -88,7 +88,7 @@ export class OrderSchema extends PothosSchema {
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
order: t.prismaField({ order: t.prismaField({
@@ -99,10 +99,10 @@ export class OrderSchema extends PothosSchema {
return await this.prisma.order.findUnique({ return await this.prisma.order.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
})); }))
// mutation section // mutation section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
createOrder: t.prismaField({ createOrder: t.prismaField({
@@ -129,18 +129,17 @@ export class OrderSchema extends PothosSchema {
const order = await prisma.order.create({ const order = await prisma.order.create({
...query, ...query,
data: args.data, data: args.data,
}); })
// check if service is valid // check if service is valid
if (!args.data.service.connect) { if (!args.data.service.connect) {
throw new Error('Service not found'); throw new Error('Service not found')
} }
// check if service price is free // check if service price is free
if (args.data.service.connect.price === 0) { if (args.data.service.connect.price === 0) {
return order; return order
} }
// generate payment code by prefix 'EPESS' + 6 hex digits // generate payment code by prefix 'EPESS' + 6 hex digits
const paymentCode = const paymentCode = 'EPESS' + Math.random().toString(16).slice(2, 8)
'EPESS' + Math.random().toString(16).slice(2, 8);
// create payment // create payment
await prisma.payment.create({ await prisma.payment.create({
data: { data: {
@@ -149,9 +148,9 @@ export class OrderSchema extends PothosSchema {
paymentCode: paymentCode, paymentCode: paymentCode,
expiredAt: new Date(Date.now() + 1000 * 60 * 60 * 24), expiredAt: new Date(Date.now() + 1000 * 60 * 60 * 24),
}, },
}); })
return order; return order
}); })
}, },
}), }),
deleteOrder: t.prismaField({ deleteOrder: t.prismaField({
@@ -167,7 +166,7 @@ export class OrderSchema extends PothosSchema {
return await this.prisma.order.delete({ return await this.prisma.order.delete({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
updateOrder: t.prismaField({ updateOrder: t.prismaField({
@@ -191,9 +190,9 @@ export class OrderSchema extends PothosSchema {
...query, ...query,
data: args.data, data: args.data,
where: args.where, where: args.where,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { PaymentSchema } from './payment.schema'; import { PaymentSchema } from './payment.schema'
@Module({ @Module({
providers: [PaymentSchema], providers: [PaymentSchema],

View File

@@ -1,13 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { PaymentStatus } from '@prisma/client'; import { PaymentStatus } from '@prisma/client'
@Injectable() @Injectable()
export class PaymentSchema extends PothosSchema { export class PaymentSchema extends PothosSchema {
@@ -15,7 +15,7 @@ export class PaymentSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
// Types section // Types section
@@ -46,7 +46,7 @@ export class PaymentSchema extends PothosSchema {
description: 'The order for the payment.', description: 'The order for the payment.',
}), }),
}), }),
}); })
} }
// Queries section // Queries section
@@ -61,7 +61,7 @@ export class PaymentSchema extends PothosSchema {
return await this.prisma.payment.findUnique({ return await this.prisma.payment.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
payments: t.prismaField({ payments: t.prismaField({
@@ -77,9 +77,9 @@ export class PaymentSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -7,9 +7,9 @@ import {
Param, Param,
Body, Body,
Headers, Headers,
} from '@nestjs/common'; } from '@nestjs/common'
import { PayosService } from './payos.service'; import { PayosService } from './payos.service'
import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { ApiTags, ApiOperation } from '@nestjs/swagger'
@ApiTags('Payos') @ApiTags('Payos')
@Controller('payos') @Controller('payos')
@@ -23,13 +23,13 @@ export class PayosController {
@Body() body: any, @Body() body: any,
@Headers('x-payos-signature') signature: string, @Headers('x-payos-signature') signature: string,
) { ) {
return this.payosService.webhook(body, signature); return this.payosService.webhook(body, signature)
} }
// ping webhook // ping webhook
@Get('webhook') @Get('webhook')
@ApiOperation({ summary: 'Ping webhook' }) @ApiOperation({ summary: 'Ping webhook' })
async ping() { async ping() {
return this.payosService.ping(); return this.payosService.ping()
} }
} }

View File

@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { PayosController } from './payos.controller'; import { PayosController } from './payos.controller'
import { PayosService } from './payos.service'; import { PayosService } from './payos.service'
@Module({ @Module({
providers: [PayosService], providers: [PayosService],

View File

@@ -1,29 +1,29 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class PayosService { export class PayosService {
constructor(private readonly prisma: PrismaService) {} constructor(private readonly prisma: PrismaService) {}
async ping() { async ping() {
return 'pong'; return 'pong'
} }
async webhook(body: any, signature: string) { async webhook(body: any, signature: string) {
Logger.log('Webhook received', body); Logger.log('Webhook received', body)
return body; return body
} }
async createPaymentURL(body: any) { async createPaymentURL(body: any) {
return body; return body
} }
async cancelPaymentURL(body: any) { async cancelPaymentURL(body: any) {
return body; return body
} }
async refundPayment(body: any) { async refundPayment(body: any) {
return body; return body
} }
} }

View File

@@ -1,5 +1,5 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { PrismaService } from './prisma.service'; import { PrismaService } from './prisma.service'
@Global() @Global()
@Module({ @Module({

View File

@@ -3,13 +3,13 @@ import {
Injectable, Injectable,
Logger, Logger,
OnModuleInit, OnModuleInit,
} from '@nestjs/common'; } from '@nestjs/common'
import { PrismaClient } from '@prisma/client'; import { PrismaClient } from '@prisma/client'
@Injectable() @Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit { export class PrismaService extends PrismaClient implements OnModuleInit {
private readonly logger = new Logger(PrismaService.name); private readonly logger = new Logger(PrismaService.name)
constructor() { constructor() {
super({ super({
log: [ log: [
@@ -35,44 +35,44 @@ export class PrismaService extends PrismaClient implements OnModuleInit {
maxWait: 30 * 1000, maxWait: 30 * 1000,
timeout: 60 * 1000, timeout: 60 * 1000,
}, },
}); })
} }
async onModuleInit() { async onModuleInit() {
this.logger.log('Try to connect database...'); this.logger.log('Try to connect database...')
const maxRetry = parseInt(process.env.PRISMA_MAX_RETRY as string) ?? 3; const maxRetry = parseInt(process.env.PRISMA_MAX_RETRY as string) ?? 3
const retryDelay = 10000; const retryDelay = 10000
for (let attempt = 1; attempt <= maxRetry; attempt++) { for (let attempt = 1; attempt <= maxRetry; attempt++) {
try { try {
await this.$connect(); await this.$connect()
this.logger.log('Connected.'); this.logger.log('Connected.')
return; return
} catch (error) { } catch (error) {
if (attempt < maxRetry) { if (attempt < maxRetry) {
this.logger.warn( this.logger.warn(
`Connection attempt ${attempt} failed. Retrying in ${retryDelay}ms...`, `Connection attempt ${attempt} failed. Retrying in ${retryDelay}ms...`,
); )
await this.delay(retryDelay); await this.delay(retryDelay)
} else { } else {
this.logger.error( this.logger.error(
`Failed to connect to the database after ${maxRetry} attempts.`, `Failed to connect to the database after ${maxRetry} attempts.`,
); )
throw error; throw error
} }
} }
} }
} }
private delay(ms: number): Promise<void> { private delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms)); return new Promise((resolve) => setTimeout(resolve, ms))
} }
async enableShutdownHooks(app: INestApplication) { async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit' as never, async () => { this.$on('beforeExit' as never, async () => {
this.logger.log('Wait for application closing...'); this.logger.log('Wait for application closing...')
await app.close(); await app.close()
}); })
} }
} }

View File

@@ -1,6 +1,6 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { RedisService } from './redis.service'; import { RedisService } from './redis.service'
@Global() @Global()
@Module({ @Module({

View File

@@ -1,41 +1,41 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { Redis } from 'ioredis'; import { Redis } from 'ioredis'
import { User } from '@prisma/client'; import { User } from '@prisma/client'
@Injectable() @Injectable()
export class RedisService { export class RedisService {
private readonly redis: Redis; private readonly redis: Redis
constructor() { constructor() {
this.redis = new Redis(process.env.REDIS_URL as string); this.redis = new Redis(process.env.REDIS_URL as string)
} }
async get(key: string) { async get(key: string) {
return await this.redis.get(key); return await this.redis.get(key)
} }
async set(key: string, value: string, expireAt: number) { async set(key: string, value: string, expireAt: number) {
return await this.redis.set(key, value, 'EXAT', expireAt); return await this.redis.set(key, value, 'EXAT', expireAt)
} }
async del(key: string) { async del(key: string) {
return await this.redis.del(key); return await this.redis.del(key)
} }
async close() { async close() {
return await this.redis.quit(); return await this.redis.quit()
} }
async getUser(sessionId: string) { async getUser(sessionId: string) {
const userData = await this.get(sessionId); const userData = await this.get(sessionId)
if (!userData) { if (!userData) {
return null; return null
} }
const retrievedUser: User = JSON.parse(userData); const retrievedUser: User = JSON.parse(userData)
return retrievedUser; return retrievedUser
} }
async setUser(sessionId: string, user: User, expireAt: number) { async setUser(sessionId: string, user: User, expireAt: number) {
return await this.set(sessionId, JSON.stringify(user), expireAt); return await this.set(sessionId, JSON.stringify(user), expireAt)
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { RefundTicketSchema } from './refundticket.schema'; import { RefundTicketSchema } from './refundticket.schema'
@Module({ @Module({
providers: [RefundTicketSchema], providers: [RefundTicketSchema],

View File

@@ -1,13 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { PaymentStatus } from '@prisma/client'; import { PaymentStatus } from '@prisma/client'
@Injectable() @Injectable()
export class RefundTicketSchema extends PothosSchema { export class RefundTicketSchema extends PothosSchema {
@@ -15,7 +15,7 @@ export class RefundTicketSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
// Types section // Types section
@@ -45,7 +45,7 @@ export class RefundTicketSchema extends PothosSchema {
description: 'The order for the refund ticket.', description: 'The order for the refund ticket.',
}), }),
}), }),
}); })
} }
// Queries section // Queries section
@@ -65,9 +65,9 @@ export class RefundTicketSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,14 +1,6 @@
import { import { Controller, Get, Post, Put, Delete, Param, Body } from '@nestjs/common'
Controller, import { RestfulService } from './restful.service'
Get, import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'
Post,
Put,
Delete,
Param,
Body,
} from '@nestjs/common';
import { RestfulService } from './restful.service';
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
@ApiTags('Restful') @ApiTags('Restful')
@Controller('restful') @Controller('restful')
@@ -19,7 +11,7 @@ export class RestfulController {
@ApiOperation({ summary: 'Get all items' }) @ApiOperation({ summary: 'Get all items' })
@ApiResponse({ status: 200, description: 'Returns all items.' }) @ApiResponse({ status: 200, description: 'Returns all items.' })
getAllItems() { getAllItems() {
return this.restfulService.getAllItems(); return this.restfulService.getAllItems()
} }
// @Get(':id') // @Get(':id')
@@ -63,4 +55,4 @@ export class RestfulController {
// } // }
} }
export default RestfulController; export default RestfulController

View File

@@ -1,8 +1,8 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { RestfulController } from './restful.controller'; import { RestfulController } from './restful.controller'
import { RestfulService } from './restful.service'; import { RestfulService } from './restful.service'
import { ClerkModule } from '../Clerk/clerk.module'; import { ClerkModule } from '../Clerk/clerk.module'
import { PayosModule } from '../Payos/payos.module'; import { PayosModule } from '../Payos/payos.module'
@Module({ @Module({
imports: [ClerkModule, PayosModule], imports: [ClerkModule, PayosModule],

View File

@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
@Injectable() @Injectable()
export class RestfulService { export class RestfulService {
getAllItems() { getAllItems() {
return 'Hello World'; return 'Hello World'
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ResumeSchema } from './resume.schema'; import { ResumeSchema } from './resume.schema'
@Module({ @Module({
providers: [ResumeSchema], providers: [ResumeSchema],

View File

@@ -1,14 +1,14 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { MinioService } from '../Minio/minio.service'; import { MinioService } from '../Minio/minio.service'
import { ResumeStatus } from '@prisma/client'; import { ResumeStatus } from '@prisma/client'
@Injectable() @Injectable()
export class ResumeSchema extends PothosSchema { export class ResumeSchema extends PothosSchema {
constructor( constructor(
@@ -16,7 +16,7 @@ export class ResumeSchema extends PothosSchema {
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly minioService: MinioService, private readonly minioService: MinioService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -55,7 +55,7 @@ export class ResumeSchema extends PothosSchema {
description: 'The resume file for the resume.', description: 'The resume file for the resume.',
}), }),
}), }),
}); })
} }
@PothosRef() @PothosRef()
@@ -92,7 +92,7 @@ export class ResumeSchema extends PothosSchema {
description: 'The resume for the resume file.', description: 'The resume for the resume file.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
init(): void { init(): void {
@@ -109,7 +109,7 @@ export class ResumeSchema extends PothosSchema {
resolve: async (query, root, args, ctx, info) => { resolve: async (query, root, args, ctx, info) => {
try { try {
if (ctx.isSubscription) { if (ctx.isSubscription) {
throw new Error('Not allowed'); throw new Error('Not allowed')
} }
const resumes = await this.prisma.resume.findMany({ const resumes = await this.prisma.resume.findMany({
...query, ...query,
@@ -117,11 +117,11 @@ export class ResumeSchema extends PothosSchema {
userId: ctx.http.me.id, userId: ctx.http.me.id,
status: args.status ?? undefined, status: args.status ?? undefined,
}, },
}); })
return resumes; return resumes
} catch (error) { } catch (error) {
Logger.error(error, 'myResumes'); Logger.error(error, 'myResumes')
return []; return []
} }
}, },
}), }),
@@ -137,7 +137,7 @@ export class ResumeSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
@@ -149,8 +149,8 @@ export class ResumeSchema extends PothosSchema {
const resume = await this.prisma.resume.findUnique({ const resume = await this.prisma.resume.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
return resume; return resume
}, },
}), }),
@@ -162,11 +162,11 @@ export class ResumeSchema extends PothosSchema {
const resumeFile = await this.prisma.resumeFile.findUnique({ const resumeFile = await this.prisma.resumeFile.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
if (!resumeFile) { if (!resumeFile) {
return null; return null
} }
return resumeFile; return resumeFile
}, },
}), }),
resumeFiles: t.prismaField({ resumeFiles: t.prismaField({
@@ -181,11 +181,11 @@ export class ResumeSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
return resumeFiles; return resumeFiles
}, },
}), }),
})); }))
// Mutations section // Mutations section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -207,15 +207,15 @@ export class ResumeSchema extends PothosSchema {
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
const { resumeFile } = args; const { resumeFile } = args
const { mimetype } = await resumeFile; const { mimetype } = await resumeFile
const { filename, actualFileName } = const { filename, actualFileName } =
await this.minioService.uploadFile(resumeFile, 'resumes'); await this.minioService.uploadFile(resumeFile, 'resumes')
const fileUrl = await this.minioService.getFileUrl( const fileUrl = await this.minioService.getFileUrl(
filename, filename,
'resumes', 'resumes',
); )
const { userId, centerId } = args; const { userId, centerId } = args
const resume = await this.prisma.resume.upsert({ const resume = await this.prisma.resume.upsert({
...query, ...query,
where: { where: {
@@ -245,8 +245,8 @@ export class ResumeSchema extends PothosSchema {
}, },
status: ResumeStatus.REQUESTED, status: ResumeStatus.REQUESTED,
}, },
}); })
return resume; return resume
}, },
}), }),
@@ -264,13 +264,13 @@ export class ResumeSchema extends PothosSchema {
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
const { resumeId, status } = args; const { resumeId, status } = args
const resume = await this.prisma.resume.update({ const resume = await this.prisma.resume.update({
...query, ...query,
where: { id: resumeId }, where: { id: resumeId },
data: { status }, data: { status },
}); })
return resume; return resume
}, },
}), }),
@@ -284,14 +284,14 @@ export class ResumeSchema extends PothosSchema {
}), }),
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
const { resumeFileId } = args; const { resumeFileId } = args
const resumeFile = await this.prisma.resumeFile.delete({ const resumeFile = await this.prisma.resumeFile.delete({
...query, ...query,
where: { id: resumeFileId }, where: { id: resumeFileId },
}); })
return resumeFile; return resumeFile
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ScheduleSchema } from './schedule.schema'; import { ScheduleSchema } from './schedule.schema'
@Module({ @Module({
providers: [ScheduleSchema], providers: [ScheduleSchema],

View File

@@ -1,13 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { ScheduleStatus } from '@prisma/client'; import { ScheduleStatus } from '@prisma/client'
@Injectable() @Injectable()
export class ScheduleSchema extends PothosSchema { export class ScheduleSchema extends PothosSchema {
@@ -15,7 +15,7 @@ export class ScheduleSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -50,7 +50,7 @@ export class ScheduleSchema extends PothosSchema {
nullable: false, nullable: false,
}), }),
}), }),
}); })
} }
@PothosRef() @PothosRef()
@@ -76,7 +76,7 @@ export class ScheduleSchema extends PothosSchema {
description: 'The schedule the schedule date belongs to.', description: 'The schedule the schedule date belongs to.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -90,7 +90,7 @@ export class ScheduleSchema extends PothosSchema {
return await this.prisma.schedule.findUnique({ return await this.prisma.schedule.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
@@ -106,9 +106,9 @@ export class ScheduleSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,8 +1,8 @@
import * as DateTimeUtils from '../common/utils/datetime.utils'; import * as DateTimeUtils from '../common/utils/datetime.utils'
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
import { PrismaService } from 'src/Prisma/prisma.service'; import { PrismaService } from 'src/Prisma/prisma.service'
import { Schedule } from '@prisma/client'; import { Schedule } from '@prisma/client'
@Injectable() @Injectable()
export class ScheduleService { export class ScheduleService {

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ServiceSchema } from './service.schema'; import { ServiceSchema } from './service.schema'
@Module({ @Module({
providers: [ServiceSchema], providers: [ServiceSchema],

View File

@@ -1,15 +1,15 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { MinioService } from '../Minio/minio.service'; import { MinioService } from '../Minio/minio.service'
import { ServiceStatus } from '@prisma/client'; import { ServiceStatus } from '@prisma/client'
import { MailService } from '../Mail/mail.service'; import { MailService } from '../Mail/mail.service'
@Injectable() @Injectable()
export class ServiceSchema extends PothosSchema { export class ServiceSchema extends PothosSchema {
constructor( constructor(
@@ -18,7 +18,7 @@ export class ServiceSchema extends PothosSchema {
private readonly minioService: MinioService, private readonly minioService: MinioService,
private readonly mailService: MailService, private readonly mailService: MailService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -107,7 +107,7 @@ export class ServiceSchema extends PothosSchema {
description: 'The managed service for the service.', description: 'The managed service for the service.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -122,12 +122,12 @@ export class ServiceSchema extends PothosSchema {
resolve: async (query, root, args, ctx, info) => { resolve: async (query, root, args, ctx, info) => {
return await this.prisma.service.findMany({ return await this.prisma.service.findMany({
...query, ...query,
}); })
}, },
totalCount: (query) => { totalCount: (query) => {
return this.prisma.service.count({ return this.prisma.service.count({
...query, ...query,
}); })
}, },
}, },
{}, {},
@@ -146,7 +146,7 @@ export class ServiceSchema extends PothosSchema {
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
}); })
}, },
}), }),
service: t.prismaField({ service: t.prismaField({
@@ -165,10 +165,10 @@ export class ServiceSchema extends PothosSchema {
include: { include: {
feedbacks: true, feedbacks: true,
}, },
}); })
}, },
}), }),
})); }))
// Mutation section // Mutation section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -185,7 +185,7 @@ export class ServiceSchema extends PothosSchema {
return await this.prisma.service.create({ return await this.prisma.service.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
updateService: t.prismaField({ updateService: t.prismaField({
@@ -206,7 +206,7 @@ export class ServiceSchema extends PothosSchema {
...query, ...query,
where: args.where, where: args.where,
data: args.input, data: args.input,
}); })
}, },
}), }),
deleteService: t.prismaField({ deleteService: t.prismaField({
@@ -222,7 +222,7 @@ export class ServiceSchema extends PothosSchema {
return await this.prisma.service.delete({ return await this.prisma.service.delete({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
approveOrRejectService: t.prismaField({ approveOrRejectService: t.prismaField({
@@ -244,18 +244,18 @@ export class ServiceSchema extends PothosSchema {
}, },
resolve: async (query, root, args, ctx, info) => { resolve: async (query, root, args, ctx, info) => {
if (ctx.isSubscription) { if (ctx.isSubscription) {
throw new Error('Not allowed'); throw new Error('Not allowed')
} }
return await this.prisma.$transaction(async (prisma) => { return await this.prisma.$transaction(async (prisma) => {
// check if service is already approved or rejected // check if service is already approved or rejected
const service = await prisma.service.findUnique({ const service = await prisma.service.findUnique({
where: { id: args.serviceId }, where: { id: args.serviceId },
}); })
if (!service) { if (!service) {
throw new Error('Service not found'); throw new Error('Service not found')
} }
if (service.status !== ServiceStatus.PENDING) { if (service.status !== ServiceStatus.PENDING) {
throw new Error('Service is already approved or rejected'); throw new Error('Service is already approved or rejected')
} }
// update service status // update service status
const updatedService = await prisma.service.update({ const updatedService = await prisma.service.update({
@@ -272,33 +272,33 @@ export class ServiceSchema extends PothosSchema {
}, },
}, },
}, },
}); })
// mail to all mentor or center owner for the center // mail to all mentor or center owner for the center
const center = await prisma.center.findUnique({ const center = await prisma.center.findUnique({
where: { id: service.centerId }, where: { id: service.centerId },
}); })
if (!center?.centerOwnerId) { if (!center?.centerOwnerId) {
throw new Error('Center owner not found'); throw new Error('Center owner not found')
} }
const centerOwner = await prisma.user.findUnique({ const centerOwner = await prisma.user.findUnique({
where: { id: center.centerOwnerId }, where: { id: center.centerOwnerId },
}); })
if (!centerOwner) { if (!centerOwner) {
throw new Error('Center owner not found'); throw new Error('Center owner not found')
} }
const centerMentor = await prisma.centerMentor.findMany({ const centerMentor = await prisma.centerMentor.findMany({
where: { centerId: service.centerId }, where: { centerId: service.centerId },
}); })
const mentorIds = centerMentor.map((mentor) => mentor.mentorId); const mentorIds = centerMentor.map((mentor) => mentor.mentorId)
// get mentor emails // get mentor emails
const mentorEmails = await prisma.user.findMany({ const mentorEmails = await prisma.user.findMany({
where: { id: { in: mentorIds } }, where: { id: { in: mentorIds } },
}); })
Logger.log(mentorEmails, 'ServiceSchema'); Logger.log(mentorEmails, 'ServiceSchema')
const emails = [ const emails = [
centerOwner.email, centerOwner.email,
...mentorEmails.map((mentor) => mentor.email), ...mentorEmails.map((mentor) => mentor.email),
]; ]
if (args.approve) { if (args.approve) {
await this.mailService.sendTemplateEmail( await this.mailService.sendTemplateEmail(
emails, emails,
@@ -308,7 +308,7 @@ export class ServiceSchema extends PothosSchema {
SERVICE_NAME: service.name, SERVICE_NAME: service.name,
CENTER_NAME: center.name, CENTER_NAME: center.name,
}, },
); )
} else { } else {
await this.mailService.sendTemplateEmail( await this.mailService.sendTemplateEmail(
emails, emails,
@@ -319,12 +319,12 @@ export class ServiceSchema extends PothosSchema {
CENTER_NAME: center.name, CENTER_NAME: center.name,
ADMIN_NOTE: args.adminNote ?? 'Không có lý do', ADMIN_NOTE: args.adminNote ?? 'Không có lý do',
}, },
); )
} }
return updatedService; return updatedService
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ServiceAndCategorySchema } from './serviceandcategory.schema'; import { ServiceAndCategorySchema } from './serviceandcategory.schema'
@Module({ @Module({
providers: [ServiceAndCategorySchema], providers: [ServiceAndCategorySchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class ServiceAndCategorySchema extends PothosSchema { export class ServiceAndCategorySchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class ServiceAndCategorySchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -35,7 +35,7 @@ export class ServiceAndCategorySchema extends PothosSchema {
description: 'The ID of the sub category.', description: 'The ID of the sub category.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -53,9 +53,9 @@ export class ServiceAndCategorySchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ServiceFeedbackSchema } from './servicefeedback.schema'; import { ServiceFeedbackSchema } from './servicefeedback.schema'
@Module({ @Module({
providers: [ServiceFeedbackSchema], providers: [ServiceFeedbackSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class ServiceFeedbackSchema extends PothosSchema { export class ServiceFeedbackSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class ServiceFeedbackSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -54,7 +54,7 @@ export class ServiceFeedbackSchema extends PothosSchema {
description: 'The service that was provided.', description: 'The service that was provided.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -72,9 +72,9 @@ export class ServiceFeedbackSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { ServiceMeetingRoomSchema } from './servicemeetingroom.schema'; import { ServiceMeetingRoomSchema } from './servicemeetingroom.schema'
@Module({ @Module({
providers: [ServiceMeetingRoomSchema], providers: [ServiceMeetingRoomSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class ServiceMeetingRoomSchema extends PothosSchema { export class ServiceMeetingRoomSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -32,7 +32,7 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
description: 'The chatting room.', description: 'The chatting room.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -47,7 +47,7 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
return await this.prisma.serviceMeetingRoom.findUnique({ return await this.prisma.serviceMeetingRoom.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
serviceMeetingRooms: t.prismaField({ serviceMeetingRooms: t.prismaField({
@@ -62,9 +62,9 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,6 +1,6 @@
import { Module, Global } from '@nestjs/common'; import { Module, Global } from '@nestjs/common'
import { UploadedFileSchema } from './uploadedfile.schema'; import { UploadedFileSchema } from './uploadedfile.schema'
import { MinioModule } from '../Minio/minio.module'; import { MinioModule } from '../Minio/minio.module'
@Global() @Global()
@Module({ @Module({
imports: [MinioModule], imports: [MinioModule],

View File

@@ -1,14 +1,14 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { MinioService } from 'src/Minio/minio.service'; import { MinioService } from 'src/Minio/minio.service'
import { UploadedFileType } from '@prisma/client'; import { UploadedFileType } from '@prisma/client'
@Injectable() @Injectable()
export class UploadedFileSchema extends PothosSchema { export class UploadedFileSchema extends PothosSchema {
constructor( constructor(
@@ -16,7 +16,7 @@ export class UploadedFileSchema extends PothosSchema {
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly minioService: MinioService, private readonly minioService: MinioService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -62,7 +62,7 @@ export class UploadedFileSchema extends PothosSchema {
description: 'The workshop that the file belongs to.', description: 'The workshop that the file belongs to.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -77,16 +77,16 @@ export class UploadedFileSchema extends PothosSchema {
const file = await this.prisma.uploadedFile.findUnique({ const file = await this.prisma.uploadedFile.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
if (!file) { if (!file) {
throw new Error('File not found'); throw new Error('File not found')
} }
const fileUrl = await this.minioService.getFileUrl(file.id, 'files'); const fileUrl = await this.minioService.getFileUrl(file.id, 'files')
if (!fileUrl) { if (!fileUrl) {
throw new Error('Cannot retrieve file url'); throw new Error('Cannot retrieve file url')
} }
file.fileUrl = fileUrl; file.fileUrl = fileUrl
return file; return file
}, },
}), }),
uploadedFiles: t.prismaField({ uploadedFiles: t.prismaField({
@@ -101,17 +101,17 @@ export class UploadedFileSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
const fileUrls = await Promise.all( const fileUrls = await Promise.all(
files.map((file) => this.minioService.getFileUrl(file.id, 'files')), files.map((file) => this.minioService.getFileUrl(file.id, 'files')),
); )
return files.map((file, index) => ({ return files.map((file, index) => ({
...file, ...file,
fileUrl: fileUrls[index] ?? '', fileUrl: fileUrls[index] ?? '',
})); }))
}, },
}), }),
})); }))
// Mutations section // Mutations section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -137,18 +137,18 @@ export class UploadedFileSchema extends PothosSchema {
where: { where: {
id: args.userId, id: args.userId,
}, },
}); })
if (!user) { if (!user) {
throw new Error('User not found'); throw new Error('User not found')
} }
const { filename, mimetype, actualFileName } = const { filename, mimetype, actualFileName } =
await this.minioService.uploadFile(args.file, 'files'); await this.minioService.uploadFile(args.file, 'files')
if (!mimetype) { if (!mimetype) {
throw new Error('File type not supported'); throw new Error('File type not supported')
} }
const fileUrl = await this.minioService.getFileUrl(filename, 'files'); const fileUrl = await this.minioService.getFileUrl(filename, 'files')
if (!fileUrl) { if (!fileUrl) {
throw new Error('Cannot retrieve file url, please try again later'); throw new Error('Cannot retrieve file url, please try again later')
} }
const uploadedFile = await this.prisma.uploadedFile.create({ const uploadedFile = await this.prisma.uploadedFile.create({
data: { data: {
@@ -160,8 +160,8 @@ export class UploadedFileSchema extends PothosSchema {
fileUrl: fileUrl ?? '', fileUrl: fileUrl ?? '',
uploadedAt: new Date(), uploadedAt: new Date(),
}, },
}); })
return uploadedFile; return uploadedFile
}, },
}), }),
@@ -187,21 +187,21 @@ export class UploadedFileSchema extends PothosSchema {
where: { where: {
id: args.userId, id: args.userId,
}, },
}); })
if (!user) { if (!user) {
throw new Error('User not found'); throw new Error('User not found')
} }
const uploadedFiles = await Promise.all( const uploadedFiles = await Promise.all(
args.files.map((file) => args.files.map((file) =>
this.minioService.uploadFile(file, 'files'), this.minioService.uploadFile(file, 'files'),
), ),
); )
// get file urls // get file urls
const fileUrls = await Promise.all( const fileUrls = await Promise.all(
uploadedFiles.map((file) => uploadedFiles.map((file) =>
this.minioService.getFileUrl(file.filename, 'files'), this.minioService.getFileUrl(file.filename, 'files'),
), ),
); )
// map uploadedFiles to db // map uploadedFiles to db
const dbFiles = uploadedFiles.map((file, index) => ({ const dbFiles = uploadedFiles.map((file, index) => ({
userId: user.id, userId: user.id,
@@ -211,13 +211,13 @@ export class UploadedFileSchema extends PothosSchema {
actualFileName: file.actualFileName, actualFileName: file.actualFileName,
fileUrl: fileUrls[index] ?? '', fileUrl: fileUrls[index] ?? '',
uploadedAt: new Date(), uploadedAt: new Date(),
})); }))
// create files in db // create files in db
const createdFiles = const createdFiles =
await this.prisma.uploadedFile.createManyAndReturn({ await this.prisma.uploadedFile.createManyAndReturn({
data: dbFiles, data: dbFiles,
}); })
return createdFiles; return createdFiles
}, },
}), }),
@@ -235,17 +235,17 @@ export class UploadedFileSchema extends PothosSchema {
where: { where: {
id: args.id, id: args.id,
}, },
}); })
if (!file) { if (!file) {
throw new Error('File not found'); throw new Error('File not found')
} }
await this.minioService.deleteFile(file.fileName, 'files'); await this.minioService.deleteFile(file.fileName, 'files')
await this.prisma.uploadedFile.delete({ await this.prisma.uploadedFile.delete({
where: { where: {
id: file.id, id: file.id,
}, },
}); })
return file; return file
}, },
}), }),
@@ -266,22 +266,22 @@ export class UploadedFileSchema extends PothosSchema {
in: args.ids, in: args.ids,
}, },
}, },
}); })
await this.prisma.uploadedFile.deleteMany({ await this.prisma.uploadedFile.deleteMany({
where: { where: {
id: { id: {
in: args.ids, in: args.ids,
}, },
}, },
}); })
await Promise.all( await Promise.all(
files.map((file) => files.map((file) =>
this.minioService.deleteFile(file.fileName, 'files'), this.minioService.deleteFile(file.fileName, 'files'),
), ),
); )
return files; return files
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { UserSchema } from './user.schema'; import { UserSchema } from './user.schema'
@Module({ @Module({
providers: [UserSchema], providers: [UserSchema],
exports: [UserSchema], exports: [UserSchema],

View File

@@ -1,15 +1,15 @@
import { Inject, Injectable, Logger } from '@nestjs/common'; import { Inject, Injectable, Logger } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { clerkClient } from '@clerk/express'; import { clerkClient } from '@clerk/express'
import { UnauthorizedException } from '@nestjs/common'; import { UnauthorizedException } from '@nestjs/common'
import { MailService } from '../Mail/mail.service'; import { MailService } from '../Mail/mail.service'
@Injectable() @Injectable()
export class UserSchema extends PothosSchema { export class UserSchema extends PothosSchema {
constructor( constructor(
@@ -17,7 +17,7 @@ export class UserSchema extends PothosSchema {
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly mailService: MailService, private readonly mailService: MailService,
) { ) {
super(); super()
} }
// Types section // Types section
@@ -99,7 +99,7 @@ export class UserSchema extends PothosSchema {
description: 'The admin note of the user.', description: 'The admin note of the user.',
}), }),
}), }),
}); })
} }
// Query section // Query section
@@ -112,8 +112,8 @@ export class UserSchema extends PothosSchema {
sessionId: t.arg({ type: 'String', required: true }), sessionId: t.arg({ type: 'String', required: true }),
}, },
resolve: async (_, { sessionId }) => { resolve: async (_, { sessionId }) => {
const session = await clerkClient.sessions.getSession(sessionId); const session = await clerkClient.sessions.getSession(sessionId)
return JSON.parse(JSON.stringify(session)); return JSON.parse(JSON.stringify(session))
}, },
}), }),
newSession: t.field({ newSession: t.field({
@@ -128,8 +128,8 @@ export class UserSchema extends PothosSchema {
const session = await clerkClient.signInTokens.createSignInToken({ const session = await clerkClient.signInTokens.createSignInToken({
userId, userId,
expiresInSeconds: 60 * 60 * 24, expiresInSeconds: 60 * 60 * 24,
}); })
return session.id; return session.id
}, },
}), }),
me: t.prismaField({ me: t.prismaField({
@@ -137,9 +137,9 @@ export class UserSchema extends PothosSchema {
type: this.user(), type: this.user(),
resolve: async (query, root, args, ctx) => { resolve: async (query, root, args, ctx) => {
if (ctx.isSubscription) { if (ctx.isSubscription) {
throw new Error('Not allowed'); throw new Error('Not allowed')
} }
return ctx.http.me; return ctx.http.me
}, },
}), }),
@@ -155,7 +155,7 @@ export class UserSchema extends PothosSchema {
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
@@ -167,7 +167,7 @@ export class UserSchema extends PothosSchema {
return await this.prisma.user.findUniqueOrThrow({ return await this.prisma.user.findUniqueOrThrow({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
userBySession: t.prismaField({ userBySession: t.prismaField({
@@ -178,17 +178,17 @@ export class UserSchema extends PothosSchema {
}, },
resolve: async (query, root, args) => { resolve: async (query, root, args) => {
// check if the token is valid // check if the token is valid
const session = await clerkClient.sessions.getSession(args.sessionId); const session = await clerkClient.sessions.getSession(args.sessionId)
Logger.log(session, 'Session'); Logger.log(session, 'Session')
return await this.prisma.user.findFirstOrThrow({ return await this.prisma.user.findFirstOrThrow({
...query, ...query,
where: { where: {
id: session.userId, id: session.userId,
}, },
}); })
}, },
}), }),
})); }))
// Mutation section // Mutation section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -210,7 +210,7 @@ export class UserSchema extends PothosSchema {
...query, ...query,
where: args.where, where: args.where,
data: args.input, data: args.input,
}); })
}, },
}), }),
@@ -228,10 +228,10 @@ export class UserSchema extends PothosSchema {
center_name: 'băng đĩa lậu hải ngoại', center_name: 'băng đĩa lậu hải ngoại',
invite_url: 'https://epess.org', invite_url: 'https://epess.org',
}, },
); )
return 'Email sent'; return 'Email sent'
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { WorkshopSchema } from './workshop.schema'; import { WorkshopSchema } from './workshop.schema'
@Global() @Global()
@Module({ @Module({

View File

@@ -1,13 +1,13 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
import { MinioService } from 'src/Minio/minio.service'; import { MinioService } from 'src/Minio/minio.service'
@Injectable() @Injectable()
export class WorkshopSchema extends PothosSchema { export class WorkshopSchema extends PothosSchema {
@@ -16,7 +16,7 @@ export class WorkshopSchema extends PothosSchema {
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly minioService: MinioService, private readonly minioService: MinioService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -80,7 +80,7 @@ export class WorkshopSchema extends PothosSchema {
description: 'The meeting room that the workshop is for.', description: 'The meeting room that the workshop is for.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -94,7 +94,7 @@ export class WorkshopSchema extends PothosSchema {
return await this.prisma.workshop.findUnique({ return await this.prisma.workshop.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
@@ -110,10 +110,10 @@ export class WorkshopSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
// Mutations section // Mutations section
this.builder.mutationFields((t) => ({ this.builder.mutationFields((t) => ({
@@ -130,7 +130,7 @@ export class WorkshopSchema extends PothosSchema {
return await this.prisma.workshop.create({ return await this.prisma.workshop.create({
...query, ...query,
data: args.input, data: args.input,
}); })
}, },
}), }),
@@ -152,9 +152,9 @@ export class WorkshopSchema extends PothosSchema {
...query, ...query,
where: args.where, where: args.where,
data: args.input, data: args.input,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module, Global } from '@nestjs/common'; import { Module, Global } from '@nestjs/common'
import { WorkshopMeetingRoomSchema } from './workshopmeetingroom.schema'; import { WorkshopMeetingRoomSchema } from './workshopmeetingroom.schema'
@Global() @Global()
@Module({ @Module({

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class WorkshopMeetingRoomSchema extends PothosSchema { export class WorkshopMeetingRoomSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class WorkshopMeetingRoomSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -31,7 +31,7 @@ export class WorkshopMeetingRoomSchema extends PothosSchema {
description: 'The workshop that the meeting room is for.', description: 'The workshop that the meeting room is for.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -44,7 +44,7 @@ export class WorkshopMeetingRoomSchema extends PothosSchema {
return await this.prisma.workshopMeetingRoom.findUnique({ return await this.prisma.workshopMeetingRoom.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
workshopMeetingRooms: t.prismaField({ workshopMeetingRooms: t.prismaField({
@@ -58,9 +58,9 @@ export class WorkshopMeetingRoomSchema extends PothosSchema {
cursor: args.cursor ?? undefined, cursor: args.cursor ?? undefined,
take: args.take ?? undefined, take: args.take ?? undefined,
skip: args.skip ?? undefined, skip: args.skip ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { WorkshopOrganizationSchema } from './workshoporganization.schema'; import { WorkshopOrganizationSchema } from './workshoporganization.schema'
@Module({ @Module({
providers: [WorkshopOrganizationSchema], providers: [WorkshopOrganizationSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class WorkshopOrganizationSchema extends PothosSchema { export class WorkshopOrganizationSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class WorkshopOrganizationSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
workshopOrganization() { workshopOrganization() {
@@ -38,6 +38,6 @@ export class WorkshopOrganizationSchema extends PothosSchema {
'The date and time the workshop organization was created.', 'The date and time the workshop organization was created.',
}), }),
}), }),
}); })
} }
} }

View File

@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { WorkshopSubscriptionSchema } from './workshopsubscription.schema'; import { WorkshopSubscriptionSchema } from './workshopsubscription.schema'
@Module({ @Module({
providers: [WorkshopSubscriptionSchema], providers: [WorkshopSubscriptionSchema],

View File

@@ -1,12 +1,12 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { import {
Pothos, Pothos,
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
import { Builder } from '../Graphql/graphql.builder'; import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service'; import { PrismaService } from '../Prisma/prisma.service'
@Injectable() @Injectable()
export class WorkshopSubscriptionSchema extends PothosSchema { export class WorkshopSubscriptionSchema extends PothosSchema {
@@ -14,7 +14,7 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
@Inject(SchemaBuilderToken) private readonly builder: Builder, @Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
) { ) {
super(); super()
} }
@PothosRef() @PothosRef()
workshopSubscription() { workshopSubscription() {
@@ -39,7 +39,7 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
'The date and time the workshop subscription was created.', 'The date and time the workshop subscription was created.',
}), }),
}), }),
}); })
} }
@Pothos() @Pothos()
@@ -54,7 +54,7 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
return await this.prisma.workshopSubscription.findUnique({ return await this.prisma.workshopSubscription.findUnique({
...query, ...query,
where: args.where, where: args.where,
}); })
}, },
}), }),
workshopSubscriptions: t.prismaField({ workshopSubscriptions: t.prismaField({
@@ -69,9 +69,9 @@ export class WorkshopSubscriptionSchema extends PothosSchema {
take: args.take ?? undefined, take: args.take ?? undefined,
orderBy: args.orderBy ?? undefined, orderBy: args.orderBy ?? undefined,
where: args.filter ?? undefined, where: args.filter ?? undefined,
}); })
}, },
}), }),
})); }))
} }
} }

View File

@@ -1,9 +1,9 @@
import { ClerkModule } from './Clerk/clerk.module'; import { ClerkModule } from './Clerk/clerk.module'
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config'
import { GraphqlModule } from './Graphql/graphql.module'; import { GraphqlModule } from './Graphql/graphql.module'
import { MailModule } from './Mail/mail.module'; import { MailModule } from './Mail/mail.module'
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common'
import { RestfulModule } from './Restful/restful.module'; import { RestfulModule } from './Restful/restful.module'
@Module({ @Module({
imports: [ imports: [

View File

@@ -1,7 +1,7 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'
import { CommonGraphqlError } from './graphql/common.graphql.error'; import { CommonGraphqlError } from './graphql/common.graphql.error'
import { JwtUtils } from './utils/jwt.utils'; import { JwtUtils } from './utils/jwt.utils'
@Global() @Global()
@Module({ @Module({
imports: [], imports: [],

View File

@@ -1,15 +1,15 @@
import { Inject, Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common'
import { Builder } from '../../Graphql/graphql.builder'; import { Builder } from '../../Graphql/graphql.builder'
import { import {
PothosRef, PothosRef,
PothosSchema, PothosSchema,
SchemaBuilderToken, SchemaBuilderToken,
} from '@smatch-corp/nestjs-pothos'; } from '@smatch-corp/nestjs-pothos'
@Injectable() @Injectable()
export class CommonGraphqlError extends PothosSchema { export class CommonGraphqlError extends PothosSchema {
constructor(@Inject(SchemaBuilderToken) private readonly builder: Builder) { constructor(@Inject(SchemaBuilderToken) private readonly builder: Builder) {
super(); super()
} }
@PothosRef() @PothosRef()
@@ -19,6 +19,6 @@ export class CommonGraphqlError extends PothosSchema {
fields: (t) => ({ fields: (t) => ({
message: t.exposeString('message'), message: t.exposeString('message'),
}), }),
}); })
} }
} }

View File

@@ -1,29 +1,29 @@
import { sign, verify } from 'jsonwebtoken'; import { sign, verify } from 'jsonwebtoken'
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common'
@Injectable() @Injectable()
export class JwtUtils { export class JwtUtils {
signToken(payload: string, expiresIn: string) { signToken(payload: string, expiresIn: string) {
return sign(payload, process.env.JWT_SECRET!, { expiresIn }); return sign(payload, process.env.JWT_SECRET!, { expiresIn })
} }
//eslint-disable-next-line @typescript-eslint/no-explicit-any //eslint-disable-next-line @typescript-eslint/no-explicit-any
signTokenRS256(payload: any, expiresIn: string) { signTokenRS256(payload: any, expiresIn: string) {
const privateKey = process.env.JWT_RS256_PRIVATE_KEY!; const privateKey = process.env.JWT_RS256_PRIVATE_KEY!
return sign(payload, privateKey, { return sign(payload, privateKey, {
algorithm: 'RS256', algorithm: 'RS256',
expiresIn, expiresIn,
}); })
} }
verifyTokenRS256(token: string) { verifyTokenRS256(token: string) {
const publicKey = process.env.JWT_RS256_PUBLIC_KEY!; const publicKey = process.env.JWT_RS256_PUBLIC_KEY!
return verify(token, publicKey, { return verify(token, publicKey, {
algorithms: ['RS256'], algorithms: ['RS256'],
}); })
} }
verifyToken(token: string) { verifyToken(token: string) {
return verify(token, process.env.JWT_SECRET!); return verify(token, process.env.JWT_SECRET!)
} }
} }

View File

@@ -1,39 +1,39 @@
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
import { AppModule } from './app.module'; import { AppModule } from './app.module'
import { Logger } from '@nestjs/common'; import { Logger } from '@nestjs/common'
import { NestFactory } from '@nestjs/core'; import { NestFactory } from '@nestjs/core'
import { clerkMiddleware } from '@clerk/express'; import { clerkMiddleware } from '@clerk/express'
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js'; import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.js'
import path from 'node:path'; import path from 'node:path'
import { readFileSync } from 'node:fs'; import { readFileSync } from 'node:fs'
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule)
// load private key and public key // load private key and public key
const privateKey = readFileSync( const privateKey = readFileSync(
path.join(__dirname, 'KeyStore', 'private_key.pem'), path.join(__dirname, 'KeyStore', 'private_key.pem'),
'utf8', 'utf8',
); )
const publicKey = readFileSync( const publicKey = readFileSync(
path.join(__dirname, 'KeyStore', 'public_key.pem'), path.join(__dirname, 'KeyStore', 'public_key.pem'),
'utf8', 'utf8',
); )
// set private key and public key to env // set private key and public key to env
process.env.JWT_RS256_PRIVATE_KEY = privateKey; process.env.JWT_RS256_PRIVATE_KEY = privateKey
process.env.JWT_RS256_PUBLIC_KEY = publicKey; process.env.JWT_RS256_PUBLIC_KEY = publicKey
Logger.log( Logger.log(
`Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`, `Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`,
'Bootstrap', 'Bootstrap',
); )
Logger.log( Logger.log(
`Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`, `Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`,
'Bootstrap', 'Bootstrap',
); )
const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(','); // split by comma to array const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(',') // split by comma to array
app.enableCors({ app.enableCors({
origin: corsOrigin, origin: corsOrigin,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
@@ -44,20 +44,20 @@ async function bootstrap() {
'x-session-id', 'x-session-id',
], ],
credentials: true, credentials: true,
}); })
// set base path for api // set base path for api
app.setGlobalPrefix(process.env.API_PATH ?? '/v1'); app.setGlobalPrefix(process.env.API_PATH ?? '/v1')
const config = new DocumentBuilder() const config = new DocumentBuilder()
.setTitle('EPESS API') .setTitle('EPESS API')
.setDescription('API documentation for EPESS application') .setDescription('API documentation for EPESS application')
.setVersion('0.0.1') .setVersion('0.0.1')
.addBearerAuth() .addBearerAuth()
.build(); .build()
const document = SwaggerModule.createDocument(app, config); const document = SwaggerModule.createDocument(app, config)
SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'v1', app, document); SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'v1', app, document)
document.paths[process.env.API_PATH + '/graphql'] = { document.paths[process.env.API_PATH + '/graphql'] = {
get: { get: {
@@ -71,10 +71,10 @@ async function bootstrap() {
}, },
}, },
}, },
}; }
// clerk middleware // clerk middleware
app.use(clerkMiddleware({})); app.use(clerkMiddleware({}))
// graphql upload // graphql upload
app.use( app.use(
@@ -82,11 +82,11 @@ async function bootstrap() {
maxFileSize: 100 * 1024 * 1024, // 100 MB maxFileSize: 100 * 1024 * 1024, // 100 MB
maxFiles: 10, maxFiles: 10,
}), }),
); )
const host = process.env.LISTEN_HOST ?? '0.0.0.0'; const host = process.env.LISTEN_HOST ?? '0.0.0.0'
const port = process.env.LISTEN_PORT ?? 3000; // Default to 3000 if LISTEN_PORT is not set const port = process.env.LISTEN_PORT ?? 3000 // Default to 3000 if LISTEN_PORT is not set
await app.listen(port, host, () => { await app.listen(port, host, () => {
Logger.log(`Server is running on http://${host}:${port}`, 'Bootstrap'); Logger.log(`Server is running on http://${host}:${port}`, 'Bootstrap')
}); })
} }
bootstrap(); bootstrap()

File diff suppressed because one or more lines are too long

View File

@@ -1,24 +1,24 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing'
import { INestApplication } from '@nestjs/common'; import { INestApplication } from '@nestjs/common'
import * as request from 'supertest'; import * as request from 'supertest'
import { AppModule } from './../src/app.module'; import { AppModule } from './../src/app.module'
describe('AppController (e2e)', () => { describe('AppController (e2e)', () => {
let app: INestApplication; let app: INestApplication
beforeEach(async () => { beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({ const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule], imports: [AppModule],
}).compile(); }).compile()
app = moduleFixture.createNestApplication(); app = moduleFixture.createNestApplication()
await app.init(); await app.init()
}); })
it('/ (GET)', () => { it('/ (GET)', () => {
return request(app.getHttpServer()) return request(app.getHttpServer())
.get('/') .get('/')
.expect(200) .expect(200)
.expect('Hello World!'); .expect('Hello World!')
}); })
}); })