fix time geneate logic and replace default datetime by luxon
This commit is contained in:
Submodule epess-database updated: eb5e274bd0...6d55331650
18
package-lock.json
generated
18
package-lock.json
generated
@@ -50,6 +50,7 @@
|
||||
"graphql-ws": "^5.16.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"luxon": "^3.5.0",
|
||||
"minio": "^8.0.1",
|
||||
"nestjs-minio": "^2.6.2",
|
||||
"nodemailer": "^6.9.15",
|
||||
@@ -78,6 +79,7 @@
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/nodemailer": "^6.4.16",
|
||||
"@types/passport-jwt": "^4.0.1",
|
||||
@@ -5548,6 +5550,13 @@
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz",
|
||||
"integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/methods": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz",
|
||||
@@ -12883,6 +12892,15 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
|
||||
"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.30.8",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
"graphql-ws": "^5.16.0",
|
||||
"ioredis": "^5.4.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"luxon": "^3.5.0",
|
||||
"minio": "^8.0.1",
|
||||
"nestjs-minio": "^2.6.2",
|
||||
"nodemailer": "^6.9.15",
|
||||
@@ -100,6 +101,7 @@
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/jest": "^29.5.2",
|
||||
"@types/lodash": "^4.17.13",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/nodemailer": "^6.4.16",
|
||||
"@types/passport-jwt": "^4.0.1",
|
||||
|
||||
@@ -3,6 +3,9 @@ import { Injectable, Logger } from '@nestjs/common'
|
||||
import { PrismaService } from '../Prisma/prisma.service'
|
||||
import { clerkClient } from '@clerk/express'
|
||||
|
||||
export interface ClerkResponse {
|
||||
|
||||
}
|
||||
@Injectable()
|
||||
export class ClerkService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
|
||||
@@ -41,6 +41,7 @@ export type SchemaContext =
|
||||
res: Response
|
||||
me: User
|
||||
pubSub: PubSub
|
||||
invalidateCache: () => Promise<void>
|
||||
generator: PrismaCrudGenerator<BuilderTypes>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,12 @@ import { initContextCache } from '@pothos/core'
|
||||
...initContextCache(),
|
||||
isSubscription: false,
|
||||
http: {
|
||||
req,
|
||||
me: await graphqlService.acquireContext(req),
|
||||
invalidateCache: () =>
|
||||
graphqlService.invalidateCache(
|
||||
req.headers['x-session-id'] as string,
|
||||
),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -37,6 +37,7 @@ export class GraphqlService {
|
||||
// redis context cache
|
||||
const cachedUser = await this.redis.getUser(sessionId)
|
||||
if (cachedUser) {
|
||||
Logger.log(`Cache hit for sessionId: ${sessionId}`)
|
||||
return cachedUser
|
||||
}
|
||||
// check if the token is valid
|
||||
@@ -53,4 +54,10 @@ export class GraphqlService {
|
||||
await this.redis.setUser(sessionId, user, session.expireAt)
|
||||
return user
|
||||
}
|
||||
|
||||
async invalidateCache(sessionId: string) {
|
||||
// invalidate redis cache for sessionId
|
||||
await this.redis.del(sessionId)
|
||||
Logger.log(`Invalidated cache for sessionId: ${sessionId}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ export class MessageSchema extends PothosSchema {
|
||||
description: 'The ID of the chat room.',
|
||||
}),
|
||||
message: t.expose('message', {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
type: 'Json' as any,
|
||||
description: 'The message content.',
|
||||
}),
|
||||
|
||||
@@ -81,7 +81,7 @@ export class OrderSchema extends PothosSchema {
|
||||
description:
|
||||
'Retrieve a list of orders with optional filtering, ordering, and pagination.',
|
||||
args: this.builder.generator.findManyArgs('Order'),
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.order.findMany({
|
||||
...query,
|
||||
take: args.take ?? undefined,
|
||||
@@ -95,7 +95,7 @@ export class OrderSchema extends PothosSchema {
|
||||
type: this.order(),
|
||||
args: this.builder.generator.findUniqueArgs('Order'),
|
||||
description: 'Retrieve a single order by its unique identifier.',
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.order.findUnique({
|
||||
...query,
|
||||
where: args.where,
|
||||
@@ -124,7 +124,7 @@ export class OrderSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return this.prisma.$transaction(async (prisma) => {
|
||||
const order = await prisma.order.create({
|
||||
...query,
|
||||
@@ -162,7 +162,7 @@ export class OrderSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.order.delete({
|
||||
...query,
|
||||
where: args.where,
|
||||
@@ -185,7 +185,7 @@ export class OrderSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.order.update({
|
||||
...query,
|
||||
data: args.data,
|
||||
|
||||
@@ -23,6 +23,16 @@ export type ScheduleConfigType =
|
||||
| null
|
||||
| undefined
|
||||
|
||||
export type ScheduleConfigTypeForCenter =
|
||||
| {
|
||||
startDate?: string | null | undefined
|
||||
endDate?: string | null | undefined
|
||||
slots?: number[] | null | undefined
|
||||
days?: number[] | null | undefined
|
||||
}
|
||||
| null
|
||||
| undefined
|
||||
|
||||
export type ScheduleSlotType = {
|
||||
slot: string
|
||||
start: string
|
||||
@@ -144,6 +154,18 @@ export class ScheduleSchema extends PothosSchema {
|
||||
})
|
||||
}
|
||||
|
||||
@PothosRef()
|
||||
scheduleConfigInputForCenter() {
|
||||
return this.builder.inputType('ScheduleConfigInputForCenter', {
|
||||
fields: (t) => ({
|
||||
startDate: t.string(),
|
||||
endDate: t.string(),
|
||||
slots: t.intList(),
|
||||
days: t.intList(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
@Pothos()
|
||||
init(): void {
|
||||
this.builder.queryFields((t) => ({
|
||||
@@ -175,6 +197,21 @@ export class ScheduleSchema extends PothosSchema {
|
||||
},
|
||||
}),
|
||||
|
||||
// centerPreviewSchedule: t.field({
|
||||
// type: this.previewSchedule(),
|
||||
// description: 'Preview a schedule for center mentor.',
|
||||
// args: {
|
||||
// scheduleConfig: t.arg({
|
||||
// type: this.scheduleConfigInputForCenter(),
|
||||
// }),
|
||||
// },
|
||||
// resolve: async (_parent, args, _context, _info) => {
|
||||
// return await this.scheduleService.createSchedulePreviewForCenter(
|
||||
// args.scheduleConfig,
|
||||
// )
|
||||
// },
|
||||
// }),
|
||||
|
||||
adminPreviewSchedule: t.field({
|
||||
type: this.previewSchedule(),
|
||||
description: 'Preview a schedule for admin.',
|
||||
|
||||
@@ -7,11 +7,21 @@ import { AppConfigService } from 'src/AppConfig/appconfig.service'
|
||||
import {
|
||||
PreviewScheduleType,
|
||||
ScheduleConfigType,
|
||||
ScheduleConfigTypeForCenter,
|
||||
ScheduleSlotType,
|
||||
} from './schedule.schema'
|
||||
import { Config } from '@prisma/client'
|
||||
import { DateTime, Settings, Zone } from 'luxon'
|
||||
import * as _ from 'lodash'
|
||||
|
||||
Settings.defaultLocale = 'en-US'
|
||||
Settings.defaultZone = 'utc'
|
||||
// Settings.defaultWeekSettings = {
|
||||
// firstDay: 2,
|
||||
// minimalDays: 1,
|
||||
// weekend: [6, 7],
|
||||
// }
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleService {
|
||||
constructor(
|
||||
@@ -38,6 +48,18 @@ export class ScheduleService {
|
||||
}
|
||||
}
|
||||
|
||||
// async createSchedulePreviewForCenter(
|
||||
// scheduleConfig: ScheduleConfigTypeForCenter,
|
||||
// ): Promise<PreviewScheduleType> {
|
||||
// const config: Config[] = await this.appConfigService.getVisibleConfigs()
|
||||
// Logger.log(config)
|
||||
// // process scheduleConfig input by filling with default values from config
|
||||
// const scheduleConfigFilled = this.processScheduleConfig(
|
||||
// scheduleConfig,
|
||||
// config,
|
||||
// )
|
||||
// }
|
||||
|
||||
generateSlots(scheduleConfigFilled: ScheduleConfigType): ScheduleSlotType[] {
|
||||
Logger.log(`Generating slots with config: ${scheduleConfigFilled}`)
|
||||
const slots: ScheduleSlotType[] = []
|
||||
@@ -66,11 +88,11 @@ export class ScheduleService {
|
||||
!this.isOverLapping(
|
||||
startTime,
|
||||
endTime,
|
||||
this.getSpecificDateWithTime(
|
||||
DateTime.fromISO(
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.midDayBreakTimeStart,
|
||||
),
|
||||
this.getSpecificDateWithTime(
|
||||
DateTime.fromISO(
|
||||
// @ts-ignore
|
||||
scheduleConfigFilled?.midDayBreakTimeEnd,
|
||||
),
|
||||
@@ -78,8 +100,8 @@ export class ScheduleService {
|
||||
) {
|
||||
slots.push({
|
||||
slot: i.toString(),
|
||||
start: startTime.toISOString(),
|
||||
end: endTime.toISOString(),
|
||||
start: startTime.toString(),
|
||||
end: endTime.toString(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -87,14 +109,14 @@ export class ScheduleService {
|
||||
}
|
||||
|
||||
isOverLapping(
|
||||
startTime1: Date,
|
||||
endTime1: Date,
|
||||
startTime2: Date,
|
||||
endTime2: Date,
|
||||
startTime1: DateTime,
|
||||
endTime1: DateTime,
|
||||
startTime2: DateTime,
|
||||
endTime2: DateTime,
|
||||
) {
|
||||
return (
|
||||
Math.max(startTime1.getTime(), startTime2.getTime()) <
|
||||
Math.min(endTime1.getTime(), endTime2.getTime())
|
||||
Math.max(startTime1.toMillis(), startTime2.toMillis()) <
|
||||
Math.min(endTime1.toMillis(), endTime2.toMillis())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -104,10 +126,11 @@ export class ScheduleService {
|
||||
slotDuration: string,
|
||||
slotBreakDuration: string,
|
||||
) {
|
||||
const startDate = new Date(startTime)
|
||||
const endDate = new Date(endTime)
|
||||
const startDate = DateTime.fromISO(startTime)
|
||||
const endDate = DateTime.fromISO(endTime)
|
||||
|
||||
const totalMinutes = (endDate.getTime() - startDate.getTime()) / (60 * 1000)
|
||||
const totalMinutes =
|
||||
(endDate.toMillis() - startDate.toMillis()) / (60 * 1000)
|
||||
const numberOfSlots = Math.floor(
|
||||
totalMinutes / (parseInt(slotDuration) + parseInt(slotBreakDuration)),
|
||||
)
|
||||
@@ -120,13 +143,14 @@ export class ScheduleService {
|
||||
slotBreakDuration: string,
|
||||
slotStartTime: string,
|
||||
) {
|
||||
const startTime = new Date(slotStartTime)
|
||||
startTime.setUTCMinutes(
|
||||
startTime.getUTCMinutes() +
|
||||
slotNumber * (parseInt(slotDuration) + parseInt(slotBreakDuration)),
|
||||
)
|
||||
const endTime = new Date(startTime)
|
||||
endTime.setUTCMinutes(endTime.getUTCMinutes() + parseInt(slotDuration))
|
||||
const durationInMinutes = parseInt(slotDuration);
|
||||
const breakDurationInMinutes = parseInt(slotBreakDuration);
|
||||
|
||||
const startTime = DateTime.fromISO(slotStartTime).plus({
|
||||
minutes: (slotNumber - 1) * (durationInMinutes + breakDurationInMinutes),
|
||||
});
|
||||
|
||||
const endTime = startTime.plus({ minutes: durationInMinutes })
|
||||
return { startTime, endTime }
|
||||
}
|
||||
|
||||
@@ -169,26 +193,23 @@ export class ScheduleService {
|
||||
return _.camelCase(str.toLowerCase())
|
||||
}
|
||||
|
||||
getTodayWithTime(date: Date) {
|
||||
const today = new Date()
|
||||
today.setUTCHours(
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
0,
|
||||
)
|
||||
getTodayWithTime(date: DateTime) {
|
||||
let today = DateTime.now()
|
||||
today = today.set({
|
||||
hour: date.hour,
|
||||
minute: date.minute,
|
||||
second: date.second,
|
||||
})
|
||||
return today
|
||||
}
|
||||
|
||||
getSpecificDateWithTime(date: Date) {
|
||||
const specificDate = new Date(date)
|
||||
date = new Date(date)
|
||||
specificDate.setUTCHours(
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
0,
|
||||
)
|
||||
getSpecificDateWithTime(date: DateTime) {
|
||||
let specificDate = DateTime.now()
|
||||
specificDate = specificDate.set({
|
||||
hour: date.hour,
|
||||
minute: date.minute,
|
||||
second: date.second,
|
||||
})
|
||||
return specificDate
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
|
||||
args: this.builder.generator.findUniqueArgs('ServiceMeetingRoom'),
|
||||
description:
|
||||
'Retrieve a single service meeting room by its unique identifier.',
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.serviceMeetingRoom.findUnique({
|
||||
...query,
|
||||
where: args.where,
|
||||
@@ -55,7 +55,7 @@ export class ServiceMeetingRoomSchema extends PothosSchema {
|
||||
args: this.builder.generator.findManyArgs('ServiceMeetingRoom'),
|
||||
description:
|
||||
'Retrieve a list of service meeting rooms with optional filtering, ordering, and pagination.',
|
||||
resolve: async (query, root, args, ctx, info) => {
|
||||
resolve: async (query, _root, args, _ctx, _info) => {
|
||||
return await this.prisma.serviceMeetingRoom.findMany({
|
||||
...query,
|
||||
skip: args.skip ?? undefined,
|
||||
|
||||
@@ -73,7 +73,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
'Retrieve a single uploaded file by its unique identifier.',
|
||||
type: this.uploadedFile(),
|
||||
args: this.builder.generator.findUniqueArgs('UploadedFile'),
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (query, _root, args) => {
|
||||
const file = await this.prisma.uploadedFile.findUnique({
|
||||
...query,
|
||||
where: args.where,
|
||||
@@ -94,7 +94,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
'Retrieve a list of uploaded files with optional filtering, ordering, and pagination.',
|
||||
type: [this.uploadedFile()],
|
||||
args: this.builder.generator.findManyArgs('UploadedFile'),
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (query, _root, args) => {
|
||||
const files = await this.prisma.uploadedFile.findMany({
|
||||
...query,
|
||||
skip: args.skip ?? undefined,
|
||||
@@ -132,7 +132,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (_query, _root, args) => {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: args.userId,
|
||||
@@ -182,7 +182,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (_query, _root, args) => {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: {
|
||||
id: args.userId,
|
||||
@@ -230,7 +230,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (_query, _root, args) => {
|
||||
const file = await this.prisma.uploadedFile.findUnique({
|
||||
where: {
|
||||
id: args.id,
|
||||
@@ -259,7 +259,7 @@ export class UploadedFileSchema extends PothosSchema {
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
resolve: async (query, root, args) => {
|
||||
resolve: async (_query, _root, args) => {
|
||||
const files = await this.prisma.uploadedFile.findMany({
|
||||
where: {
|
||||
id: {
|
||||
|
||||
@@ -214,6 +214,113 @@ export class UserSchema extends PothosSchema {
|
||||
},
|
||||
}),
|
||||
|
||||
updateMe: t.field({
|
||||
type: this.user(),
|
||||
description: 'Update the current user in context.',
|
||||
args: {
|
||||
input: t.arg({
|
||||
type: this.builder.generator.getUpdateInput('User', [
|
||||
'id',
|
||||
'adminNote',
|
||||
'center',
|
||||
'customerChatRoom',
|
||||
'avatarUrl',
|
||||
// 'bankAccountNumber',
|
||||
// 'bankBin',
|
||||
'email',
|
||||
'name',
|
||||
'phoneNumber',
|
||||
'role',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
'files',
|
||||
'orders',
|
||||
'sendingMessage',
|
||||
'mentor',
|
||||
'mentorChatRoom',
|
||||
'resume',
|
||||
'service',
|
||||
'serviceFeedbacks',
|
||||
'workshopSubscription',
|
||||
]),
|
||||
required: false,
|
||||
}),
|
||||
imageBlob: t.arg({
|
||||
type: 'Upload',
|
||||
required: false,
|
||||
}),
|
||||
firstName: t.arg({
|
||||
type: 'String',
|
||||
required: false,
|
||||
}),
|
||||
lastName: t.arg({
|
||||
type: 'String',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
resolve: async (_query, args, ctx, _info) => {
|
||||
if (ctx.isSubscription) {
|
||||
throw new Error('Not allowed')
|
||||
}
|
||||
const id = ctx.http.me.id
|
||||
if (args.imageBlob) {
|
||||
const { mimetype, createReadStream } = await args.imageBlob
|
||||
if (mimetype && createReadStream) {
|
||||
const stream = createReadStream()
|
||||
const chunks: Uint8Array[] = []
|
||||
|
||||
for await (const chunk of stream) {
|
||||
chunks.push(chunk)
|
||||
}
|
||||
|
||||
const buffer = Buffer.concat(chunks)
|
||||
await clerkClient.users.updateUserProfileImage(id, {
|
||||
file: new Blob([buffer]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// update info to clerk
|
||||
const clerkUser = await clerkClient.users.updateUser(id, {
|
||||
firstName: args.firstName as string,
|
||||
lastName: args.lastName as string,
|
||||
})
|
||||
Logger.log(clerkUser, 'Clerk User')
|
||||
// update bank account number and bank bin to database
|
||||
if (args.input?.bankAccountNumber) {
|
||||
await this.prisma.user.update({
|
||||
where: { id: clerkUser.id },
|
||||
data: {
|
||||
bankAccountNumber: args.input.bankAccountNumber,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (args.input?.bankBin) {
|
||||
await this.prisma.user.update({
|
||||
where: { id: clerkUser.id },
|
||||
data: {
|
||||
bankBin: args.input.bankBin,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (args.firstName || args.lastName) {
|
||||
await this.prisma.user.update({
|
||||
where: { id: clerkUser.id },
|
||||
data: {
|
||||
name: `${args.firstName || ''} ${args.lastName || ''}`.trim(),
|
||||
},
|
||||
})
|
||||
}
|
||||
// invalidate cache
|
||||
await ctx.http.invalidateCache()
|
||||
return await this.prisma.user.findUniqueOrThrow({
|
||||
where: { id: clerkUser.id },
|
||||
})
|
||||
},
|
||||
}),
|
||||
|
||||
inviteModerator: t.field({
|
||||
type: 'String',
|
||||
args: {
|
||||
|
||||
Reference in New Issue
Block a user