import { Inject, Injectable, Logger } from '@nestjs/common'; import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken, } from '@smatch-corp/nestjs-pothos'; import { Builder } from '../Graphql/graphql.builder'; import { PrismaService } from '../Prisma/prisma.service'; import { clerkClient } from '@clerk/express'; import type { Session } from '@clerk/express'; import { UnauthorizedException } from '@nestjs/common'; @Injectable() export class UserSchema extends PothosSchema { constructor( @Inject(SchemaBuilderToken) private readonly builder: Builder, private readonly prisma: PrismaService, ) { super(); } // Types section @PothosRef() user() { return this.builder.prismaObject('User', { description: 'A user in the system.', fields: (t) => ({ id: t.exposeID('id', { description: 'The ID of the user.', }), name: t.exposeString('name', { description: 'The name of the user.', }), email: t.exposeString('email', { description: 'The email of the user.', }), phoneNumber: t.exposeString('phoneNumber', { description: 'The phone number of the user.', }), bankBin: t.exposeString('bankBin', { description: 'The bank bin of the user.', }), bankAccountNumber: t.exposeString('bankAccountNumber', { description: 'The bank account number of the user.', }), role: t.exposeString('role', { description: 'The role of the user.', }), createdAt: t.expose('createdAt', { type: 'DateTime', nullable: true, description: 'The date and time the user was created.', }), updatedAt: t.expose('updatedAt', { type: 'DateTime', nullable: true, description: 'The date and time the user was updated.', }), orders: t.relation('orders', { description: 'The orders of the user.', }), serviceFeedbacks: t.relation('serviceFeedbacks', { description: 'The service feedbacks of the user.', }), files: t.relation('files', { description: 'The files of the user.', }), sendingMessage: t.relation('sendingMessage', { description: 'The sending message of the user.', }), center: t.relation('center', { description: 'The center of the user.', }), customerChatRoom: t.relation('customerChatRoom', { description: 'The customer chat room of the user.', }), centerStaffChatRoom: t.relation('centerStaffChatRoom', { description: 'The center staff chat room of the user.', }), CenterStaff: t.relation('CenterStaff', { description: 'The center staff of the user.', }), WorkshopSubscription: t.relation('WorkshopSubscription', { description: 'The workshop subscription of the user.', }), }), }); } // Query section @Pothos() init(): void { this.builder.queryFields((t) => ({ session: t.field({ type: 'Json', args: { sessionId: t.arg({ type: 'String', required: true }), }, resolve: async (_, { sessionId }) => { const session = await clerkClient.sessions.getSession(sessionId); return JSON.parse(JSON.stringify(session)); }, }), newSession: t.field({ type: 'String', args: { userId: t.arg({ type: 'String', required: true, }), }, resolve: async (_, { userId }) => { const session = await clerkClient.signInTokens.createSignInToken({ userId, expiresInSeconds: 60 * 60 * 24, }); return session.id; }, }), me: t.prismaField({ description: 'Retrieve the current user.', type: this.user(), resolve: async (query, root, args, ctx, info) => { const sessionCookie = ctx.req.headers.cookie ?.split('; ') .find((row) => row.startsWith('__session=')) ?.split('=')[1]; if (!sessionCookie) throw new UnauthorizedException({ message: 'No session cookie found', }); const session = await clerkClient.sessions.getSession(sessionCookie); if (!session) throw new UnauthorizedException(); return await this.prisma.user.findUnique({ where: { id: session.userId }, }); }, }), users: t.prismaField({ description: 'Retrieve a list of users with optional filtering, ordering, and pagination.', type: [this.user()], args: this.builder.generator.findManyArgs('User'), resolve: async (query, root, args, ctx, info) => { return await this.prisma.user.findMany({ ...query, take: args.take ?? 10, skip: args.skip ?? undefined, orderBy: args.orderBy ?? undefined, where: args.filter ?? undefined, }); }, }), user: t.prismaField({ description: 'Retrieve a single user by their unique identifier.', type: this.user(), args: this.builder.generator.findUniqueArgs('User'), resolve: async (query, root, args, ctx, info) => { return await this.prisma.user.findUnique({ ...query, where: args.where, }); }, }), userBySession: t.prismaField({ description: 'Retrieve a single user by their session ID.', type: this.user(), args: { sessionId: t.arg({ type: 'String', required: true }), }, resolve: async (query, root, args, ctx, info) => { // check if the token is valid const session = await clerkClient.sessions.getSession(args.sessionId); Logger.log(session, 'Session'); return await this.prisma.user.findFirst({ ...query, where: { id: session.userId, }, }); }, }), })); // Mutation section this.builder.mutationFields((t) => ({ updateUser: t.prismaField({ description: 'Update an existing user.', type: this.user(), args: { input: t.arg({ type: this.builder.generator.getUpdateInput('User'), required: true, }), where: t.arg({ type: this.builder.generator.getWhereUnique('User'), required: true, }), }, resolve: async (query, root, args, ctx, info) => { return await this.prisma.user.update({ ...query, where: args.where, data: args.input, }); }, }), // banUser: t.prismaField({ // description: 'Ban a user.', // type: this.user(), // args: { // userId: t.arg({ type: 'String', required: true }), // }, // resolve: async (query, root, args, ctx, info) => { // return await this.prisma.user.update({ // ...query, // where: { id: args.userId }, // data: { banned: true }, // }); // }, // }), })); } }