course_web01 / backend /src /courses /courses.service.ts
trae-bot
Update project
426f2a4
import {
Injectable,
NotFoundException,
ForbiddenException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Course } from '../entities/course.entity';
import { UserCourse } from '../entities/user-course.entity';
import { UserStar } from '../entities/user-star.entity';
import { Comment } from '../entities/comment.entity';
@Injectable()
export class CoursesService {
constructor(
@InjectRepository(Course)
private courseRepository: Repository<Course>,
@InjectRepository(UserCourse)
private userCourseRepository: Repository<UserCourse>,
@InjectRepository(UserStar)
private userStarRepository: Repository<UserStar>,
@InjectRepository(Comment)
private commentRepository: Repository<Comment>,
) {}
async findAll() {
return this.courseRepository.find({
where: { isActive: true },
select: [
'id',
'title',
'description',
'coverImage',
'price',
'category',
'viewCount',
'likeCount',
'starCount',
],
order: { createdAt: 'DESC' },
});
}
async findOne(id: number) {
const course = await this.courseRepository.findOne({
where: { id, isActive: true },
select: [
'id',
'title',
'description',
'coverImage',
'price',
'category',
'viewCount',
'likeCount',
'starCount',
],
});
if (!course) {
throw new NotFoundException('Course not found');
}
return course;
}
async incrementViewCount(id: number) {
await this.courseRepository.increment({ id }, 'viewCount', 1);
}
async toggleLike(id: number) {
const course = await this.courseRepository.findOne({ where: { id } });
if (course) {
await this.courseRepository.increment({ id }, 'likeCount', 1);
}
}
async toggleStar(courseId: number, userId: number) {
const existingStar = await this.userStarRepository.findOne({
where: { courseId, userId },
});
if (existingStar) {
await this.userStarRepository.remove(existingStar);
await this.courseRepository.decrement({ id: courseId }, 'starCount', 1);
} else {
const newStar = this.userStarRepository.create({ courseId, userId });
await this.userStarRepository.save(newStar);
await this.courseRepository.increment({ id: courseId }, 'starCount', 1);
}
}
async getUserStars(userId: number) {
const userStars = await this.userStarRepository.find({
where: { userId },
relations: ['course'],
});
return userStars.map((us) => ({
id: us.course.id,
title: us.course.title,
coverImage: us.course.coverImage,
description: us.course.description,
price: us.course.price,
category: us.course.category,
viewCount: us.course.viewCount,
likeCount: us.course.likeCount,
starCount: us.course.starCount,
}));
}
async getUserCourses(userId: number) {
const userCourses = await this.userCourseRepository.find({
where: { userId },
relations: ['course'],
});
return userCourses.map((uc) => ({
id: uc.course.id,
title: uc.course.title,
coverImage: uc.course.coverImage,
expiredAt: uc.expiredAt,
}));
}
async getComments(courseId: number) {
const comments = await this.commentRepository.find({
where: { courseId },
relations: ['user', 'replyToComment', 'replyToComment.user'],
order: { createdAt: 'ASC' },
});
return comments.map(c => ({
id: c.id,
courseId: c.courseId,
userId: c.userId,
parentId: c.parentId,
replyToCommentId: c.replyToCommentId,
content: c.content,
createdAt: c.createdAt,
user: {
id: c.user.id,
nickname: c.user.nickname,
avatar: c.user.avatar,
isVip: c.user.isVip,
},
replyToUser: c.replyToComment ? {
id: c.replyToComment.user.id,
nickname: c.replyToComment.user.nickname,
} : undefined
}));
}
async addComment(courseId: number, userId: number, content: string, parentId?: number, replyToCommentId?: number) {
const course = await this.courseRepository.findOne({ where: { id: courseId } });
if (!course) throw new NotFoundException('Course not found');
const comment = this.commentRepository.create({
courseId,
userId,
content,
parentId,
replyToCommentId,
});
await this.commentRepository.save(comment);
const savedComment = await this.commentRepository.findOne({
where: { id: comment.id },
relations: ['user', 'replyToComment', 'replyToComment.user']
});
if (!savedComment) throw new NotFoundException('Comment not found after save');
return {
id: savedComment.id,
courseId: savedComment.courseId,
userId: savedComment.userId,
parentId: savedComment.parentId,
replyToCommentId: savedComment.replyToCommentId,
content: savedComment.content,
createdAt: savedComment.createdAt,
user: {
id: savedComment.user.id,
nickname: savedComment.user.nickname,
avatar: savedComment.user.avatar,
isVip: savedComment.user.isVip,
},
replyToUser: savedComment.replyToComment ? {
id: savedComment.replyToComment.user.id,
nickname: savedComment.replyToComment.user.nickname,
} : undefined
};
}
async getCourseAccess(userId: number, courseId: number) {
const userCourse = await this.userCourseRepository.findOne({
where: { userId, courseId },
relations: ['course'],
});
if (!userCourse) {
throw new ForbiddenException('You have not purchased this course');
}
if (userCourse.expiredAt < new Date()) {
throw new ForbiddenException('Your access to this course has expired');
}
return {
hasAccess: true,
driveLink: userCourse.course.driveLink, // In a real app, this should be a dynamic signed URL
expiredAt: userCourse.expiredAt,
};
}
}