feat: add certificates, groups, support system, and moderation
Backend changes: - Add Certificate generation service with beautiful HTML templates - Add CourseGroup, GroupMember, GroupMessage models for group collaboration - Add Homework and HomeworkSubmission models with AI + teacher grading - Add SupportTicket and TicketMessage models for help desk - Add Moderation API for admin/moderator course approval workflow - All new modules: CertificatesModule, GroupsModule, SupportModule, ModerationModule Frontend changes: - Add certificate download button when course completed - Update course page to load enrollment progress from backend - Integrate lesson completion with backend API Database schema now supports: - Course groups with chat functionality - Homework assignments with dual AI/human grading - Support ticket system with admin responses - Full moderation workflow (PENDING_REVIEW -> PUBLISHED/REJECTED) Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
48
apps/api/src/groups/groups.service.ts
Normal file
48
apps/api/src/groups/groups.service.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Injectable, NotFoundException, ForbiddenException } from '@nestjs/common';
|
||||
import { PrismaService } from '../common/prisma/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class GroupsService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async createGroup(courseId: string, userId: string, name: string, description?: string): Promise<any> {
|
||||
const course = await this.prisma.course.findFirst({ where: { id: courseId, authorId: userId } });
|
||||
if (!course) throw new ForbiddenException('Only course author can create groups');
|
||||
|
||||
return this.prisma.courseGroup.create({
|
||||
data: { courseId, name, description },
|
||||
});
|
||||
}
|
||||
|
||||
async addMember(groupId: string, userId: string, role = 'student'): Promise<any> {
|
||||
return this.prisma.groupMember.create({
|
||||
data: { groupId, userId, role },
|
||||
});
|
||||
}
|
||||
|
||||
async getGroupMessages(groupId: string, userId: string): Promise<any> {
|
||||
const member = await this.prisma.groupMember.findUnique({
|
||||
where: { groupId_userId: { groupId, userId } },
|
||||
});
|
||||
if (!member) throw new ForbiddenException('Not a member of this group');
|
||||
|
||||
return this.prisma.groupMessage.findMany({
|
||||
where: { groupId },
|
||||
include: { user: { select: { id: true, name: true, avatarUrl: true } } },
|
||||
orderBy: { createdAt: 'asc' },
|
||||
take: 100,
|
||||
});
|
||||
}
|
||||
|
||||
async sendMessage(groupId: string, userId: string, content: string): Promise<any> {
|
||||
const member = await this.prisma.groupMember.findUnique({
|
||||
where: { groupId_userId: { groupId, userId } },
|
||||
});
|
||||
if (!member) throw new ForbiddenException('Not a member of this group');
|
||||
|
||||
return this.prisma.groupMessage.create({
|
||||
data: { groupId, userId, content },
|
||||
include: { user: { select: { id: true, name: true, avatarUrl: true } } },
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user