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