update some complex logic

This commit is contained in:
2024-11-24 22:25:14 +07:00
parent edcd340d0b
commit 68dabd186a
6 changed files with 141 additions and 24 deletions

View File

@@ -9,7 +9,7 @@ import { Builder } from '../Graphql/graphql.builder'
import { PrismaService } from '../Prisma/prisma.service' import { PrismaService } from '../Prisma/prisma.service'
// import { LiveKitRoomService } from 'src/LiveKit/livekit.room.service' // import { LiveKitRoomService } from 'src/LiveKit/livekit.room.service'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { Role } from '@prisma/client'
@Injectable() @Injectable()
export class CollaborationSessionSchema extends PothosSchema { export class CollaborationSessionSchema extends PothosSchema {
constructor( constructor(
@@ -61,16 +61,76 @@ export class CollaborationSessionSchema extends PothosSchema {
@Pothos() @Pothos()
init(): void { init(): void {
this.builder.queryFields((t) => ({ this.builder.queryFields((t) => ({
// get collaboration session by schedule date id, if not exist, create new one
collaborationSession: t.prismaField({ collaborationSession: t.prismaField({
type: this.collaborationSession(), type: this.collaborationSession(),
args: this.builder.generator.findUniqueArgs('CollaborationSession'), args: {
scheduleDateId: t.arg.string({
description: 'The ID of the schedule date.',
required: true,
}),
},
description: description:
'Retrieve a single collaboration session by its unique identifier.', 'Retrieve a single collaboration session by its unique identifier.',
resolve: async (query, _root, args, _ctx, _info) => { resolve: async (_query, _root, args, ctx, _info) => {
return await this.prisma.collaborationSession.findUnique({ if (ctx.isSubscription) throw new Error('Not allowed')
...query, /* ---------- use case 1 : customer get collaboration session by id --------- */
where: args.where, if (args.scheduleDateId && ctx.http.me?.role === Role.CUSTOMER) {
if (!args.scheduleDateId)
throw new Error('Schedule date ID is required')
return await this.prisma.collaborationSession.findUniqueOrThrow({
where: {
scheduleDateId: args.scheduleDateId,
},
}) })
}
/* ---------- use case 2 : center mentor get collaboration session by schedule date id --------- */
if (!args.scheduleDateId)
throw new Error('Schedule date ID is required')
if (ctx.http.me?.role !== Role.CENTER_MENTOR)
throw new Error('User not allowed')
const scheduleDate = await this.prisma.scheduleDate.findUniqueOrThrow(
{
where: {
id: args.scheduleDateId,
},
},
)
if (!scheduleDate) throw new Error('Schedule date not found')
// check if order is exist in schedule date
if (!scheduleDate.orderId) throw new Error('Order not found')
const collaborationSession =
await this.prisma.collaborationSession.findUnique({
where: {
scheduleDateId: scheduleDate.id,
},
})
const order = await this.prisma.order.findUnique({
where: {
id: scheduleDate.orderId,
},
})
if (!order) throw new Error('Order not found')
if (!order.chatRoomId) throw new Error('Order chat room not found')
if (!collaborationSession) {
const chatRoom = await this.prisma.chatRoom.findUnique({
where: {
id: order.chatRoomId,
},
})
if (!chatRoom) throw new Error('Chat room not found')
// create new one
const newCollaborationSession =
await this.prisma.collaborationSession.create({
data: {
scheduleDateId: scheduleDate.id,
// assign chat room
chatRoomId: order.chatRoomId,
},
})
return newCollaborationSession // if not exist use case
}
return collaborationSession // if exist use case
}, },
}), }),
collaborationSessions: t.prismaField({ collaborationSessions: t.prismaField({

View File

@@ -46,14 +46,34 @@ export class MeetingRoomSchema extends PothosSchema {
@Pothos() @Pothos()
init(): void { init(): void {
this.builder.queryFields((t) => ({ this.builder.queryFields((t) => ({
// get meeting room by collaboration session id if exist or create new one
meetingRoom: t.prismaField({ meetingRoom: t.prismaField({
type: this.meetingRoom(), type: this.meetingRoom(),
args: this.builder.generator.findUniqueArgs('MeetingRoom'), args: {
resolve: async (query, _parent, args, ctx: SchemaContext) => { scheduleDateId: t.arg.string({
required: true,
}),
},
resolve: async (_query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) throw new Error('Not allowed') if (ctx.isSubscription) throw new Error('Not allowed')
return await this.prisma.meetingRoom.findUnique({ const collaborationSession =
...query, await this.prisma.collaborationSession.findUnique({
where: args.where, where: {
scheduleDateId: args.scheduleDateId,
},
})
if (!collaborationSession)
throw new Error('Collaboration session not found')
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: {
collaborationSessionId: collaborationSession.id,
},
})
if (meetingRoom) return meetingRoom
return await this.prisma.meetingRoom.create({
data: {
collaborationSessionId: collaborationSession.id,
},
}) })
}, },
}), }),

View File

@@ -12,6 +12,7 @@ import type {
} from '@payos/node/lib/type' } from '@payos/node/lib/type'
import { import {
ChatRoomType, ChatRoomType,
MessageType,
OrderStatus, OrderStatus,
PaymentStatus, PaymentStatus,
ScheduleDateStatus, ScheduleDateStatus,
@@ -117,6 +118,16 @@ export class PayosService {
orderId: order.id, orderId: order.id,
}, },
}) })
// send first message from mentor to customer
await tx.message.create({
data: {
content:
'Xin chào, mình là hướng dẫn viên của bạn, hãy bắt đầu học ngay nhé!',
type: MessageType.TEXT,
chatRoomId: chatRoom.id,
senderId: mentorId,
},
})
return { return {
message: 'Payment received', message: 'Payment received',
} }

View File

@@ -12,27 +12,49 @@ import { json } from 'express'
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule) const app = await NestFactory.create(AppModule)
// load private key and public key // load private key and public key
const privateKey = readFileSync(path.join(__dirname, 'KeyStore', 'private_key.pem'), 'utf8') const privateKey = readFileSync(
const publicKey = readFileSync(path.join(__dirname, 'KeyStore', 'public_key.pem'), 'utf8') path.join(__dirname, 'KeyStore', 'private_key.pem'),
'utf8',
)
const publicKey = readFileSync(
path.join(__dirname, 'KeyStore', 'public_key.pem'),
'utf8',
)
// set private key and public key to env // set private key and public key to env
process.env.JWT_RS256_PRIVATE_KEY = privateKey process.env.JWT_RS256_PRIVATE_KEY = privateKey
process.env.JWT_RS256_PUBLIC_KEY = publicKey process.env.JWT_RS256_PUBLIC_KEY = publicKey
Logger.log(`Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`, 'Bootstrap') Logger.log(
Logger.log(`Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`, 'Bootstrap') `Private key: ${privateKey.slice(0, 10).replace(/\n/g, '')}...`,
'Bootstrap',
)
Logger.log(
`Public key: ${publicKey.slice(0, 10).replace(/\n/g, '')}...`,
'Bootstrap',
)
const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(',') // split by comma to array const corsOrigin = (process.env.CORS_ORIGIN ?? '').split(',') // split by comma to array
app.enableCors({ app.enableCors({
origin: corsOrigin, origin: corsOrigin,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', '*', 'x-apollo-operation-name', 'x-session-id'], allowedHeaders: [
'Content-Type',
'*',
'x-apollo-operation-name',
'x-session-id',
],
credentials: true, credentials: true,
}) })
// set base path for api // set base path for api
app.setGlobalPrefix(process.env.API_PATH ?? '/v1') app.setGlobalPrefix(process.env.API_PATH ?? '/v1')
const config = new DocumentBuilder().setTitle('EPESS API').setDescription('API documentation for EPESS application').setVersion('0.0.1').addBearerAuth().build() const config = new DocumentBuilder()
.setTitle('EPESS API')
.setDescription('API documentation for EPESS application')
.setVersion('0.0.1')
.addBearerAuth()
.build()
const document = SwaggerModule.createDocument(app, config) const document = SwaggerModule.createDocument(app, config)
SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'v1', app, document) SwaggerModule.setup(process.env.SWAGGER_PATH ?? 'v1', app, document)
@@ -41,7 +63,8 @@ async function bootstrap() {
get: { get: {
tags: ['GraphQL'], tags: ['GraphQL'],
summary: 'GraphQL Playground', summary: 'GraphQL Playground',
description: 'Access the GraphQL Playground to interact with the GraphQL API.', description:
'Access the GraphQL Playground to interact with the GraphQL API.',
responses: { responses: {
'200': { '200': {
description: 'GraphQL Playground', description: 'GraphQL Playground',
@@ -61,13 +84,16 @@ async function bootstrap() {
// graphql upload // graphql upload
app.use( app.use(
graphqlUploadExpress({ graphqlUploadExpress({
maxFileSize: 100 * 1024 * 1024, // 100 MB maxFileSize: 1024 * 1024 * 1024, // 1 GB
maxFiles: 10, maxFiles: 10,
}), }),
) )
// biome-ignore lint/suspicious/noExplicitAny: <explanation> // biome-ignore lint/suspicious/noExplicitAny: <explanation>
} catch (error: any) { } catch (error: any) {
Logger.error(`Error in file upload middleware: ${error.message}`, 'Bootstrap') Logger.error(
`Error in file upload middleware: ${error.message}`,
'Bootstrap',
)
// Optionally, you can handle the error further or rethrow it // Optionally, you can handle the error further or rethrow it
} }

File diff suppressed because one or more lines are too long