your message

This commit is contained in:
root
2026-02-06 14:53:52 +00:00
parent c809d049fe
commit 3d488f22b7
47 changed files with 3127 additions and 425 deletions

View File

@ -14,35 +14,171 @@ export class GroupsService {
});
}
async addMember(groupId: string, userId: string, role = 'student'): Promise<any> {
return this.prisma.groupMember.create({
data: { groupId, userId, role },
async ensureDefaultGroup(courseId: string): Promise<any> {
const existing = await this.prisma.courseGroup.findFirst({
where: { courseId, isDefault: true },
});
if (existing) return existing;
return this.prisma.courseGroup.create({
data: {
courseId,
name: 'Основная группа',
description: 'Обсуждение курса и вопросы преподавателю',
isDefault: true,
},
});
}
async getDefaultGroup(courseId: string, userId: string): Promise<any> {
const group = await this.ensureDefaultGroup(courseId);
await this.assertCanReadGroup(group.id, userId);
const [messages, members] = await Promise.all([
this.getGroupMessages(group.id, userId),
this.getGroupMembers(group.id, userId),
]);
return { group, messages, members };
}
async addMember(groupId: string, requesterId: string, targetUserId: string, role = 'student'): Promise<any> {
const group = await this.prisma.courseGroup.findUnique({
where: { id: groupId },
include: { course: { select: { authorId: true } } },
});
if (!group) throw new NotFoundException('Group not found');
if (group.course.authorId !== requesterId) {
throw new ForbiddenException('Only course author can add members manually');
}
return this.prisma.groupMember.upsert({
where: { groupId_userId: { groupId, userId: targetUserId } },
create: { groupId, userId: targetUserId, role },
update: { role },
});
}
async getGroupMembers(groupId: string, userId: string): Promise<any> {
await this.assertCanReadGroup(groupId, userId);
return this.prisma.groupMember.findMany({
where: { groupId },
include: {
user: {
select: { id: true, name: true, email: true, avatarUrl: true },
},
},
orderBy: { joinedAt: 'asc' },
});
}
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');
await this.assertCanReadGroup(groupId, userId);
return this.prisma.groupMessage.findMany({
where: { groupId },
include: { user: { select: { id: true, name: true, avatarUrl: true } } },
orderBy: { createdAt: 'asc' },
take: 100,
take: 200,
});
}
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');
await this.assertCanReadGroup(groupId, userId);
return this.prisma.groupMessage.create({
data: { groupId, userId, content },
include: { user: { select: { id: true, name: true, avatarUrl: true } } },
});
}
async createInviteLink(groupId: string, userId: string): Promise<any> {
const group = await this.prisma.courseGroup.findUnique({
where: { id: groupId },
include: { course: { select: { authorId: true } } },
});
if (!group) throw new NotFoundException('Group not found');
if (group.course.authorId !== userId) {
throw new ForbiddenException('Only course author can create invite links');
}
const appUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3080';
return {
groupId,
inviteUrl: `${appUrl}/dashboard/groups/${groupId}`,
};
}
async joinByInvite(groupId: string, userId: string): Promise<any> {
const group = await this.prisma.courseGroup.findUnique({
where: { id: groupId },
include: {
course: {
select: { id: true, authorId: true, price: true },
},
},
});
if (!group) throw new NotFoundException('Group not found');
const hasEnrollment = await this.prisma.enrollment.findUnique({
where: { userId_courseId: { userId, courseId: group.course.id } },
});
const hasPurchase = await this.prisma.purchase.findUnique({
where: { userId_courseId: { userId, courseId: group.course.id } },
});
if (!hasEnrollment && !hasPurchase && group.course.authorId !== userId) {
throw new ForbiddenException('Enroll or purchase course first');
}
return this.prisma.groupMember.upsert({
where: { groupId_userId: { groupId, userId } },
create: { groupId, userId, role: group.course.authorId === userId ? 'teacher' : 'student' },
update: {},
});
}
async isMember(groupId: string, userId: string): Promise<boolean> {
const member = await this.prisma.groupMember.findUnique({
where: { groupId_userId: { groupId, userId } },
select: { id: true },
});
return Boolean(member);
}
private async assertCanReadGroup(groupId: string, userId: string): Promise<void> {
const group = await this.prisma.courseGroup.findUnique({
where: { id: groupId },
include: {
course: {
select: { id: true, authorId: true },
},
},
});
if (!group) {
throw new NotFoundException('Group not found');
}
if (group.course.authorId === userId) return;
const member = await this.prisma.groupMember.findUnique({
where: { groupId_userId: { groupId, userId } },
select: { id: true },
});
if (member) return;
const enrollment = await this.prisma.enrollment.findUnique({
where: { userId_courseId: { userId, courseId: group.course.id } },
select: { id: true },
});
if (enrollment) {
await this.prisma.groupMember.upsert({
where: { groupId_userId: { groupId, userId } },
create: { groupId, userId, role: 'student' },
update: {},
});
return;
}
throw new ForbiddenException('No access to this group');
}
}