update some complex logic
This commit is contained in:
Submodule epess-database updated: e96b0b03d9...b0b509d773
@@ -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({
|
||||||
|
|||||||
@@ -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,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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',
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/main.ts
44
src/main.ts
@@ -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
Reference in New Issue
Block a user