import { PrismaClient } from '@prisma/client'; import { AuthenticationError, ForbiddenError } from 'apollo-server-express'; import { PubSub } from 'graphql-subscriptions'; const prisma = new PrismaClient(); const pubsub = new PubSub(); export const ROOM_ADDED = 'ROOM_ADDED'; export const ROOM_UPDATED = 'ROOM_UPDATED'; export const roomResolvers = { Query: { rooms: async () => { return prisma.room.findMany({ where: { isPrivate: false }, }); }, room: async (_: any, { id }: { id: string }) => { return prisma.room.findUnique({ where: { id }, }); }, }, Mutation: { createRoom: async ( _: any, { name, description, isPrivate = false, }: { name: string; description?: string; isPrivate?: boolean }, context: any ) => { if (!context.userId) { throw new AuthenticationError('You must be logged in to create a room'); } const room = await prisma.room.create({ data: { name, description, isPrivate, owner: { connect: { id: context.userId }, }, members: { connect: { id: context.userId }, }, }, }); pubsub.publish(ROOM_ADDED, { roomAdded: room }); return room; }, joinRoom: async (_: any, { roomId }: { roomId: string }, context: any) => { if (!context.userId) { throw new AuthenticationError('You must be logged in to join a room'); } const room = await prisma.room.findUnique({ where: { id: roomId }, include: { members: true }, }); if (!room) { throw new ForbiddenError('Room not found'); } if (room.isPrivate) { // In a real application, you would check if the user has been invited throw new ForbiddenError( 'You cannot join a private room without an invitation' ); } // Check if user is already a member const isMember = room.members.some( (member: { id: string }) => member.id === context.userId ); if (isMember) { return room; } const updatedRoom = await prisma.room.update({ where: { id: roomId }, data: { members: { connect: { id: context.userId }, }, }, include: { members: true }, }); // Publish room updated event pubsub.publish(ROOM_UPDATED, { roomUpdated: updatedRoom }); return updatedRoom; }, leaveRoom: async (_: any, { roomId }: { roomId: string }, context: any) => { if (!context.userId) { throw new AuthenticationError('You must be logged in to leave a room'); } const room = await prisma.room.findUnique({ where: { id: roomId }, include: { members: true }, }); if (!room) { throw new ForbiddenError('Room not found'); } // Check if user is a member const isMember = room.members.some( (member: { id: string }) => member.id === context.userId ); if (!isMember) { throw new ForbiddenError('You are not a member of this room'); } // If user is the owner, they cannot leave if (room.ownerId === context.userId) { throw new ForbiddenError('You cannot leave a room you own'); } const updatedRoom = await prisma.room.update({ where: { id: roomId }, data: { members: { disconnect: { id: context.userId }, }, }, include: { members: true }, }); // Publish room updated event pubsub.publish(ROOM_UPDATED, { roomUpdated: updatedRoom }); return true; }, }, Subscription: { roomAdded: { subscribe: () => pubsub.asyncIterator([ROOM_ADDED]), }, roomUpdated: { subscribe: () => pubsub.asyncIterator([ROOM_UPDATED]), }, }, Room: { messages: async (parent: any) => { return prisma.message.findMany({ where: { roomId: parent.id }, orderBy: { createdAt: 'asc' }, }); }, members: async (parent: any) => { return prisma.user.findMany({ where: { rooms: { some: { id: parent.id, }, }, }, }); }, owner: async (parent: any) => { return prisma.user.findUnique({ where: { id: parent.ownerId }, }); }, }, };