import { Inject, Injectable, Logger } from '@nestjs/common' import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos' import { Builder, SchemaContext } from 'src/Graphql/graphql.builder' import { LiveKitService } from 'src/LiveKit/livekit.service' import { MinioService } from 'src/Minio/minio.service' import { PrismaService } from 'src/Prisma/prisma.service' @Injectable() export class MeetingRoomSchema extends PothosSchema { constructor( @Inject(SchemaBuilderToken) private readonly builder: Builder, private readonly prisma: PrismaService, private readonly livekitService: LiveKitService, private readonly minioService: MinioService, ) { super() } @PothosRef() meetingRoom() { return this.builder.prismaObject('MeetingRoom', { fields: (t) => ({ id: t.exposeID('id'), collaborationSessionId: t.exposeString('collaborationSessionId'), collaborationSession: t.relation('collaborationSession'), collaborators: t.relation('collaborators'), createdAt: t.expose('createdAt', { type: 'DateTime' }), updatedAt: t.expose('updatedAt', { type: 'DateTime' }), recordUrl: t.string({ nullable: true, resolve: async (meetingRoom) => { return await this.minioService.getRoomRecordUrl(meetingRoom.id) }, }), }), }) } @PothosRef() meetingRoomJoinInfo() { return this.builder.simpleObject('MeetingRoomJoinInfo', { fields: (t) => ({ id: t.string({ description: 'The ID of the meeting room.', }), token: t.string({ description: 'The token to join the meeting room.', }), serverUrl: t.string({ description: 'The URL of the server.', }), }), }) } @PothosRef() meetingRoomCollaborator() { return this.builder.prismaObject('MeetingRoomCollaborator', { fields: (t) => ({ id: t.exposeID('id'), meetingRoomId: t.exposeString('meetingRoomId'), meetingRoom: t.relation('meetingRoom'), userId: t.exposeString('userId'), user: t.relation('user'), }), }) } @Pothos() init(): void { this.builder.queryFields((t) => ({ // get meeting room by collaboration session id if exist or create new one meetingRoom: t.prismaField({ type: this.meetingRoom(), args: { scheduleDateId: t.arg.string({ required: true, }), }, resolve: async (_query, _parent, args, _ctx: SchemaContext) => { const collaborationSession = await this.prisma.collaborationSession.findUnique({ where: { scheduleDateId: args.scheduleDateId, }, }) if (!collaborationSession) { throw new Error('Collaboration session not found') } const meetingRoom = await this.prisma.meetingRoom.findUnique({ where: { collaborationSessionId: collaborationSession.id, }, }) if (meetingRoom) { return meetingRoom } return await this.prisma.meetingRoom.create({ data: { collaborationSessionId: collaborationSession.id, }, }) }, }), // get meeting room info by room id and check if user is collaborator of collaboration session then create new token and return it, // if not collaborator then throw error meetingRoomJoinInfo: t.field({ type: this.meetingRoomJoinInfo(), args: { collaborationSessionId: t.arg.string({ required: true, }), }, resolve: async (_, args, ctx: SchemaContext) => { if (!ctx.me) { throw new Error('Unauthorized') } const meetingRoom = await this.prisma.meetingRoom.findUnique({ where: { collaborationSessionId: args.collaborationSessionId }, }) if (!meetingRoom) { throw new Error('Meeting room not found') } // check if user is collaborator of collaboration session const collaborationSession = await this.prisma.collaborationSession.findUnique({ where: { id: meetingRoom.collaborationSessionId }, }) if (!collaborationSession) { throw new Error('Collaboration session not found') } if (!collaborationSession.collaboratorsIds.includes(ctx.me.id)) { throw new Error('User is not collaborator') } // create new token const token = await this.livekitService.createToken(ctx.me, meetingRoom.id) return { id: meetingRoom.id, token, serverUrl: this.livekitService.getServerUrl(), } }, }), interviewJoinInfo: t.field({ type: this.meetingRoomJoinInfo(), args: { scheduleId: t.arg.string({ required: true, }), }, resolve: async (_, args, ctx: SchemaContext) => { if (!ctx.me) { throw new Error('Unauthorized') } const token = await this.livekitService.createToken(ctx.me, args.scheduleId) return { id: args.scheduleId, token, serverUrl: this.livekitService.getServerUrl(), } }, }), })) this.builder.mutationFields((t) => ({ createMeetingRoom: t.prismaField({ type: this.meetingRoom(), args: { input: t.arg({ type: this.builder.generator.getCreateInput('MeetingRoom', [ 'id', 'createdAt', 'updatedAt', 'collaborators', ]), required: true, }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.meetingRoom.create({ ...query, data: args.input, }) }, }), updateMeetingRoomCollaborators: t.prismaField({ type: this.meetingRoom(), args: { meetingRoomId: t.arg.string({ required: true, }), addCollaborators: t.arg.stringList({ required: false, }), removeCollaborators: t.arg.stringList({ required: false, }), }, resolve: async (query, _parent, args, ctx: SchemaContext) => { if (!ctx.me) { throw new Error('Unauthorized') } return await this.prisma.meetingRoom.update({ ...query, where: { id: args.meetingRoomId, }, data: { collaborators: { createMany: { data: args.addCollaborators ? args.addCollaborators.map((id) => ({ userId: id })) : [], }, deleteMany: { userId: { in: args.removeCollaborators || [], }, }, }, }, }) }, }), })) } }