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>
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
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 } } },
|
|
});
|
|
}
|
|
}
|