From 776881f9613d52858554b372f4727913ee3c29e1 Mon Sep 17 00:00:00 2001 From: Ly Tuan Kiet Date: Fri, 20 Dec 2024 18:30:50 +0700 Subject: [PATCH] chore: combine context --- src/Analytic/analytic.schema.ts | 42 ++-- src/Center/center.schema.ts | 12 +- src/CenterMentor/centermentor.schema.ts | 14 +- src/ChatRoom/chatroom.schema.ts | 146 ++++++++---- .../collaborationsession.schema.ts | 38 ++-- src/Document/document.schema.ts | 116 ++-------- src/Graphql/graphql.builder.ts | 210 +++++++++--------- src/Graphql/graphql.module.ts | 188 ++++++++-------- src/MeetingRoom/meetingroom.schema.ts | 31 +-- src/Message/message.schema.ts | 21 +- src/Order/order.schema.ts | 41 ++-- .../personalmilestone.schema.ts | 31 +-- src/Quiz/quiz.schema.ts | 67 ++---- src/RefundTicket/refundticket.schema.ts | 49 ++-- src/Resume/resume.schema.ts | 32 +-- src/Schedule/schedule.schema.ts | 35 ++- src/Service/service.schema.ts | 42 ++-- src/ServiceFeedback/servicefeedback.schema.ts | 13 +- src/User/user.module.ts | 9 +- src/User/user.schema.ts | 54 ++--- src/Workshop/workshop.schema.ts | 11 +- .../workshopmeetingroom.schema.ts | 7 +- .../workshopsubscription.schema.ts | 17 +- 23 files changed, 532 insertions(+), 694 deletions(-) diff --git a/src/Analytic/analytic.schema.ts b/src/Analytic/analytic.schema.ts index eeec61f..614f6e5 100644 --- a/src/Analytic/analytic.schema.ts +++ b/src/Analytic/analytic.schema.ts @@ -171,19 +171,16 @@ export class AnalyticSchema extends PothosSchema { type: this.customerAnalytic(), description: 'Retrieve a single customer analytic.', resolve: async (_parent, _args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.CUSTOMER) { + if (ctx.me.role !== Role.CUSTOMER) { throw new Error('Only customers can access this data') } // calculate analytic const activeServiceCount = await this.prisma.order.count({ where: { - userId: ctx.http.me.id, + userId: ctx.me.id, status: OrderStatus.PAID, schedule: { dates: { @@ -198,12 +195,12 @@ export class AnalyticSchema extends PothosSchema { }) const totalServiceCount = await this.prisma.order.count({ where: { - userId: ctx.http.me.id, + userId: ctx.me.id, }, }) const totalSpent = await this.prisma.order.aggregate({ where: { - userId: ctx.http.me.id, + userId: ctx.me.id, status: OrderStatus.PAID, }, _sum: { @@ -211,7 +208,7 @@ export class AnalyticSchema extends PothosSchema { }, }) return { - userId: ctx.http.me.id, + userId: ctx.me.id, activeServiceCount: activeServiceCount, totalServiceCount: totalServiceCount, totalSpent: totalSpent._sum.total, @@ -223,18 +220,15 @@ export class AnalyticSchema extends PothosSchema { type: this.mentorAnalytic(), description: 'Retrieve a single mentor analytic.', resolve: async (_parent, _args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.CENTER_MENTOR) { + if (ctx.me.role !== Role.CENTER_MENTOR) { throw new Error('Only center mentors can access this data') } // calculate analytic return { - userId: ctx.http.me.id, + userId: ctx.me.id, } }, }), @@ -242,19 +236,16 @@ export class AnalyticSchema extends PothosSchema { type: this.centerAnalytic(), description: 'Retrieve a single center analytic.', resolve: async (_parent, _args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.CENTER_OWNER) { + if (ctx.me.role !== Role.CENTER_OWNER) { throw new Error('Only center owners can access this data') } // get center by owner id const center = await this.prisma.center.findUnique({ where: { - centerOwnerId: ctx.http.me.id, + centerOwnerId: ctx.me.id, }, }) if (!center) { @@ -266,7 +257,7 @@ export class AnalyticSchema extends PothosSchema { const activeMentorCount = await this.prisma.user.count({ where: { center: { - centerOwnerId: ctx.http.me.id, + centerOwnerId: ctx.me.id, }, banned: false, }, @@ -340,13 +331,10 @@ export class AnalyticSchema extends PothosSchema { }, description: 'Retrieve a single platform analytic.', resolve: async (_parent, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.ADMIN && ctx.http.me.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.ADMIN && ctx.me.role !== Role.MODERATOR) { throw new Error('Only admins and moderators can access this data') } // calculate analytic for services sorted by args.serviceSortBy and args.timeframes diff --git a/src/Center/center.schema.ts b/src/Center/center.schema.ts index d485ec5..cbf508c 100644 --- a/src/Center/center.schema.ts +++ b/src/Center/center.schema.ts @@ -154,16 +154,13 @@ export class CenterSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed in subscription') - } - if (ctx.http.me?.role !== Role.CUSTOMER) { + if (ctx.me?.role !== Role.CUSTOMER) { throw new Error('Not allowed') } // check if user has already created a center const existingCenter = await this.prisma.center.findFirst({ where: { - centerOwnerId: ctx.http.me?.id, + centerOwnerId: ctx.me?.id, }, }) if (existingCenter) { @@ -239,10 +236,7 @@ export class CenterSchema extends PothosSchema { }, resolve: async (query, _root, args, ctx) => { return await this.prisma.$transaction(async (prisma) => { - if (ctx.isSubscription) { - throw new Error('Not allowed in subscription') - } - if (ctx.http.me?.role !== Role.ADMIN && ctx.http.me?.role !== Role.MODERATOR) { + if (ctx.me?.role !== Role.ADMIN && ctx.me?.role !== Role.MODERATOR) { throw new Error('Not allowed') } const center = await prisma.center.findUnique({ diff --git a/src/CenterMentor/centermentor.schema.ts b/src/CenterMentor/centermentor.schema.ts index 1d234a2..af40f30 100644 --- a/src/CenterMentor/centermentor.schema.ts +++ b/src/CenterMentor/centermentor.schema.ts @@ -139,11 +139,11 @@ export class CenterMentorSchema extends PothosSchema { }, resolve: async (_query, _root, args, ctx) => { return this.prisma.$transaction(async (prisma) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } // get centerId by user id from context - const userId = ctx.http.me?.id + const userId = ctx.me.id if (!userId) { throw new Error('User ID is required') } @@ -205,8 +205,8 @@ export class CenterMentorSchema extends PothosSchema { adminNote: t.arg({ type: 'String', required: false }), }, resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } return this.prisma.$transaction(async (prisma) => { // get mentor info @@ -255,7 +255,7 @@ export class CenterMentorSchema extends PothosSchema { data: { content: args.adminNote ?? '', mentorId: mentor.id, - notedByUserId: ctx.http.me?.id ?? '', + notedByUserId: ctx.me.id, }, }) // update user role @@ -310,7 +310,7 @@ export class CenterMentorSchema extends PothosSchema { adminNote: { create: { content: args.adminNote ?? '', - notedByUserId: ctx.http.me?.id ?? '', + notedByUserId: ctx.me.id, updatedAt: new Date(), }, }, diff --git a/src/ChatRoom/chatroom.schema.ts b/src/ChatRoom/chatroom.schema.ts index b94d09e..139cde1 100644 --- a/src/ChatRoom/chatroom.schema.ts +++ b/src/ChatRoom/chatroom.schema.ts @@ -1,88 +1,123 @@ -import { Inject, Injectable } from '@nestjs/common' -import { ChatRoomType } from '@prisma/client' -import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos' -import { Builder } from '../Graphql/graphql.builder' -import { PrismaService } from '../Prisma/prisma.service' +import { Inject, Injectable } from "@nestjs/common"; +import { ChatRoomType } from "@prisma/client"; +import { + Pothos, + PothosRef, + PothosSchema, + SchemaBuilderToken, +} from "@smatch-corp/nestjs-pothos"; +import { Builder } from "../Graphql/graphql.builder"; +import { PrismaService } from "../Prisma/prisma.service"; @Injectable() export class ChatroomSchema extends PothosSchema { constructor( @Inject(SchemaBuilderToken) private readonly builder: Builder, - private readonly prisma: PrismaService, + private readonly prisma: PrismaService ) { - super() + super(); } @PothosRef() chatRoom() { - return this.builder.prismaObject('ChatRoom', { - description: 'A chat room in the system.', + return this.builder.prismaObject("ChatRoom", { + description: "A chat room in the system.", fields: (t) => ({ - id: t.exposeID('id', { - description: 'The ID of the chat room.', + id: t.exposeID("id", { + description: "The ID of the chat room.", }), - type: t.expose('type', { + type: t.expose("type", { type: ChatRoomType, - description: 'The type of the chat room.', + description: "The type of the chat room.", }), - customerId: t.exposeID('customerId', { - description: 'The ID of the customer.', + customerId: t.exposeID("customerId", { + description: "The ID of the customer.", }), - centerId: t.exposeID('centerId', { - description: 'The ID of the center.', + centerId: t.exposeID("centerId", { + description: "The ID of the center.", }), - mentorId: t.exposeID('mentorId', { - description: 'The ID of the mentor.', + mentorId: t.exposeID("mentorId", { + description: "The ID of the mentor.", }), - createdAt: t.expose('createdAt', { - type: 'DateTime', - description: 'The date and time the chat room was created.', + createdAt: t.expose("createdAt", { + type: "DateTime", + description: "The date and time the chat room was created.", }), - message: t.relation('message', { - description: 'The messages in the chat room.', + message: t.relation("message", { + description: "The messages in the chat room.", }), - customer: t.relation('customer', { - description: 'The customer.', + customer: t.relation("customer", { + description: "The customer.", }), - center: t.relation('center', { - description: 'The center.', + center: t.relation("center", { + description: "The center.", }), - mentor: t.relation('mentor', { - description: 'The mentor.', + mentor: t.relation("mentor", { + description: "The mentor.", }), - collaborationSession: t.relation('CollaborationSession', { - description: 'The collaboration session.', + collaborationSession: t.relation("CollaborationSession", { + description: "The collaboration session.", }), - lastActivity: t.expose('lastActivity', { - type: 'DateTime', - description: 'The last activity date and time.', + lastActivity: t.expose("lastActivity", { + type: "DateTime", + description: "The last activity date and time.", }), - order: t.relation('Order', { - description: 'The order.', + order: t.relation("Order", { + description: "The order.", }), }), - }) + }); } + // @PothosRef() + // chatUser() { + // return this.builder.simpleObject("ChatUser", { + // description: "A user in a chat room.", + // fields: (t) => ({ + // user: t.field({ + // type: this.userSchema.user(), + // description: "The user.", + // }), + // chatRoom: t.field({ + // type: this.chatRoom(), + // description: "The chat room.", + // }), + // lastMessage: t.field({ + // type: this.messageSchema.message(), + // description: "The last message.", + // }), + // lastMessageAt: t.field({ + // type: "DateTime", + // description: "The date and time of the last message.", + // }), + // unreadCount: t.field({ + // type: "Int", + // description: "The number of unread messages.", + // }), + // }), + // }); + // } + @Pothos() init(): void { this.builder.queryFields((t) => ({ chatRoom: t.prismaField({ type: this.chatRoom(), - description: 'Retrieve a single chat room by its unique identifier.', - args: this.builder.generator.findUniqueArgs('ChatRoom'), + description: "Retrieve a single chat room by its unique identifier.", + args: this.builder.generator.findUniqueArgs("ChatRoom"), resolve: async (query, _root, args, _ctx, _info) => { return await this.prisma.chatRoom.findUnique({ ...query, where: args.where, - }) + }); }, }), chatRooms: t.prismaField({ type: [this.chatRoom()], - description: 'Retrieve a list of chat rooms with optional filtering, ordering, and pagination.', - args: this.builder.generator.findManyArgs('ChatRoom'), + description: + "Retrieve a list of chat rooms with optional filtering, ordering, and pagination.", + args: this.builder.generator.findManyArgs("ChatRoom"), resolve: async (query, _root, args, _ctx, _info) => { return await this.prisma.chatRoom.findMany({ ...query, @@ -90,9 +125,30 @@ export class ChatroomSchema extends PothosSchema { take: args.take ?? undefined, orderBy: args.orderBy ?? undefined, where: args.filter ?? undefined, - }) + }); }, }), - })) + // chatUsers: t.prismaField({ + // type: [this.chatUser()], + // args: { + // chatRoomId: t.arg({ + // type: "ID", + // description: "The ID of the chat room.", + // }), + // }, + // description: "Retrieve a list of chat users.", + // args: this.builder.generator.findManyArgs("ChatUser"), + // resolve: async (query, _root, args, ctx, _info) => { + // if (ctx.isSubscription) { + // throw new Error("Not allowed"); + // } + // if (!ctx.user) { + // throw new Error("Unauthorized"); + // } + // // TODO: get chat users for the chat room + // return []; + // }, + // }), + })); } } diff --git a/src/CollaborationSession/collaborationsession.schema.ts b/src/CollaborationSession/collaborationsession.schema.ts index 7016664..16d3fb7 100644 --- a/src/CollaborationSession/collaborationsession.schema.ts +++ b/src/CollaborationSession/collaborationsession.schema.ts @@ -73,10 +73,7 @@ export class CollaborationSessionSchema extends PothosSchema { }, description: 'Retrieve a single collaboration session by its unique identifier.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } const scheduleDate = await this.prisma.scheduleDate.findUnique({ @@ -94,9 +91,9 @@ export class CollaborationSessionSchema extends PothosSchema { }, }) /* ---------- use case 1 : customer get collaboration session by id --------- */ - if (ctx.http.me?.role === Role.CUSTOMER && collaborationSession) { + if (ctx.me?.role === Role.CUSTOMER && collaborationSession) { // check if user is participant - if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) { + if (!collaborationSession.collaboratorsIds.includes(ctx.me.id)) { throw new Error('User not allowed') } // update schedule date status @@ -111,14 +108,14 @@ export class CollaborationSessionSchema extends PothosSchema { return collaborationSession } /* ---------- use case 2 : center mentor get collaboration session by schedule date id --------- */ - if (ctx.http.me.role !== Role.CENTER_MENTOR && ctx.http.me.role !== Role.CENTER_OWNER) { + if (ctx.me.role !== Role.CENTER_MENTOR && ctx.me.role !== Role.CENTER_OWNER) { if (!collaborationSession) { throw new Error('Mentor does not created collaboration session yet') } throw new Error('User not allowed') } // check if user is participant - if (!scheduleDate.participantIds.includes(ctx.http.me.id)) { + if (!scheduleDate.participantIds.includes(ctx.me.id)) { throw new Error('User not allowed') } // check if order is exist in schedule date @@ -218,16 +215,13 @@ export class CollaborationSessionSchema extends PothosSchema { liveKitToken: t.field({ type: 'String', resolve: async (_, _args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http?.me?.id) { + if (!ctx.me?.id) { throw new Error('Unauthorized') } // check if participantId is in meetingRoomCollaborators const meetingRoomCollaborator = await this.prisma.meetingRoomCollaborator.findFirst({ where: { - userId: ctx.http.me.id, + userId: ctx.me.id, }, }) if (!meetingRoomCollaborator) { @@ -241,7 +235,7 @@ export class CollaborationSessionSchema extends PothosSchema { if (!meetingRoom) { throw new Error('Meeting room not found') } - const token = await this.liveKitService.createToken(ctx.http.me, meetingRoom.id) + const token = await this.liveKitService.createToken(ctx.me, meetingRoom.id) return token }, }), @@ -263,10 +257,7 @@ export class CollaborationSessionSchema extends PothosSchema { }, description: 'Update the active document ID for a collaboration session.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } // check permission @@ -281,7 +272,7 @@ export class CollaborationSessionSchema extends PothosSchema { if (!collaborationSession) { throw new Error('Collaboration session not found') } - if (!collaborationSession.scheduleDate.participantIds.includes(ctx.http.me.id)) { + if (!collaborationSession.scheduleDate.participantIds.includes(ctx.me.id)) { throw new Error('User not allowed') } const updatedCollaborationSession = await this.prisma.collaborationSession.update({ @@ -292,7 +283,7 @@ export class CollaborationSessionSchema extends PothosSchema { activeDocumentId: args.activeDocumentId, }, }) - ctx.http.pubSub.publish(`collaborationSessionUpdated:${collaborationSession.id}`, updatedCollaborationSession) + ctx.pubSub.publish(`collaborationSessionUpdated:${collaborationSession.id}`, updatedCollaborationSession) Logger.log(`Collaboration session updated: ${updatedCollaborationSession.id}`, 'updateActiveDocumentId') return updatedCollaborationSession }, @@ -310,10 +301,7 @@ export class CollaborationSessionSchema extends PothosSchema { }), }, subscribe: async (_parent, args, ctx) => { - if (!ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.websocket.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } const collaborationSession = await this.prisma.collaborationSession.findUnique({ @@ -324,7 +312,7 @@ export class CollaborationSessionSchema extends PothosSchema { if (!collaborationSession) { throw new Error('Collaboration session not found') } - return ctx.websocket.pubSub.asyncIterator([ + return ctx.pubSub.asyncIterator([ `collaborationSessionUpdated:${collaborationSession.id}`, ]) as unknown as AsyncIterable }, diff --git a/src/Document/document.schema.ts b/src/Document/document.schema.ts index f7a1e65..552b5a2 100644 --- a/src/Document/document.schema.ts +++ b/src/Document/document.schema.ts @@ -206,10 +206,7 @@ export class DocumentSchema extends PothosSchema { type: [this.document()], args: this.builder.generator.findManyArgs("Document"), resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - if (!ctx.http?.me?.id) { + if (!ctx.me?.id) { throw new Error("User not found"); } return await this.prisma.document.findMany({ @@ -217,8 +214,8 @@ export class DocumentSchema extends PothosSchema { orderBy: args.orderBy ?? undefined, where: { OR: [ - { ownerId: ctx.http.me.id }, - { collaborators: { some: { userId: ctx.http.me.id } } }, + { ownerId: ctx.me.id }, + { collaborators: { some: { userId: ctx.me.id } } }, ], }, }); @@ -252,10 +249,7 @@ export class DocumentSchema extends PothosSchema { type: this.document(), args: {}, resolve: async (query, _args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - const userId = ctx.http?.me?.id; + const userId = ctx.me?.id; if (!userId) { throw new Error("User not found"); } @@ -271,33 +265,6 @@ export class DocumentSchema extends PothosSchema { }, }), - testCheckGrammar: t.field({ - type: "Boolean", - args: { - documentId: t.arg({ type: "String", required: true }), - pageId: t.arg({ type: "Int", required: true }), - promptType: t.arg({ - type: this.builder.enumType("PromptType", { - values: [ - "CHECK_GRAMMAR", - "REWRITE_TEXT", - "SUMMARIZE", - "TRANSLATE", - "EXPAND_CONTENT", - ] as const, - }), - required: true, - }), - }, - resolve: async (_query, args, _ctx: SchemaContext) => { - await this.documentService.checkGrammarForPage( - args.documentId, - args.pageId, - args.promptType as PromptType - ); - return true; - }, - }), // exportDocument: t.field({ // type: this.DocumentExportObject(), @@ -344,10 +311,7 @@ export class DocumentSchema extends PothosSchema { pageIndex: t.arg({ type: "Int", required: true }), }, resolve: async (_, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - if (!ctx.http?.me?.id) { + if (!ctx.me?.id) { throw new Error("User not found"); } if (!args.documentId) { @@ -371,7 +335,7 @@ export class DocumentSchema extends PothosSchema { pageIndex: args.pageIndex, delta, totalPage, - senderId: ctx.http?.me?.id, + senderId: ctx.me?.id, eventType: DocumentEvent.CLIENT_REQUEST_SYNC, }; }, @@ -398,10 +362,7 @@ export class DocumentSchema extends PothosSchema { }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - const userId = ctx.http?.me?.id; + const userId = ctx.me?.id; if (!userId) { throw new Error("Unauthorized"); } @@ -430,13 +391,10 @@ export class DocumentSchema extends PothosSchema { }), }, resolve: async (_, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } const { - http: { pubSub }, + pubSub, } = ctx; - const senderId = ctx.http?.me?.id; + const senderId = ctx.me?.id; if (!senderId) { throw new Error("User not found"); } @@ -466,10 +424,7 @@ export class DocumentSchema extends PothosSchema { data: t.arg({ type: this.documentDeltaInput(), required: true }), }, resolve: async (_, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - const senderId = ctx.http?.me?.id; + const senderId = ctx.me?.id; if (!args.data.documentId) { throw new Error("Document id not found"); } @@ -522,10 +477,7 @@ export class DocumentSchema extends PothosSchema { }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } - if (!ctx.http?.me?.id) { + if (!ctx.me?.id) { throw new Error("Unauthorized"); } // check if user is owner or collaborator @@ -541,9 +493,9 @@ export class DocumentSchema extends PothosSchema { if ( !document.isPublic && !document.collaborators.some( - (c) => c.userId === ctx.http?.me?.id && c.writable + (c) => c.userId === ctx.me?.id && c.writable ) && - document.ownerId !== ctx.http?.me?.id + document.ownerId !== ctx.me?.id ) { throw new Error("User is not owner or collaborator of document"); } @@ -563,9 +515,6 @@ export class DocumentSchema extends PothosSchema { writable: t.arg({ type: "Boolean", required: true }), }, resolve: async (_, __, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } // check if ctx user is owner of document const document = await this.prisma.document.findUnique({ where: { id: args.documentId }, @@ -573,7 +522,7 @@ export class DocumentSchema extends PothosSchema { if (!document) { throw new Error("Document not found"); } - if (document.ownerId !== ctx.http?.me?.id) { + if (document.ownerId !== ctx.me?.id) { throw new Error("User is not owner of document"); } return await this.prisma.documentCollaborator.create({ @@ -593,9 +542,6 @@ export class DocumentSchema extends PothosSchema { userId: t.arg({ type: "String", required: true }), }, resolve: async (_, __, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } // check if ctx user is owner of document const document = await this.prisma.document.findUnique({ where: { id: args.documentId }, @@ -603,7 +549,7 @@ export class DocumentSchema extends PothosSchema { if (!document) { throw new Error("Document not found"); } - if (document.ownerId !== ctx.http?.me?.id) { + if (document.ownerId !== ctx.me?.id) { throw new Error("User is not owner of document"); } return await this.prisma.documentCollaborator.delete({ @@ -625,9 +571,6 @@ export class DocumentSchema extends PothosSchema { writable: t.arg({ type: "Boolean", required: true }), }, resolve: async (_, __, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } // check if ctx user is owner of document const document = await this.prisma.document.findUnique({ where: { id: args.documentId }, @@ -635,7 +578,7 @@ export class DocumentSchema extends PothosSchema { if (!document) { throw new Error("Document not found"); } - if (document.ownerId !== ctx.http?.me?.id) { + if (document.ownerId !== ctx.me?.id) { throw new Error("User is not owner of document"); } return await this.prisma.documentCollaborator.update({ @@ -656,9 +599,6 @@ export class DocumentSchema extends PothosSchema { imageId: t.arg({ type: "String", required: true }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } const document = await this.prisma.document.findUnique({ where: { id: args.documentId }, include: { @@ -669,9 +609,9 @@ export class DocumentSchema extends PothosSchema { throw new Error("Document not found"); } if ( - document.ownerId !== ctx.http?.me?.id && + document.ownerId !== ctx.me?.id && !document.collaborators.some( - (c) => c.userId === ctx.http?.me?.id && (c.writable || c.readable) + (c) => c.userId === ctx.me?.id && (c.writable || c.readable) ) ) { throw new Error("User is not owner or collaborator of document"); @@ -702,9 +642,6 @@ export class DocumentSchema extends PothosSchema { }), }, subscribe: async (_, args, ctx: SchemaContext) => { - if (!ctx.isSubscription) { - throw new Error("Not allowed"); - } const documentId = args.documentId; // check user permission const document = await this.prisma.document.findUnique({ @@ -718,17 +655,17 @@ export class DocumentSchema extends PothosSchema { } if (!document.isPublic) { if ( - document.ownerId !== ctx.websocket?.me?.id && + document.ownerId !== ctx.me?.id && !document.collaborators.some( (c) => - c.userId === ctx.websocket?.me?.id && + c.userId === ctx.me?.id && (c.writable || c.readable) ) ) { throw new Error("User is not owner or collaborator of document"); } } - return ctx.websocket.pubSub.asyncIterator([ + return ctx.pubSub.asyncIterator([ `${DocumentEvent.CHANGED}.${documentId}`, `${DocumentEvent.DELETED}.${documentId}`, `${DocumentEvent.SAVED}.${documentId}`, @@ -739,11 +676,7 @@ export class DocumentSchema extends PothosSchema { `${DocumentEvent.CURSOR_MOVED}.${documentId}`, ]) as unknown as AsyncIterable; }, - resolve: async (payload: DocumentDelta, _args, ctx: SchemaContext) => { - if (!ctx.isSubscription) { - throw new Error("Not allowed"); - } - + resolve: async (payload: DocumentDelta, _args, _ctx: SchemaContext) => { // If there's an explicit sync request, pass it through immediately if (payload.requestSync) { return payload; @@ -797,9 +730,6 @@ export class DocumentSchema extends PothosSchema { pageIndex: number, ctx: SchemaContext ): Promise { - if (!ctx.isSubscription) { - throw new Error("Not allowed"); - } try { const syncKey = `document:sync:${documentId}:${pageIndex}`; const currentTime = DateTimeUtils.now().toMillis().toString(); @@ -823,7 +753,7 @@ export class DocumentSchema extends PothosSchema { } // Optionally publish AI suggestion if needed - ctx.websocket.pubSub.publish( + ctx.pubSub.publish( `${DocumentEvent.AI_SUGGESTION}.${documentId}`, { documentId, diff --git a/src/Graphql/graphql.builder.ts b/src/Graphql/graphql.builder.ts index 553f736..4a4938a 100644 --- a/src/Graphql/graphql.builder.ts +++ b/src/Graphql/graphql.builder.ts @@ -1,93 +1,84 @@ -import { Injectable, Logger } from '@nestjs/common' -import SchemaBuilder from '@pothos/core' -import AuthzPlugin from '@pothos/plugin-authz' -import ErrorsPlugin from '@pothos/plugin-errors' -import PrismaPlugin, { PothosPrismaDatamodel, PrismaClient } from '@pothos/plugin-prisma' -import PrismaUtils from '@pothos/plugin-prisma-utils' -import RelayPlugin from '@pothos/plugin-relay' -import SimpleObjectPlugin from '@pothos/plugin-simple-objects' -import SmartSubscriptionPlugin, { subscribeOptionsFromIterator } from '@pothos/plugin-smart-subscriptions' -import ZodPlugin from '@pothos/plugin-zod' -import { User } from '@prisma/client' -import { JsonValue } from '@prisma/client/runtime/library' -import { Request, Response } from 'express' -import { Kind, ValueNode } from 'graphql' -import { RedisPubSub } from 'graphql-redis-subscriptions' -import { JSONObjectResolver } from 'graphql-scalars' +import { Injectable, Logger } from "@nestjs/common"; +import SchemaBuilder from "@pothos/core"; +import AuthzPlugin from "@pothos/plugin-authz"; +import ErrorsPlugin from "@pothos/plugin-errors"; +import PrismaPlugin, { + PothosPrismaDatamodel, + PrismaClient, +} from "@pothos/plugin-prisma"; +import PrismaUtils from "@pothos/plugin-prisma-utils"; +import RelayPlugin from "@pothos/plugin-relay"; +import SimpleObjectPlugin from "@pothos/plugin-simple-objects"; +import SmartSubscriptionPlugin, { + subscribeOptionsFromIterator, +} from "@pothos/plugin-smart-subscriptions"; +import ZodPlugin from "@pothos/plugin-zod"; +import { User } from "@prisma/client"; +import { JsonValue } from "@prisma/client/runtime/library"; +import { Request, Response } from "express"; +import { Kind, ValueNode } from "graphql"; +import { RedisPubSub } from "graphql-redis-subscriptions"; +import { JSONObjectResolver } from "graphql-scalars"; // @ts-expect-error -import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs' +import GraphQLUpload from "graphql-upload/GraphQLUpload.mjs"; // @ts-expect-error -import type { FileUpload } from 'graphql-upload/processRequest.mjs' -import { DateTime } from 'luxon' -import Delta from 'quill-delta' -import { DateTimeUtils } from '../common/utils/datetime.utils' -import type PrismaTypes from '../types/pothos.generated' -import { getDatamodel } from '../types/pothos.generated' -import { PrismaCrudGenerator } from './graphql.generator' - -export type SchemaContext = - | { - isSubscription: true - websocket: { - req: Request - pubSub: RedisPubSub - sessionId: string - me: User - generator: PrismaCrudGenerator - } - } - | { - isSubscription: false - http: { - req: Request - res: Response - me: User | null - pubSub: RedisPubSub - invalidateCache: () => Promise - generator: PrismaCrudGenerator - } - } +import type { FileUpload } from "graphql-upload/processRequest.mjs"; +import { DateTime } from "luxon"; +import Delta from "quill-delta"; +import { DateTimeUtils } from "../common/utils/datetime.utils"; +import type PrismaTypes from "../types/pothos.generated"; +import { getDatamodel } from "../types/pothos.generated"; +import { PrismaCrudGenerator } from "./graphql.generator"; +export type SchemaContext = { + req: Request; + pubSub: RedisPubSub; + sessionId: string; + me: User; + generator: PrismaCrudGenerator; + res: Response; + invalidateCache: () => Promise; +}; // extend prisma types to contain string type export interface SchemaBuilderOption { - Context: SchemaContext - PrismaTypes: PrismaTypes - DataModel: PothosPrismaDatamodel + Context: SchemaContext; + PrismaTypes: PrismaTypes; + DataModel: PothosPrismaDatamodel; Connection: { - totalCount: number | (() => number | Promise) - } + totalCount: number | (() => number | Promise); + }; // AuthZRule: keyof typeof rules; Scalars: { DateTime: { - Input: string | DateTime | Date - Output: string | DateTime | Date - } + Input: string | DateTime | Date; + Output: string | DateTime | Date; + }; Json: { - Input: JsonValue - Output: JsonValue - } + Input: JsonValue; + Output: JsonValue; + }; Upload: { - Input: FileUpload - Output: FileUpload - } + Input: FileUpload; + Output: FileUpload; + }; Int: { - Input: number - Output: number | bigint | string - } + Input: number; + Output: number | bigint | string; + }; Delta: { - Input: Delta - Output: Delta - } + Input: Delta; + Output: Delta; + }; JsonList: { - Input: JsonValue[] - Output: JsonValue[] - } - } + Input: JsonValue[]; + Output: JsonValue[]; + }; + }; } @Injectable() export class Builder extends SchemaBuilder { - public generator: PrismaCrudGenerator + public generator: PrismaCrudGenerator; constructor(private readonly prisma: PrismaClient) { super({ @@ -104,17 +95,15 @@ export class Builder extends SchemaBuilder { smartSubscriptions: { debounceDelay: 1000, ...subscribeOptionsFromIterator((name, context) => { - return context.isSubscription - ? context.websocket.pubSub.asyncIterator(name) - : context.http.pubSub.asyncIterator(name) + return context.pubSub.asyncIterator(name); }), }, zod: { // optionally customize how errors are formatted validationError: (zodError, _args, _context, _info) => { // the default behavior is to just throw the zod error directly - Logger.error(zodError.message, 'Zod Error') - return zodError + Logger.error(zodError.message, "Zod Error"); + return zodError; }, }, relay: {}, @@ -123,65 +112,70 @@ export class Builder extends SchemaBuilder { exposeDescriptions: true, filterConnectionTotalCount: true, onUnusedQuery: (info) => { - Logger.log(`Unused query: ${info.fieldName}`, 'GraphQL') + Logger.log(`Unused query: ${info.fieldName}`, "GraphQL"); }, dmmf: getDatamodel(), }, errors: { defaultTypes: [], }, - }) - this.generator = new PrismaCrudGenerator(this) - this.scalarType('DateTime', { + }); + this.generator = new PrismaCrudGenerator(this); + this.scalarType("DateTime", { serialize: (value) => { - if (typeof value === 'string') { - return value + if (typeof value === "string") { + return value; } - if (typeof value === 'object' && value !== null && 'toISO' in value) { - return value + if (typeof value === "object" && value !== null && "toISO" in value) { + return value; } if (value instanceof Date) { - return DateTimeUtils.toIsoString(DateTimeUtils.fromDate(value)) + return DateTimeUtils.toIsoString(DateTimeUtils.fromDate(value)); } - throw new Error('Invalid DateTime') + throw new Error("Invalid DateTime"); }, parseValue: (value) => { - if (typeof value === 'string') { - return DateTimeUtils.fromIsoString(value) + if (typeof value === "string") { + return DateTimeUtils.fromIsoString(value); } - throw new Error('Invalid DateTime') + throw new Error("Invalid DateTime"); }, parseLiteral: (ast) => { if (ast.kind === Kind.STRING) { - return DateTimeUtils.fromIsoString(ast.value) + return DateTimeUtils.fromIsoString(ast.value); } - throw new Error('Invalid DateTime') + throw new Error("Invalid DateTime"); }, - }) - this.scalarType('Delta', { + }); + this.scalarType("Delta", { serialize: (value) => JSON.stringify(value), parseValue: (value: unknown) => JSON.parse(value as string) as Delta, parseLiteral: (ast: ValueNode) => ast as unknown as Delta, - }) + }); - this.scalarType('JsonList', { + this.scalarType("JsonList", { serialize: (value) => JSON.stringify(value), - parseValue: (value: unknown) => JSON.parse(value as string) as JsonValue[], + parseValue: (value: unknown) => + JSON.parse(value as string) as JsonValue[], parseLiteral: (ast: ValueNode) => ast as unknown as JsonValue[], - }) + }); - this.addScalarType('Json', JSONObjectResolver) - this.addScalarType('Upload', GraphQLUpload) + this.addScalarType("Json", JSONObjectResolver); + this.addScalarType("Upload", GraphQLUpload); - this.queryType({}) - this.mutationType({}) - this.subscriptionType({}) - this.globalConnectionField('totalCount', (t) => + this.queryType({}); + this.mutationType({}); + this.subscriptionType({}); + this.globalConnectionField("totalCount", (t) => t.int({ nullable: true, - resolve: (parent) => (typeof parent.totalCount === 'function' ? parent.totalCount() : parent.totalCount), - }), - ) + resolve: (parent) => + typeof parent.totalCount === "function" + ? parent.totalCount() + : parent.totalCount, + }) + ); } } -export type BuilderTypes = PothosSchemaTypes.ExtendDefaultTypes +export type BuilderTypes = + PothosSchemaTypes.ExtendDefaultTypes; diff --git a/src/Graphql/graphql.module.ts b/src/Graphql/graphql.module.ts index 400a50e..4690ddc 100644 --- a/src/Graphql/graphql.module.ts +++ b/src/Graphql/graphql.module.ts @@ -1,53 +1,53 @@ -import { Global, Logger, Module } from '@nestjs/common' +import { Global, Logger, Module } from "@nestjs/common"; -import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default' -import { ApolloDriverConfig } from '@nestjs/apollo' -import { ConfigModule } from '@nestjs/config' -import { GraphQLModule } from '@nestjs/graphql' -import { initContextCache } from '@pothos/core' -import { PothosModule } from '@smatch-corp/nestjs-pothos' -import { PothosApolloDriver } from '@smatch-corp/nestjs-pothos-apollo-driver' -import { Request } from 'express' -import { RedisPubSub } from 'graphql-redis-subscriptions' -import { CloseCode, Context, WebSocket } from 'graphql-ws' -import { PersonalMilestoneModule } from 'src/PersonalMilestone/personalmilestone.module' -import { AdminNoteModule } from '../AdminNote/adminnote.module' -import { AnalyticModule } from '../Analytic/analytic.module' -import { AppConfigModule } from '../AppConfig/appconfig.module' -import { CategoryModule } from '../Category/category.module' -import { CenterModule } from '../Center/center.module' -import { CenterMentorModule } from '../CenterMentor/centermentor.module' -import { ChatroomModule } from '../ChatRoom/chatroom.module' -import { CollaborationSessionModule } from '../CollaborationSession/collaborationsession.module' -import { DocumentModule } from '../Document/document.module' -import { ManagedServiceModule } from '../ManagedService/managedservice.module' -import { MeetingRoomModule } from '../MeetingRoom/meetingroom.module' -import { MessageModule } from '../Message/message.module' -import { OrderModule } from '../Order/order.module' -import { PaymentModule } from '../Payment/payment.module' -import { PrismaModule } from '../Prisma/prisma.module' -import { PrismaService } from '../Prisma/prisma.service' -import { PubSubModule } from '../PubSub/pubsub.module' -import { PubSubService } from '../PubSub/pubsub.service' -import { QuizModule } from '../Quiz/quiz.module' -import { RedisModule } from '../Redis/redis.module' -import { RedisService } from '../Redis/redis.service' -import { RefundTicketModule } from '../RefundTicket/refundticket.module' -import { ResumeModule } from '../Resume/resume.module' -import { ScheduleModule } from '../Schedule/schedule.module' -import { ServiceModule } from '../Service/service.module' -import { ServiceAndCategoryModule } from '../ServiceAndCategory/serviceandcategory.module' -import { ServiceFeedbackModule } from '../ServiceFeedback/servicefeedback.module' -import { UploadedFileModule } from '../UploadedFile/uploadedfile.module' -import { UserModule } from '../User/user.module' -import { WorkshopModule } from '../Workshop/workshop.module' -import { WorkshopMeetingRoomModule } from '../WorkshopMeetingRoom/workshopmeetingroom.module' -import { WorkshopOrganizationModule } from '../WorkshopOrganization/workshoporganization.module' -import { WorkshopSubscriptionModule } from '../WorkshopSubscription/workshopsubscription.module' -import { CommonModule } from '../common/common.module' -import { Builder } from './graphql.builder' -import { PrismaCrudGenerator } from './graphql.generator' -import { GraphqlService } from './graphql.service' +import { ApolloServerPluginLandingPageLocalDefault } from "@apollo/server/plugin/landingPage/default"; +import { ApolloDriverConfig } from "@nestjs/apollo"; +import { ConfigModule } from "@nestjs/config"; +import { GraphQLModule } from "@nestjs/graphql"; +import { initContextCache } from "@pothos/core"; +import { PothosModule } from "@smatch-corp/nestjs-pothos"; +import { PothosApolloDriver } from "@smatch-corp/nestjs-pothos-apollo-driver"; +import { Request } from "express"; +import { RedisPubSub } from "graphql-redis-subscriptions"; +import { CloseCode, Context, WebSocket } from "graphql-ws"; +import { PersonalMilestoneModule } from "src/PersonalMilestone/personalmilestone.module"; +import { AdminNoteModule } from "../AdminNote/adminnote.module"; +import { AnalyticModule } from "../Analytic/analytic.module"; +import { AppConfigModule } from "../AppConfig/appconfig.module"; +import { CategoryModule } from "../Category/category.module"; +import { CenterModule } from "../Center/center.module"; +import { CenterMentorModule } from "../CenterMentor/centermentor.module"; +import { ChatroomModule } from "../ChatRoom/chatroom.module"; +import { CollaborationSessionModule } from "../CollaborationSession/collaborationsession.module"; +import { DocumentModule } from "../Document/document.module"; +import { ManagedServiceModule } from "../ManagedService/managedservice.module"; +import { MeetingRoomModule } from "../MeetingRoom/meetingroom.module"; +import { MessageModule } from "../Message/message.module"; +import { OrderModule } from "../Order/order.module"; +import { PaymentModule } from "../Payment/payment.module"; +import { PrismaModule } from "../Prisma/prisma.module"; +import { PrismaService } from "../Prisma/prisma.service"; +import { PubSubModule } from "../PubSub/pubsub.module"; +import { PubSubService } from "../PubSub/pubsub.service"; +import { QuizModule } from "../Quiz/quiz.module"; +import { RedisModule } from "../Redis/redis.module"; +import { RedisService } from "../Redis/redis.service"; +import { RefundTicketModule } from "../RefundTicket/refundticket.module"; +import { ResumeModule } from "../Resume/resume.module"; +import { ScheduleModule } from "../Schedule/schedule.module"; +import { ServiceModule } from "../Service/service.module"; +import { ServiceAndCategoryModule } from "../ServiceAndCategory/serviceandcategory.module"; +import { ServiceFeedbackModule } from "../ServiceFeedback/servicefeedback.module"; +import { UploadedFileModule } from "../UploadedFile/uploadedfile.module"; +import { UserModule } from "../User/user.module"; +import { WorkshopModule } from "../Workshop/workshop.module"; +import { WorkshopMeetingRoomModule } from "../WorkshopMeetingRoom/workshopmeetingroom.module"; +import { WorkshopOrganizationModule } from "../WorkshopOrganization/workshoporganization.module"; +import { WorkshopSubscriptionModule } from "../WorkshopSubscription/workshopsubscription.module"; +import { CommonModule } from "../common/common.module"; +import { Builder } from "./graphql.builder"; +import { PrismaCrudGenerator } from "./graphql.generator"; +import { GraphqlService } from "./graphql.service"; @Global() @Module({ imports: [ @@ -94,36 +94,48 @@ import { GraphqlService } from './graphql.service' }), GraphQLModule.forRootAsync({ driver: PothosApolloDriver, - inject: [GraphqlService, 'PUB_SUB_REDIS'], - useFactory: async (graphqlService: GraphqlService, pubsub: RedisPubSub) => ({ - path: process.env.API_PATH + '/graphql', + inject: [GraphqlService, "PUB_SUB_REDIS"], + useFactory: async ( + graphqlService: GraphqlService, + pubsub: RedisPubSub + ) => ({ + path: process.env.API_PATH + "/graphql", debug: true, playground: false, allowBatchedHttpRequests: true, includeStacktraceInErrorResponses: false, - introspection: process.env.NODE_ENV === 'development' || false, + introspection: process.env.NODE_ENV === "development" || false, logger: { - debug: (...args) => Logger.debug(...args, 'GraphqlModule'), - info: (...args) => Logger.log(...args, 'GraphqlModule'), - warn: (...args) => Logger.warn(...args, 'GraphqlModule'), - error: (...args) => Logger.error(...args, 'GraphqlModule'), + debug: (...args) => Logger.debug(...args, "GraphqlModule"), + info: (...args) => Logger.log(...args, "GraphqlModule"), + warn: (...args) => Logger.warn(...args, "GraphqlModule"), + error: (...args) => Logger.error(...args, "GraphqlModule"), }, plugins: [ApolloServerPluginLandingPageLocalDefault()], installSubscriptionHandlers: true, subscriptions: { - 'graphql-ws': { + "graphql-ws": { onSubscribe(ctx, message) { - console.log('onSubscribe', ctx, message) + console.log("onSubscribe", ctx, message); }, onConnect: (ctx: Context>) => { if (!ctx.connectionParams) { - Logger.log('No connectionParams provided', 'GraphqlModule') + Logger.log("No connectionParams provided", "GraphqlModule"); + } + if (!ctx.connectionParams?.["x-session-id"]) { + Logger.log("No sessionId provided", "GraphqlModule"); } if (!ctx.extra) { - Logger.log('No extra provided', 'GraphqlModule') + Logger.log("No extra provided", "GraphqlModule"); } - // @ts-expect-error: Request is not typed - ctx.extra.request.headers['x-session-id'] = ctx.connectionParams['x-session-id'] + const sessionId: string = ctx.connectionParams?.[ + "x-session-id" + ] as string; + if (!sessionId) { + Logger.log("No sessionId provided", "GraphqlModule"); + } + // @ts-expect-error: extra is not typed + ctx.extra.request.headers["x-session-id"] = sessionId; }, }, }, @@ -132,37 +144,34 @@ import { GraphqlService } from './graphql.service' subscriptions, extra, }: { - req?: Request - subscriptions?: Record - extra?: Record + req?: Request; + subscriptions?: Record; + extra?: Record; }) => { - initContextCache() + initContextCache(); if (subscriptions) { // @ts-expect-error: TODO - if (!extra?.request?.headers['x-session-id']) { - throw new Error('No sessionId provided') + if (!extra?.request?.headers["x-session-id"]) { + throw new Error("No sessionId provided"); } return { - isSubscription: true, - websocket: { - req: extra?.request, - pubSub: pubsub, - me: await graphqlService.acquireContextFromSessionId( - // @ts-expect-error: TODO - extra.request.headers['x-session-id'], - ), - }, - } + req: extra?.request, + pubSub: pubsub, + me: await graphqlService.acquireContextFromSessionId( + // @ts-expect-error: TODO + extra.request.headers["x-session-id"] + ), + }; } return { - isSubscription: false, - http: { - req, - me: req ? await graphqlService.acquireContext(req) : null, - pubSub: pubsub, - invalidateCache: () => graphqlService.invalidateCache(req?.headers['x-session-id'] as string), - }, - } + req, + me: req ? await graphqlService.acquireContext(req) : null, + pubSub: pubsub, + invalidateCache: () => + graphqlService.invalidateCache( + req?.headers["x-session-id"] as string + ), + }; }, }), }), @@ -171,8 +180,9 @@ import { GraphqlService } from './graphql.service' RedisService, { provide: GraphqlService, - useFactory: (prisma: PrismaService, redis: RedisService) => new GraphqlService(prisma, redis), - inject: [PrismaService, 'REDIS_CLIENT'], + useFactory: (prisma: PrismaService, redis: RedisService) => + new GraphqlService(prisma, redis), + inject: [PrismaService, "REDIS_CLIENT"], }, { provide: Builder, diff --git a/src/MeetingRoom/meetingroom.schema.ts b/src/MeetingRoom/meetingroom.schema.ts index 95e1fb1..7aec149 100644 --- a/src/MeetingRoom/meetingroom.schema.ts +++ b/src/MeetingRoom/meetingroom.schema.ts @@ -75,10 +75,7 @@ export class MeetingRoomSchema extends PothosSchema { required: true, }), }, - resolve: async (_query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } + resolve: async (_query, _parent, args, _ctx: SchemaContext) => { const collaborationSession = await this.prisma.collaborationSession.findUnique({ where: { scheduleDateId: args.scheduleDateId, @@ -112,10 +109,7 @@ export class MeetingRoomSchema extends PothosSchema { }), }, resolve: async (_, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } const meetingRoom = await this.prisma.meetingRoom.findUnique({ @@ -131,11 +125,11 @@ export class MeetingRoomSchema extends PothosSchema { if (!collaborationSession) { throw new Error('Collaboration session not found') } - if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) { + if (!collaborationSession.collaboratorsIds.includes(ctx.me.id)) { throw new Error('User is not collaborator') } // create new token - const token = await this.livekitService.createToken(ctx.http.me, meetingRoom.id) + const token = await this.livekitService.createToken(ctx.me, meetingRoom.id) return { id: meetingRoom.id, token, @@ -151,13 +145,10 @@ export class MeetingRoomSchema extends PothosSchema { }), }, resolve: async (_, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - const token = await this.livekitService.createToken(ctx.http.me, args.scheduleId) + const token = await this.livekitService.createToken(ctx.me, args.scheduleId) return { id: args.scheduleId, token, @@ -181,10 +172,7 @@ export class MeetingRoomSchema extends PothosSchema { }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.meetingRoom.create({ @@ -207,10 +195,7 @@ export class MeetingRoomSchema extends PothosSchema { }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.meetingRoom.update({ diff --git a/src/Message/message.schema.ts b/src/Message/message.schema.ts index 27b998b..f2959ea 100644 --- a/src/Message/message.schema.ts +++ b/src/Message/message.schema.ts @@ -20,7 +20,7 @@ import { DateTimeUtils } from "../common/utils/datetime.utils"; export class MessageSchema extends PothosSchema { constructor( @Inject(SchemaBuilderToken) private readonly builder: Builder, - private readonly prisma: PrismaService + private readonly prisma: PrismaService, ) { super(); } @@ -92,9 +92,6 @@ export class MessageSchema extends PothosSchema { "Retrieve a list of messages with optional filtering, ordering, and pagination.", args: this.builder.generator.findManyArgs("Message"), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } if (args.filter?.context && typeof args.filter.context === "object") { // if args.context is NOTIFICATION or SYSTEM, filter by recipientId if ( @@ -105,7 +102,7 @@ export class MessageSchema extends PothosSchema { ?.toString() .includes(MessageContextType.SYSTEM) ) { - args.filter.recipientId = ctx.http.me?.id; + args.filter.recipientId = ctx.me?.id; } } return await this.prisma.message.findMany({ @@ -151,14 +148,11 @@ export class MessageSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error("Not allowed"); - } const messageContext = MessageContextType.CHAT; // get the sender from the context and add it to the input args.input.sender = { connect: { - id: ctx.http.me?.id, + id: ctx.me?.id, }, }; if (!args.input.sender) { @@ -206,13 +200,13 @@ export class MessageSchema extends PothosSchema { }); return message; }); - ctx.http.pubSub.publish( + ctx.pubSub.publish( `${PubSubEvent.MESSAGE_SENT}.${message.chatRoomId}`, message ); // publish to new message subscribers userIds.forEach((userId: string) => { - ctx.http.pubSub.publish( + ctx.pubSub.publish( `${PubSubEvent.NEW_MESSAGE}.${userId}`, message ); @@ -233,10 +227,7 @@ export class MessageSchema extends PothosSchema { }), }, subscribe: (_, args, ctx: SchemaContext) => { - if (!ctx.isSubscription) { - throw new Error("Not allowed"); - } - return ctx.websocket.pubSub.asyncIterator([ + return ctx.pubSub.asyncIterator([ `${PubSubEvent.MESSAGE_SENT}.${args.chatRoomId}`, ]) as unknown as AsyncIterable; }, diff --git a/src/Order/order.schema.ts b/src/Order/order.schema.ts index 54ca1c7..a690e8b 100644 --- a/src/Order/order.schema.ts +++ b/src/Order/order.schema.ts @@ -154,10 +154,7 @@ export class OrderSchema extends PothosSchema { description: 'Retrieve a list of completed orders', args: this.builder.generator.findManyArgs('Order'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Orders cannot be retrieved in subscription context') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // return orders where user is the one who made the order and status is PAID and schedule.dates is in the past @@ -167,7 +164,7 @@ export class OrderSchema extends PothosSchema { AND: [ ...(args.filter ? [args.filter] : []), { - userId: ctx.http.me.id, + userId: ctx.me.id, status: OrderStatus.PAID, schedule: { OR: [ @@ -202,14 +199,11 @@ export class OrderSchema extends PothosSchema { description: 'Retrieve a list of completed orders for moderator', args: this.builder.generator.findManyArgs('Order'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Orders cannot be retrieved in subscription context') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // only for role moderator - if (ctx.http.me.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Unauthorized') } // return completed order list where schedule status is COMPLETED @@ -239,13 +233,10 @@ export class OrderSchema extends PothosSchema { }, description: 'Retrieve a list of completed orders details', resolve: async (_query, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Orders cannot be retrieved in subscription context') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Unauthorized') } // get order details @@ -367,10 +358,7 @@ export class OrderSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } if (!args.data.service.connect?.id) { @@ -388,7 +376,7 @@ export class OrderSchema extends PothosSchema { where: { AND: [ { - customerId: ctx.http.me?.id, + customerId: ctx.me?.id, }, { managedService: { @@ -419,7 +407,7 @@ export class OrderSchema extends PothosSchema { data: { status: OrderStatus.PENDING, total: service.price, - userId: ctx.http.me?.id ?? '', + userId: ctx.me?.id ?? '', serviceId: service.id, scheduleId: args.data.schedule.connect?.id ?? '', commission: service.commission ?? 0.0, @@ -460,8 +448,8 @@ export class OrderSchema extends PothosSchema { orderCode: paymentCode, amount: service.price, description: _name, - buyerName: ctx.http.me?.name ?? '', - buyerEmail: ctx.http.me?.email ?? '', + buyerName: ctx.me?.name ?? '', + buyerEmail: ctx.me?.email ?? '', returnUrl: `${process.env.PAYOS_RETURN_URL}`.replace('', service.id), cancelUrl: `${process.env.PAYOS_RETURN_URL}`.replace('', service.id), expiredAt: DateTimeUtils.now().plus({ minutes: 15 }).toUnixInteger(), @@ -519,13 +507,10 @@ export class OrderSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } - if (ctx.http.me.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Unauthorized') } return await this.prisma.order.update({ diff --git a/src/PersonalMilestone/personalmilestone.schema.ts b/src/PersonalMilestone/personalmilestone.schema.ts index 90d1f11..2a19068 100644 --- a/src/PersonalMilestone/personalmilestone.schema.ts +++ b/src/PersonalMilestone/personalmilestone.schema.ts @@ -65,10 +65,7 @@ export class PersonalMilestoneSchema extends PothosSchema { args: this.builder.generator.findUniqueArgs('PersonalMilestone'), description: 'Retrieve a single personal milestone by its unique identifier.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } return this.prisma.personalMilestone.findUnique({ @@ -81,10 +78,7 @@ export class PersonalMilestoneSchema extends PothosSchema { args: this.builder.generator.findManyArgs('PersonalMilestone'), description: 'Retrieve multiple personal milestones.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } return this.prisma.personalMilestone.findMany({ @@ -119,13 +113,10 @@ export class PersonalMilestoneSchema extends PothosSchema { }, description: 'Create multiple personal milestones.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } - const userId = ctx.http.me.id + const userId = ctx.me.id const result = await this.prisma.personalMilestone.createManyAndReturn({ data: args.data.map((data) => ({ ...data, @@ -158,13 +149,10 @@ export class PersonalMilestoneSchema extends PothosSchema { }, description: 'Update a personal milestone.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } - const userId = ctx.http.me.id + const userId = ctx.me.id return this.prisma.personalMilestone.update({ where: { ...args.where, @@ -185,10 +173,7 @@ export class PersonalMilestoneSchema extends PothosSchema { }, description: 'Delete a personal milestone.', resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Cannot get your info') } // check if the user is mentor of the schedule where the personal milestone belongs to @@ -202,7 +187,7 @@ export class PersonalMilestoneSchema extends PothosSchema { const managedService = await this.prisma.managedService.findUnique({ where: { id: schedule.managedServiceId }, }) - if (managedService?.mentorId !== ctx.http.me.id) { + if (managedService?.mentorId !== ctx.me.id) { throw new Error('Unauthorized') } } diff --git a/src/Quiz/quiz.schema.ts b/src/Quiz/quiz.schema.ts index ab67a54..7325e57 100644 --- a/src/Quiz/quiz.schema.ts +++ b/src/Quiz/quiz.schema.ts @@ -145,10 +145,7 @@ export class QuizSchema extends PothosSchema { type: this.quiz(), args: this.builder.generator.findUniqueArgs('Quiz'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.quiz.findUnique({ ...query, where: { id: args.where.id } }) @@ -167,17 +164,14 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // use case 1: customer - if (ctx.http.me.role === Role.CUSTOMER) { + if (ctx.me.role === Role.CUSTOMER) { // using pseudo random to get amount of quizzes based on userid as seed const random = getRandomWithSeed( - parseInt(crypto.createHash('sha256').update(ctx.http.me.id).digest('hex'), 16), + parseInt(crypto.createHash('sha256').update(ctx.me.id).digest('hex'), 16), ) if (!args.scheduleId) { throw new Error('Schedule ID is required') @@ -192,7 +186,7 @@ export class QuizSchema extends PothosSchema { if (!schedule) { throw new Error('Schedule not found') } - if (schedule.customerId !== ctx.http.me.id) { + if (schedule.customerId !== ctx.me.id) { throw new Error('Unauthorized') } // get centerMentorId from schedule @@ -211,7 +205,7 @@ export class QuizSchema extends PothosSchema { // check if user has already taken the quiz const quizAttempt = await this.prisma.quizAttempt.findFirst({ where: { - userId: ctx.http.me.id, + userId: ctx.me.id, quizId: quizzes[0]?.id, }, }) @@ -226,9 +220,9 @@ export class QuizSchema extends PothosSchema { } // use case 2: center mentor or center owner - if (ctx.http.me.role === Role.CENTER_MENTOR || ctx.http.me.role === Role.CENTER_OWNER) { + if (ctx.me.role === Role.CENTER_MENTOR || ctx.me.role === Role.CENTER_OWNER) { const centerMentor = await this.prisma.centerMentor.findUnique({ - where: { mentorId: ctx.http.me.id }, + where: { mentorId: ctx.me.id }, }) if (!centerMentor) { throw new Error('Center mentor not found') @@ -252,10 +246,7 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } if (!args.id) { @@ -272,10 +263,10 @@ export class QuizSchema extends PothosSchema { } // check if user is the owner of the quiz attempt if ( - result.userId !== ctx.http.me.id && - ctx.http.me.role !== Role.CENTER_OWNER && - ctx.http.me.role !== Role.CENTER_MENTOR && - ctx.http.me.role !== Role.CUSTOMER + result.userId !== ctx.me.id && + ctx.me.role !== Role.CENTER_OWNER && + ctx.me.role !== Role.CENTER_MENTOR && + ctx.me.role !== Role.CUSTOMER ) { throw new Error('Unauthorized') } @@ -299,16 +290,13 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // use case 1: center mentor or center owner - if (ctx.http.me.role === Role.CENTER_MENTOR || ctx.http.me.role === Role.CENTER_OWNER) { + if (ctx.me.role === Role.CENTER_MENTOR || ctx.me.role === Role.CENTER_OWNER) { const centerMentor = await this.prisma.centerMentor.findUnique({ - where: { mentorId: ctx.http.me.id }, + where: { mentorId: ctx.me.id }, }) if (!centerMentor) { throw new Error('Center mentor not found') @@ -331,11 +319,11 @@ export class QuizSchema extends PothosSchema { }) } // use case 2: customer - if (ctx.http.me.role === Role.CUSTOMER) { + if (ctx.me.role === Role.CUSTOMER) { return await this.prisma.quizAttempt.findMany({ ...query, where: { - userId: ctx.http.me.id, + userId: ctx.me.id, ...(args.quizId ? [{ quizId: args.quizId }] : []), }, orderBy: { @@ -356,10 +344,7 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } if (!args.data) { @@ -370,7 +355,7 @@ export class QuizSchema extends PothosSchema { } args.data.centerMentor = { connect: { - mentorId: ctx.http.me.id, + mentorId: ctx.me.id, }, } return await this.prisma.quiz.create({ @@ -394,10 +379,7 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.quiz.update({ @@ -422,10 +404,7 @@ export class QuizSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } if (!args.data) { @@ -450,7 +429,7 @@ export class QuizSchema extends PothosSchema { data: { ...args.data, quiz: { connect: { id: args.data.quiz.connect.id } }, - user: { connect: { id: ctx.http.me.id } }, + user: { connect: { id: ctx.me.id } }, }, }) // update schedule status to WAITING_INTERVIEW diff --git a/src/RefundTicket/refundticket.schema.ts b/src/RefundTicket/refundticket.schema.ts index def8309..ad8f22c 100644 --- a/src/RefundTicket/refundticket.schema.ts +++ b/src/RefundTicket/refundticket.schema.ts @@ -91,10 +91,10 @@ export class RefundTicketSchema extends PothosSchema { id: t.arg({ type: 'String', required: true }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') + if (!ctx.me) { + throw new Error('User not found') } - if (ctx.http.me?.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Only moderators can retrieve refund tickets') } return await this.prisma.refundTicket.findUnique({ ...query, where: { id: args.id } }) @@ -132,24 +132,21 @@ export class RefundTicketSchema extends PothosSchema { }), }, resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // Check if the user is a customer or a center mentor if ( - ctx.http.me?.role !== Role.CUSTOMER && - ctx.http.me?.role !== Role.CENTER_MENTOR && - ctx.http.me?.role !== Role.CENTER_OWNER + ctx.me?.role !== Role.CUSTOMER && + ctx.me?.role !== Role.CENTER_MENTOR && + ctx.me?.role !== Role.CENTER_OWNER ) { throw new Error('Only customers and center mentors can request refund') } // Check bank details for non-center mentors - if (ctx.http.me?.role !== Role.CENTER_MENTOR) { - if (!ctx.http.me?.bankBin || !ctx.http.me?.bankAccountNumber) { + if (ctx.me?.role !== Role.CENTER_MENTOR) { + if (!ctx.me?.bankBin || !ctx.me?.bankAccountNumber) { throw new Error('Bank bin and bank account number are required, please update your profile first') } } @@ -188,7 +185,7 @@ export class RefundTicketSchema extends PothosSchema { let refundAmount = 0 // Special handling for center mentors - full refund always allowed - if (ctx.http.me?.role === Role.CENTER_MENTOR) { + if (ctx.me?.role === Role.CENTER_MENTOR) { refundAmount = order.total } else { // Existing refund logic for customers @@ -204,12 +201,12 @@ export class RefundTicketSchema extends PothosSchema { } // Prepare bank details - let bankBin = ctx.http.me?.bankBin - let bankAccountNumber = ctx.http.me?.bankAccountNumber + let bankBin = ctx.me?.bankBin + let bankAccountNumber = ctx.me?.bankAccountNumber let bankName = '' // For center mentors, use a default or system bank account - if (ctx.http.me?.role === Role.CENTER_MENTOR) { + if (ctx.me?.role === Role.CENTER_MENTOR) { // You might want to replace this with a specific system bank account bankBin = 'SYSTEM_MENTOR_REFUND' bankAccountNumber = 'SYSTEM_MENTOR_ACCOUNT' @@ -234,7 +231,7 @@ export class RefundTicketSchema extends PothosSchema { bankBin: bankBin, bankAccountNumber: bankAccountNumber, bankName: bankName, - requesterId: ctx.http.me.id, + requesterId: ctx.me.id, }, }) // notify all Moderator @@ -244,15 +241,15 @@ export class RefundTicketSchema extends PothosSchema { for (const moderator of moderators) { const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me.id, recipientId: moderator.id, type: MessageType.TEXT, - content: `Có yêu cầu hoàn tiền mới từ ${ctx.http.me?.name}`, + content: `Có yêu cầu hoàn tiền mới từ ${ctx.me.name}`, sentAt: DateTimeUtils.nowAsJSDate(), context: MessageContextType.NOTIFICATION, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) } return refundTicket }, @@ -275,10 +272,10 @@ export class RefundTicketSchema extends PothosSchema { }), }, resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Subscription is not allowed') + if (!ctx.me) { + throw new Error('User not found') } - if (ctx.http.me?.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Only moderators can process refund tickets') } // if action is REJECT, reason is required @@ -291,7 +288,7 @@ export class RefundTicketSchema extends PothosSchema { data: { status: args.action === 'APPROVE' ? RefundTicketStatus.APPROVED : RefundTicketStatus.REJECTED, rejectedReason: args.action === 'REJECT' ? args.reason : undefined, - moderatorId: ctx.http.me.id, + moderatorId: ctx.me.id, }, include: { order: true, @@ -332,7 +329,7 @@ export class RefundTicketSchema extends PothosSchema { } const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me.id, + senderId: ctx.me.id, recipientId: requester.id, type: MessageType.TEXT, content: `Yêu cầu hoàn tiền của bạn đã được ${args.action === 'APPROVE' ? 'chấp thuận' : 'từ chối'}`, @@ -340,7 +337,7 @@ export class RefundTicketSchema extends PothosSchema { context: MessageContextType.NOTIFICATION, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${requester.id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${requester.id}`, message) return refundTicket }, }), diff --git a/src/Resume/resume.schema.ts b/src/Resume/resume.schema.ts index b2174af..69fd73a 100644 --- a/src/Resume/resume.schema.ts +++ b/src/Resume/resume.schema.ts @@ -108,13 +108,13 @@ export class ResumeSchema extends PothosSchema { }, resolve: async (query, _root, args, ctx, _info) => { try { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } const resumes = await this.prisma.resume.findMany({ ...query, where: { - userId: ctx.http.me?.id ?? '', + userId: ctx.me.id, status: args.status ?? undefined, }, }) @@ -205,10 +205,10 @@ export class ResumeSchema extends PothosSchema { }), }, resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } - if (ctx.http.me?.role !== Role.CUSTOMER && ctx.http.me?.role !== Role.CENTER_OWNER) { + if (ctx.me.role !== Role.CUSTOMER && ctx.me.role !== Role.CENTER_OWNER) { throw new Error('Not allowed') } const { resumeFile } = args @@ -251,15 +251,15 @@ export class ResumeSchema extends PothosSchema { for (const moderator of moderators) { const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me?.id ?? '', recipientId: moderator.id, type: MessageType.TEXT, - content: `Có yêu cầu hồ sơ mới từ ${ctx.http.me?.name}`, + content: `Có yêu cầu hồ sơ mới từ ${ctx.me?.name}`, sentAt: DateTimeUtils.nowAsJSDate(), context: MessageContextType.NOTIFICATION, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) } return resume } @@ -278,15 +278,15 @@ export class ResumeSchema extends PothosSchema { for (const moderator of moderators) { const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me?.id ?? '', recipientId: moderator.id, type: MessageType.TEXT, - content: `Có yêu cầu hồ sơ mới từ ${ctx.http.me?.name}`, + content: `Có yêu cầu hồ sơ mới từ ${ctx.me?.name}`, sentAt: DateTimeUtils.nowAsJSDate(), context: MessageContextType.NOTIFICATION, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${moderator.id}`, message) } return resume }, @@ -310,10 +310,10 @@ export class ResumeSchema extends PothosSchema { }), }, resolve: async (_query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } - if (ctx.http.me?.role !== Role.MODERATOR) { + if (ctx.me.role !== Role.MODERATOR) { throw new Error('Not allowed') } const { resumeId, status, adminNote } = args @@ -348,7 +348,7 @@ export class ResumeSchema extends PothosSchema { _adminNote = await tx.adminNote.create({ data: { content: adminNote, - notedByUserId: ctx.http.me?.id ?? '', + notedByUserId: ctx.me?.id ?? '', resumeId, }, }) diff --git a/src/Schedule/schedule.schema.ts b/src/Schedule/schedule.schema.ts index 152ce02..a2fc07f 100644 --- a/src/Schedule/schedule.schema.ts +++ b/src/Schedule/schedule.schema.ts @@ -225,10 +225,7 @@ export class ScheduleSchema extends PothosSchema { description: 'Retrieve a single schedule by its unique identifier.', args: this.builder.generator.findUniqueArgs('Schedule'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Cannot retrieve schedule in subscription') - } - if (!ctx.http?.me?.id) { + if (!ctx.me) { throw new Error('User not found') } // only return schedule belong to center @@ -236,7 +233,7 @@ export class ScheduleSchema extends PothosSchema { const center = await this.prisma.center.findFirst({ where: { AND: [ - { OR: [{ centerOwnerId: ctx.http.me.id }, { centerMentors: { some: { mentorId: ctx.http.me.id } } }] }, + { OR: [{ centerOwnerId: ctx.me.id }, { centerMentors: { some: { mentorId: ctx.me.id } } }] }, { centerStatus: CenterStatus.APPROVED }, ], }, @@ -260,14 +257,11 @@ export class ScheduleSchema extends PothosSchema { args: this.builder.generator.findManyArgs('Schedule'), description: 'Retrieve a list of schedules with optional filtering, ordering, and pagination.', resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Cannot retrieve schedules in subscription') - } - if (!ctx.http?.me?.id) { + if (!ctx.me) { throw new Error('User not found') } // use case 1: customer query schedules where customer is participant - if (ctx.http.me.role === Role.CUSTOMER) { + if (ctx.me.role === Role.CUSTOMER) { const schedules = await this.prisma.schedule.findMany({ ...query, orderBy: args.orderBy ?? undefined, @@ -278,12 +272,12 @@ export class ScheduleSchema extends PothosSchema { return schedules } // use case 2: center mentor or center owner query schedules where center mentor or center owner is mentor - if (ctx.http.me.role === Role.CENTER_MENTOR) { + if (ctx.me.role === Role.CENTER_MENTOR) { const center = await this.prisma.center.findFirst({ where: { centerMentors: { some: { - mentorId: ctx.http.me.id, + mentorId: ctx.me.id, }, }, }, @@ -299,7 +293,7 @@ export class ScheduleSchema extends PothosSchema { orderBy: args.orderBy ?? undefined, where: { AND: [ - { managedService: { service: { centerId: center.id }, mentorId: ctx.http.me.id } }, + { managedService: { service: { centerId: center.id }, mentorId: ctx.me.id } }, ...(args.filter ? [args.filter] : []), ], }, @@ -307,9 +301,9 @@ export class ScheduleSchema extends PothosSchema { return schedules } // use case 3: Center owner query all schedules belong to center - if (ctx.http.me.role === Role.CENTER_OWNER) { + if (ctx.me.role === Role.CENTER_OWNER) { const center = await this.prisma.center.findFirst({ - where: { centerOwnerId: ctx.http.me.id }, + where: { centerOwnerId: ctx.me.id }, }) if (!center) { throw new Error('Center not found') @@ -333,10 +327,7 @@ export class ScheduleSchema extends PothosSchema { description: 'Retrieve a list of schedule dates.', args: this.builder.generator.findManyArgs('ScheduleDate'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Cannot retrieve schedule dates in subscription') - } - if (!ctx.http?.me?.id) { + if (!ctx.me) { throw new Error('User not found') } return await this.prisma.scheduleDate.findMany({ @@ -345,7 +336,7 @@ export class ScheduleSchema extends PothosSchema { take: args.take ?? undefined, orderBy: args.orderBy ?? undefined, where: { - AND: [{ participantIds: { has: ctx.http.me.id } }, ...(args.filter ? [args.filter] : [])], + AND: [{ participantIds: { has: ctx.me.id } }, ...(args.filter ? [args.filter] : [])], }, }) }, @@ -404,8 +395,8 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1 }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Cannot create schedule in subscription') + if (!ctx.me) { + throw new Error('User not found') } Logger.log('args.schedule', args.schedule) // reject schedule if start date is today or in the past diff --git a/src/Service/service.schema.ts b/src/Service/service.schema.ts index 3558ceb..51deced 100644 --- a/src/Service/service.schema.ts +++ b/src/Service/service.schema.ts @@ -118,16 +118,13 @@ export class ServiceSchema extends PothosSchema { description: 'Whether the user has already provided feedback for the service.', nullable: true, resolve: async (service, _args, ctx) => { - if (ctx.isSubscription) { - return null - } - if (!ctx.http.me) { + if (!ctx.me) { return false } const serviceFeedbacks = await this.prisma.serviceFeedback.findMany({ where: { serviceId: service.id, - userId: ctx.http.me.id, + userId: ctx.me.id, }, }) return serviceFeedbacks.length > 0 @@ -164,18 +161,15 @@ export class ServiceSchema extends PothosSchema { args: this.builder.generator.findManyArgs('Service'), resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } // check role if user is mentor or center owner - const role = ctx.http.me?.role + const role = ctx.me?.role if (role !== Role.CENTER_MENTOR && role !== Role.CENTER_OWNER) { - throw new Error('Not allowed') + throw new Error('User not found') } if (role === Role.CENTER_MENTOR) { // load only service belong to center of current user const managedServices = await this.prisma.managedService.findMany({ - where: { mentorId: ctx.http.me?.id ?? '' }, + where: { mentorId: ctx.me.id }, }) if (!managedServices) { throw new Error('Managed services not found') @@ -188,7 +182,7 @@ export class ServiceSchema extends PothosSchema { // if role is center owner, load all services belong to center of current user if (role === Role.CENTER_OWNER) { const center = await this.prisma.center.findUnique({ - where: { centerOwnerId: ctx.http.me?.id ?? '' }, + where: { centerOwnerId: ctx.me.id }, }) if (!center) { throw new Error('Center not found') @@ -239,11 +233,11 @@ export class ServiceSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } // replace userId with current user id - args.input.user = { connect: { id: ctx.http.me?.id ?? '' } } + args.input.user = { connect: { id: ctx.me.id } } const service = await this.prisma.service.create({ ...query, data: args.input, @@ -279,7 +273,7 @@ export class ServiceSchema extends PothosSchema { }) const messages = await this.prisma.message.createManyAndReturn({ data: moderatorIds.map((moderator) => ({ - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me.id, recipientId: moderator.id, type: MessageType.TEXT, content: `Có một dịch vụ mới với tên ${service.name} được đăng tải bởi ${center.name}`, @@ -288,7 +282,7 @@ export class ServiceSchema extends PothosSchema { })), }) messages.forEach((message) => { - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${message.recipientId}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${message.recipientId}`, message) }) return service }, @@ -355,8 +349,8 @@ export class ServiceSchema extends PothosSchema { }), }, resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } return await this.prisma.$transaction(async (prisma) => { // check if service is already approved or rejected @@ -382,7 +376,7 @@ export class ServiceSchema extends PothosSchema { adminNote: { create: { content: args.adminNote ?? '', - notedByUserId: ctx.http.me?.id ?? '', + notedByUserId: ctx.me.id, }, }, commission: commission ?? 0, @@ -427,7 +421,7 @@ export class ServiceSchema extends PothosSchema { // add message to database const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me.id, recipientId: id, type: MessageType.TEXT, content: `Dịch vụ ${service.name} của bạn đã được chấp thuận`, @@ -438,7 +432,7 @@ export class ServiceSchema extends PothosSchema { }, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${id}`, message) }) } else { await this.mailService.sendTemplateEmail(emails, 'Thông báo về trạng thái dịch vụ', 'ServiceRejected', { @@ -455,7 +449,7 @@ export class ServiceSchema extends PothosSchema { // add message to database const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me.id, recipientId: id, type: MessageType.TEXT, content: `Dịch vụ ${service.name} của bạn đã bị từ chối`, @@ -466,7 +460,7 @@ export class ServiceSchema extends PothosSchema { }, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${id}`, message) }) } return updatedService diff --git a/src/ServiceFeedback/servicefeedback.schema.ts b/src/ServiceFeedback/servicefeedback.schema.ts index 1b725fd..e8e4cf6 100644 --- a/src/ServiceFeedback/servicefeedback.schema.ts +++ b/src/ServiceFeedback/servicefeedback.schema.ts @@ -90,21 +90,18 @@ export class ServiceFeedbackSchema extends PothosSchema { }, description: 'Create a new service feedback.', resolve: async (_, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http?.me) { + if (!ctx.me) { throw new Error('Unauthorized') } // allow only when user is CUSTOMER and order is completed - if (ctx.http?.me?.role !== Role.CUSTOMER) { + if (ctx.me.role !== Role.CUSTOMER) { throw new Error('Unauthorized') } Logger.log(`args: ${JSON.stringify(args)}`) const order = await this.prisma.order.findFirst({ where: { id: args.orderId, - userId: ctx.http?.me?.id, + userId: ctx.me.id, status: OrderStatus.PAID, schedule: { dates: { @@ -118,7 +115,7 @@ export class ServiceFeedbackSchema extends PothosSchema { if (!order) { throw new Error('Order not found') } - if (order.userId !== ctx.http?.me?.id) { + if (order.userId !== ctx.me.id) { throw new Error('Unauthorized') } if (order.status !== OrderStatus.PAID) { @@ -134,7 +131,7 @@ export class ServiceFeedbackSchema extends PothosSchema { } return await this.prisma.serviceFeedback.create({ data: { - userId: ctx.http?.me?.id, + userId: ctx.me.id, serviceId: order.serviceId, rating: args.rating, comments: args.comments, diff --git a/src/User/user.module.ts b/src/User/user.module.ts index 4dcc851..0171f40 100644 --- a/src/User/user.module.ts +++ b/src/User/user.module.ts @@ -1,10 +1,11 @@ import { Module } from '@nestjs/common' -import { ChatroomModule } from '../ChatRoom/chatroom.module' -import { MessageModule } from '../Message/message.module' +import { ChatroomSchema } from 'src/ChatRoom/chatroom.schema' +import { MessageSchema } from 'src/Message/message.schema' import { UserSchema } from './user.schema' + @Module({ - imports: [MessageModule, ChatroomModule], - providers: [UserSchema], + providers: [UserSchema, ChatroomSchema, MessageSchema], exports: [UserSchema], }) export class UserModule {} + diff --git a/src/User/user.schema.ts b/src/User/user.schema.ts index d26de35..80556f1 100644 --- a/src/User/user.schema.ts +++ b/src/User/user.schema.ts @@ -170,10 +170,10 @@ export class UserSchema extends PothosSchema { description: 'Retrieve the current user in context.', type: this.user(), resolve: async (_query, _root, _args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } - return ctx.http.me + return ctx.me }, }), @@ -184,18 +184,13 @@ export class UserSchema extends PothosSchema { take: t.arg({ type: 'Int', required: false }), }, resolve: async (_parent, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - const me = ctx.http.me - if (!me) { + if (!ctx.me) { throw new Error('User not found') } - // get chat rooms that the user is a part of const chatRooms = await this.prisma.chatRoom.findMany({ where: { - OR: [{ customerId: me.id }, { mentorId: me.id }], + OR: [{ customerId: ctx.me.id }, { mentorId: ctx.me.id }], }, orderBy: { lastActivity: 'desc', @@ -357,10 +352,10 @@ export class UserSchema extends PothosSchema { }), }, resolve: async (_query, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') + if (!ctx.me) { + throw new Error('User not found') } - const id = ctx.http.me?.id + const id = ctx.me.id if (!id) { throw new Error('User not found') } @@ -420,7 +415,7 @@ export class UserSchema extends PothosSchema { }) } // invalidate cache - await ctx.http.invalidateCache() + await ctx.invalidateCache() return await this.prisma.user.findUniqueOrThrow({ where: { id: clerkUser.id }, }) @@ -434,12 +429,12 @@ export class UserSchema extends PothosSchema { }, resolve: async (_parent, args, ctx) => { // check context - if (ctx.isSubscription) { + if (!ctx.me) { throw new Error('Not allowed') } // check context is admin - if (ctx.http.me?.role !== Role.ADMIN) { + if (ctx.me?.role !== Role.ADMIN) { throw new Error(`Only admin can invite moderator`) } return this.prisma.$transaction(async (tx) => { @@ -477,11 +472,7 @@ export class UserSchema extends PothosSchema { }), }, resolve: async (_, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - const me = ctx.http.me - if (!me) { + if (!ctx.me) { throw new Error('User not found') } // create message @@ -489,7 +480,7 @@ export class UserSchema extends PothosSchema { data: { type: args.input.type, content: args.input.content, - senderId: me.id, + senderId: ctx.me.id, recipientId: args.input.recipient?.connect?.id ?? null, chatRoomId: args.input.chatRoom?.connect?.id ?? null, sentAt: DateTimeUtils.nowAsJSDate(), @@ -498,7 +489,7 @@ export class UserSchema extends PothosSchema { }, }) // publish message - await ctx.http.pubSub.publish(`${PubSubEvent.NEW_MESSAGE}.${message.recipientId}`, message) + await ctx.pubSub.publish(`${PubSubEvent.NEW_MESSAGE}.${message.recipientId}`, message) return message }, }), @@ -508,13 +499,10 @@ export class UserSchema extends PothosSchema { userId: t.arg({ type: 'String', required: true }), }, resolve: async (_parent, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (ctx.http.me?.role !== Role.ADMIN && ctx.http.me?.role !== Role.MODERATOR) { + if (ctx.me?.role !== Role.ADMIN && ctx.me?.role !== Role.MODERATOR) { throw new Error(`Only admin or moderator can ban user`) } - if (args.userId === ctx.http.me?.id) { + if (args.userId === ctx.me?.id) { throw new Error(`Cannot ban yourself`) } // get banning user info @@ -531,7 +519,7 @@ export class UserSchema extends PothosSchema { // ban user from clerk await clerkClient.users.banUser(args.userId) // invalidate cache - await ctx.http.invalidateCache() + await ctx.invalidateCache() // update user banned status await this.prisma.user.update({ where: { id: args.userId }, @@ -547,13 +535,13 @@ export class UserSchema extends PothosSchema { userScopedMessage: t.field({ type: this.messageSchema.message(), subscribe: async (_, _args, ctx) => { - if (!ctx.isSubscription) { + if (!ctx.me) { throw new Error('Not allowed') } - return ctx.websocket.pubSub.asyncIterator([ - `${PubSubEvent.NEW_MESSAGE}.${ctx.websocket.me?.id}`, - `${PubSubEvent.NOTIFICATION}.${ctx.websocket.me?.id}`, + return ctx.pubSub.asyncIterator([ + `${PubSubEvent.NEW_MESSAGE}.${ctx.me?.id}`, + `${PubSubEvent.NOTIFICATION}.${ctx.me?.id}`, ]) as unknown as AsyncIterable }, resolve: async (payload: Message) => payload, diff --git a/src/Workshop/workshop.schema.ts b/src/Workshop/workshop.schema.ts index ea686fb..afa61b3 100644 --- a/src/Workshop/workshop.schema.ts +++ b/src/Workshop/workshop.schema.ts @@ -136,13 +136,10 @@ export class WorkshopSchema extends PothosSchema { }, description: 'Create a new workshop.', resolve: async (query, _root, args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Workshops cannot be created in subscription context') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('User is not authenticated to create a workshop') } - if (ctx.http.me.role !== Role.CENTER_OWNER) { + if (ctx.me.role !== Role.CENTER_OWNER) { throw new Error('Only center owners can create workshops') } if (!args.input.service.connect) { @@ -186,7 +183,7 @@ export class WorkshopSchema extends PothosSchema { for (const customer of customers) { const message = await this.prisma.message.create({ data: { - senderId: ctx.http.me?.id ?? '', + senderId: ctx.me?.id ?? '', recipientId: customer.id, type: MessageType.TEXT, content: `Workshop ${workshop.title} đã được lên lịch do ${service.center.name} tổ chức. Nhanh tay đăng kí ngay!`, @@ -194,7 +191,7 @@ export class WorkshopSchema extends PothosSchema { context: MessageContextType.NOTIFICATION, }, }) - ctx.http.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${customer.id}`, message) + ctx.pubSub.publish(`${PubSubEvent.NOTIFICATION}.${customer.id}`, message) } return workshop }, diff --git a/src/WorkshopMeetingRoom/workshopmeetingroom.schema.ts b/src/WorkshopMeetingRoom/workshopmeetingroom.schema.ts index 4b542f4..9d0e118 100644 --- a/src/WorkshopMeetingRoom/workshopmeetingroom.schema.ts +++ b/src/WorkshopMeetingRoom/workshopmeetingroom.schema.ts @@ -72,10 +72,7 @@ export class WorkshopMeetingRoomSchema extends PothosSchema { }), }, resolve: async (_, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed') - } - if (!ctx.http?.me) { + if (!ctx.me) { throw new Error('Unauthorized') } const meetingRoom = await this.prisma.workshopMeetingRoom.findUnique({ @@ -96,7 +93,7 @@ export class WorkshopMeetingRoomSchema extends PothosSchema { const serverUrl = this.livekitService.getServerUrl() return { id: meetingRoom.id, - token: await this.livekitService.createToken(ctx.http?.me, meetingRoom.id), + token: await this.livekitService.createToken(ctx.me, meetingRoom.id), serverUrl, chatRoomId: chatRoom?.id, } diff --git a/src/WorkshopSubscription/workshopsubscription.schema.ts b/src/WorkshopSubscription/workshopsubscription.schema.ts index 8162554..a56c63b 100644 --- a/src/WorkshopSubscription/workshopsubscription.schema.ts +++ b/src/WorkshopSubscription/workshopsubscription.schema.ts @@ -58,10 +58,7 @@ export class WorkshopSubscriptionSchema extends PothosSchema { type: [this.workshopSubscription()], args: this.builder.generator.findManyArgs('WorkshopSubscription'), description: 'Retrieve a list of workshop subscriptions with optional filtering, ordering, and pagination.', - resolve: async (query, _root, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Workshops cannot be retrieved in subscription context') - } + resolve: async (query, _root, args, _ctx) => { return await this.prisma.workshopSubscription.findMany({ ...query, skip: args.skip ?? undefined, @@ -75,16 +72,13 @@ export class WorkshopSubscriptionSchema extends PothosSchema { type: [this.workshopSubscription()], description: 'Retrieve a list of workshops that the current user is subscribed to.', resolve: async (query, _root, _args, ctx, _info) => { - if (ctx.isSubscription) { - throw new Error('Workshops cannot be retrieved in subscription context') - } - if (!ctx.http.me) { + if (!ctx.me) { throw new Error('User is not authenticated') } return await this.prisma.workshopSubscription.findMany({ ...query, where: { - userId: ctx.http.me.id, + userId: ctx.me.id, }, }) }, @@ -100,10 +94,7 @@ export class WorkshopSubscriptionSchema extends PothosSchema { }), }, resolve: async (_query, _root, args, ctx) => { - if (ctx.isSubscription) { - throw new Error('Not allowed in subscription') - } - const userId = ctx.http.me?.id + const userId = ctx.me?.id // retrieve the workshop const workshop = await this.prisma.workshop.findUnique({ where: { id: args.workshopId },