Files
course-craft-service/apps/api/src/groups/groups.service.ts
root 5ddb3db1ac 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>
2026-02-06 10:50:04 +00:00

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 } } },
});
}
}