- Added LiveKitModule to CollaborationSession and MeetingRoom modules for enhanced real-time collaboration features. - Updated CollaborationSessionSchema to include LiveKit services for managing participant access and room permissions. - Implemented a new cron job in CronService to disable services without schedules for over 30 days, improving service management. - Enhanced GraphQL schema generation with improved filtering logic for better performance and readability. - Refactored LiveKit services to streamline access token creation and room management functionalities.
223 lines
7.1 KiB
TypeScript
223 lines
7.1 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common'
|
|
import { Cron } from '@nestjs/schedule'
|
|
import { CronExpression } from '@nestjs/schedule'
|
|
import { OrderStatus, PaymentStatus, ScheduleDateStatus, ScheduleStatus, ServiceStatus } from '@prisma/client'
|
|
import { DateTimeUtils } from 'src/common/utils/datetime.utils'
|
|
import { NotificationService } from 'src/Notification/notification.service'
|
|
import { PrismaService } from 'src/Prisma/prisma.service'
|
|
|
|
@Injectable()
|
|
export class CronService {
|
|
constructor(
|
|
private readonly prisma: PrismaService,
|
|
private readonly notificationService: NotificationService,
|
|
) {}
|
|
|
|
// cron every 1 minute to check schedule date status
|
|
@Cron(CronExpression.EVERY_MINUTE)
|
|
async checkScheduleDateStatus() {
|
|
Logger.log('Checking schedule date status', 'checkScheduleDateStatus')
|
|
const schedules = await this.prisma.scheduleDate.findMany({
|
|
where: {
|
|
end: {
|
|
lt: DateTimeUtils.now().toJSDate(),
|
|
},
|
|
status: {
|
|
notIn: [ScheduleDateStatus.COMPLETED, ScheduleDateStatus.MISSING_MENTOR, ScheduleDateStatus.MISSING_CUSTOMER],
|
|
},
|
|
},
|
|
})
|
|
Logger.log(`Found ${schedules.length} schedules to update`, 'checkScheduleDateStatus')
|
|
// get all collaboration sessions
|
|
const collaborationSessions = await this.prisma.collaborationSession.findMany({
|
|
where: {
|
|
collaboratorsIds: {
|
|
hasEvery: schedules.map((s) => s.id),
|
|
},
|
|
},
|
|
})
|
|
|
|
const updates = schedules
|
|
.map((schedule) => {
|
|
const collaborationSession = collaborationSessions.find((session) => session.scheduleDateId === schedule.id)
|
|
|
|
if (!collaborationSession) {
|
|
return {
|
|
id: schedule.id,
|
|
status: ScheduleDateStatus.MISSING_MENTOR,
|
|
}
|
|
}
|
|
|
|
if (collaborationSession.collaboratorsIds.length === 1) {
|
|
return {
|
|
id: schedule.id,
|
|
status: ScheduleDateStatus.MISSING_CUSTOMER,
|
|
}
|
|
}
|
|
|
|
if (collaborationSession.collaboratorsIds.length === 2) {
|
|
return {
|
|
id: schedule.id,
|
|
status: ScheduleDateStatus.COMPLETED,
|
|
}
|
|
}
|
|
|
|
return null
|
|
})
|
|
.filter((update) => update !== null)
|
|
|
|
for (const update of updates) {
|
|
await this.prisma.scheduleDate.update({
|
|
where: { id: update.id },
|
|
data: { status: update.status },
|
|
})
|
|
}
|
|
}
|
|
|
|
// cron every 1 minute to check payment status where created_at is more than 15 minutes
|
|
@Cron(CronExpression.EVERY_MINUTE)
|
|
async checkPaymentStatus() {
|
|
Logger.log('Checking payment status', 'checkPaymentStatus')
|
|
const payments = await this.prisma.payment.findMany({
|
|
where: {
|
|
status: PaymentStatus.PENDING,
|
|
createdAt: {
|
|
lt: DateTimeUtils.now().minus({ minutes: 15 }).toJSDate(),
|
|
},
|
|
},
|
|
})
|
|
Logger.log(`Found ${payments.length} payments to update`, 'checkPaymentStatus')
|
|
for (const payment of payments) {
|
|
await this.prisma.payment.update({
|
|
where: { id: payment.id },
|
|
data: { status: PaymentStatus.CANCELLED },
|
|
})
|
|
await this.prisma.order.update({
|
|
where: { id: payment.orderId },
|
|
data: { status: OrderStatus.FAILED },
|
|
})
|
|
}
|
|
}
|
|
|
|
// handle refund ticket by order, if order status is refunded, disable schedule and remove schedule date in future
|
|
@Cron(CronExpression.EVERY_MINUTE)
|
|
async taskRefundTicket() {
|
|
Logger.log('Handling refund ticket', 'handleRefundTicket')
|
|
const now = DateTimeUtils.now().toJSDate()
|
|
// get all orders where status is REFUNDED and has schedule.dates in future
|
|
const orders = await this.prisma.order.findMany({
|
|
where: {
|
|
status: OrderStatus.REFUNDED,
|
|
schedule: {
|
|
dates: {
|
|
some: {
|
|
end: {
|
|
gt: now,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
include: {
|
|
schedule: {
|
|
include: {
|
|
dates: true,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
Logger.log(`Found ${orders.length} orders to handle`, 'handleRefundTicket')
|
|
for (const order of orders) {
|
|
await this.prisma.schedule.update({
|
|
where: { id: order.scheduleId },
|
|
data: { status: ScheduleStatus.REFUNDED },
|
|
})
|
|
}
|
|
// remove schedule date in future
|
|
for (const order of orders) {
|
|
await this.prisma.scheduleDate.deleteMany({
|
|
where: {
|
|
id: { in: order.schedule.dates.map((d) => d.id) },
|
|
start: { gt: now },
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// cron every 1 minute to check if there is any schedule date start in less than 30 minutes
|
|
@Cron(CronExpression.EVERY_MINUTE)
|
|
async taskCheckScheduleDateStart() {
|
|
Logger.log('Checking schedule date start', 'taskCheckScheduleDateStart')
|
|
const schedules = await this.prisma.schedule.findMany({
|
|
where: {
|
|
AND: [
|
|
{
|
|
scheduleStart: {
|
|
lt: DateTimeUtils.now().plus({ minutes: 30 }).toJSDate(),
|
|
},
|
|
},
|
|
{
|
|
status: ScheduleStatus.PUBLISHED,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
Logger.log(`Found ${schedules.length} schedules to check`, 'taskCheckScheduleDateStart')
|
|
for (const schedule of schedules) {
|
|
await this.prisma.scheduleDate.updateMany({
|
|
where: { scheduleId: schedule.id },
|
|
data: { status: ScheduleDateStatus.EXPIRED },
|
|
})
|
|
// update schedule status to expired
|
|
await this.prisma.schedule.update({
|
|
where: { id: schedule.id },
|
|
data: { status: ScheduleStatus.EXPIRED },
|
|
})
|
|
// send notification to mentor
|
|
const managedService = await this.prisma.managedService.findUnique({
|
|
where: { id: schedule.managedServiceId },
|
|
})
|
|
if (managedService) {
|
|
await this.notificationService.sendNotification(
|
|
managedService.mentorId,
|
|
'Lịch hướng dẫn của bạn đã hết hạn',
|
|
`Lịch hướng dẫn với ngày bắt đầu: ${DateTimeUtils.format(
|
|
DateTimeUtils.fromDate(schedule.scheduleStart),
|
|
'D',
|
|
)}, slot: ${schedule.slots.map((s) => s).join(', ')} của bạn đã hết hạn do không có học viên đăng ký, vui lòng tạo lịch hướng dẫn mới`,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
// cron every day to disable service without any schedule in the past 30 days
|
|
@Cron(CronExpression.EVERY_DAY_AT_1AM)
|
|
async taskDisableServiceWithoutSchedule() {
|
|
Logger.log('Disabling service without any schedule', 'taskDisableServiceWithoutSchedule')
|
|
const services = await this.prisma.managedService.findMany({
|
|
where: {
|
|
NOT: {
|
|
schedule: {
|
|
some: {
|
|
scheduleStart: { gte: DateTimeUtils.now().minus({ days: 30 }).toJSDate() },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
for (const service of services) {
|
|
await this.prisma.managedService.update({
|
|
where: { id: service.id },
|
|
data: {
|
|
service: {
|
|
update: {
|
|
status: ServiceStatus.INACTIVE,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
Logger.log(`Service ${service.id} has been disabled`, 'taskDisableServiceWithoutSchedule')
|
|
}
|
|
}
|
|
}
|