2026-01-28 10:42:06 +08:00
|
|
|
|
import {
|
|
|
|
|
|
Injectable,
|
|
|
|
|
|
NotFoundException,
|
|
|
|
|
|
BadRequestException,
|
|
|
|
|
|
ForbiddenException,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
} from "@nestjs/common";
|
|
|
|
|
|
import { InjectRepository } from "@nestjs/typeorm";
|
|
|
|
|
|
import { Repository } from "typeorm";
|
|
|
|
|
|
import { Group } from "../../entities/group.entity";
|
|
|
|
|
|
import { GroupMember } from "../../entities/group-member.entity";
|
|
|
|
|
|
import { User } from "../../entities/user.entity";
|
|
|
|
|
|
import { CreateGroupDto, UpdateGroupDto, JoinGroupDto } from "./dto/group.dto";
|
|
|
|
|
|
import { GroupMemberRole } from "../../common/enums";
|
|
|
|
|
|
import {
|
|
|
|
|
|
ErrorCode,
|
|
|
|
|
|
ErrorMessage,
|
|
|
|
|
|
} from "../../common/interfaces/response.interface";
|
|
|
|
|
|
import { CacheService } from "../../common/services/cache.service";
|
2026-01-28 10:42:06 +08:00
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
|
export class GroupsService {
|
2026-01-28 13:03:28 +08:00
|
|
|
|
private readonly CACHE_PREFIX = "group";
|
2026-01-28 10:42:06 +08:00
|
|
|
|
private readonly CACHE_TTL = 300; // 5 minutes
|
|
|
|
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
|
|
@InjectRepository(Group)
|
|
|
|
|
|
private groupRepository: Repository<Group>,
|
|
|
|
|
|
@InjectRepository(GroupMember)
|
|
|
|
|
|
private groupMemberRepository: Repository<GroupMember>,
|
|
|
|
|
|
@InjectRepository(User)
|
|
|
|
|
|
private userRepository: Repository<User>,
|
|
|
|
|
|
private cacheService: CacheService,
|
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 创建小组
|
|
|
|
|
|
*/
|
|
|
|
|
|
async create(userId: string, createGroupDto: CreateGroupDto) {
|
|
|
|
|
|
const user = await this.userRepository.findOne({ where: { id: userId } });
|
|
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.USER_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.USER_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户创建的小组数量
|
|
|
|
|
|
const ownedGroupsCount = await this.groupRepository.count({
|
|
|
|
|
|
where: { ownerId: userId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!user.isMember && ownedGroupsCount >= 1) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.GROUP_LIMIT_EXCEEDED,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "非会员最多只能创建1个小组",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (user.isMember && ownedGroupsCount >= 10) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.GROUP_LIMIT_EXCEEDED,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "会员最多只能创建10个小组",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是创建子组,检查父组是否存在且用户是否为会员
|
|
|
|
|
|
if (createGroupDto.parentId) {
|
|
|
|
|
|
if (!user.isMember) {
|
|
|
|
|
|
throw new ForbiddenException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "非会员不能创建子组",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const parentGroup = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: createGroupDto.parentId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!parentGroup) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.GROUP_NOT_FOUND,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "父组不存在",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建小组
|
|
|
|
|
|
const group = this.groupRepository.create({
|
|
|
|
|
|
...createGroupDto,
|
|
|
|
|
|
ownerId: userId,
|
|
|
|
|
|
maxMembers: createGroupDto.maxMembers || 50,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
await this.groupRepository.save(group);
|
|
|
|
|
|
|
|
|
|
|
|
// 将创建者添加为小组成员(角色为 owner)
|
|
|
|
|
|
const member = this.groupMemberRepository.create({
|
|
|
|
|
|
groupId: group.id,
|
|
|
|
|
|
userId: userId,
|
|
|
|
|
|
role: GroupMemberRole.OWNER,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
await this.groupMemberRepository.save(member);
|
|
|
|
|
|
|
|
|
|
|
|
return this.findOne(group.id);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 加入小组(使用原子更新防止并发竞态条件)
|
|
|
|
|
|
*/
|
|
|
|
|
|
async join(userId: string, joinGroupDto: JoinGroupDto) {
|
|
|
|
|
|
const { groupId, nickname } = joinGroupDto;
|
|
|
|
|
|
|
|
|
|
|
|
const user = await this.userRepository.findOne({ where: { id: userId } });
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.USER_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.USER_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-28 13:03:28 +08:00
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: groupId },
|
|
|
|
|
|
});
|
2026-01-28 10:42:06 +08:00
|
|
|
|
if (!group) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.GROUP_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.GROUP_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经是成员
|
|
|
|
|
|
const existingMember = await this.groupMemberRepository.findOne({
|
|
|
|
|
|
where: { groupId, userId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (existingMember) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.ALREADY_IN_GROUP,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.ALREADY_IN_GROUP],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查用户加入的小组数量
|
|
|
|
|
|
const joinedGroupsCount = await this.groupMemberRepository.count({
|
|
|
|
|
|
where: { userId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!user.isMember && joinedGroupsCount >= 3) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.JOIN_GROUP_LIMIT_EXCEEDED,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.JOIN_GROUP_LIMIT_EXCEEDED],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用原子更新:只有当当前成员数小于最大成员数时才成功
|
|
|
|
|
|
const updateResult = await this.groupRepository
|
|
|
|
|
|
.createQueryBuilder()
|
|
|
|
|
|
.update(Group)
|
|
|
|
|
|
.set({
|
2026-01-28 13:03:28 +08:00
|
|
|
|
currentMembers: () => "currentMembers + 1",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
})
|
2026-01-28 13:03:28 +08:00
|
|
|
|
.where("id = :id", { id: groupId })
|
|
|
|
|
|
.andWhere("currentMembers < maxMembers")
|
2026-01-28 10:42:06 +08:00
|
|
|
|
.execute();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果影响的行数为0,说明小组已满
|
|
|
|
|
|
if (updateResult.affected === 0) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.GROUP_FULL,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.GROUP_FULL],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加成员记录
|
|
|
|
|
|
const member = this.groupMemberRepository.create({
|
|
|
|
|
|
groupId,
|
|
|
|
|
|
userId,
|
|
|
|
|
|
nickname,
|
|
|
|
|
|
role: GroupMemberRole.MEMBER,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
await this.groupMemberRepository.save(member);
|
|
|
|
|
|
|
|
|
|
|
|
return this.findOne(groupId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 退出小组
|
|
|
|
|
|
*/
|
|
|
|
|
|
async leave(userId: string, groupId: string) {
|
|
|
|
|
|
const member = await this.groupMemberRepository.findOne({
|
|
|
|
|
|
where: { groupId, userId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!member) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.NOT_IN_GROUP,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.NOT_IN_GROUP],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 组长不能直接退出
|
|
|
|
|
|
if (member.role === GroupMemberRole.OWNER) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "组长不能退出小组,请先转让组长或解散小组",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await this.groupMemberRepository.remove(member);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新小组成员数
|
2026-01-28 13:03:28 +08:00
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: groupId },
|
|
|
|
|
|
});
|
2026-01-28 10:42:06 +08:00
|
|
|
|
if (group) {
|
|
|
|
|
|
group.currentMembers = Math.max(0, group.currentMembers - 1);
|
|
|
|
|
|
await this.groupRepository.save(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-28 13:03:28 +08:00
|
|
|
|
return { message: "退出成功" };
|
2026-01-28 10:42:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取小组详情
|
|
|
|
|
|
*/
|
|
|
|
|
|
async findOne(id: string) {
|
|
|
|
|
|
// 尝试从缓存获取
|
|
|
|
|
|
const cached = this.cacheService.get<any>(id, {
|
|
|
|
|
|
prefix: this.CACHE_PREFIX,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (cached) {
|
|
|
|
|
|
return cached;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id },
|
2026-01-28 13:03:28 +08:00
|
|
|
|
relations: ["owner", "members", "members.user"],
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!group) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.GROUP_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.GROUP_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const result = {
|
|
|
|
|
|
...group,
|
|
|
|
|
|
members: group.members.map((member) => ({
|
|
|
|
|
|
id: member.id,
|
|
|
|
|
|
userId: member.userId,
|
|
|
|
|
|
username: member.user.username,
|
|
|
|
|
|
avatar: member.user.avatar,
|
|
|
|
|
|
nickname: member.nickname,
|
|
|
|
|
|
role: member.role,
|
|
|
|
|
|
joinedAt: member.joinedAt,
|
|
|
|
|
|
})),
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 缓存结果
|
|
|
|
|
|
this.cacheService.set(id, result, {
|
|
|
|
|
|
prefix: this.CACHE_PREFIX,
|
|
|
|
|
|
ttl: this.CACHE_TTL,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取用户的小组列表
|
|
|
|
|
|
*/
|
|
|
|
|
|
async findUserGroups(userId: string) {
|
|
|
|
|
|
const members = await this.groupMemberRepository.find({
|
|
|
|
|
|
where: { userId },
|
2026-01-28 13:03:28 +08:00
|
|
|
|
relations: ["group", "group.owner"],
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
return members.map((member) => ({
|
|
|
|
|
|
...member.group,
|
|
|
|
|
|
myRole: member.role,
|
|
|
|
|
|
myNickname: member.nickname,
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 更新小组信息
|
|
|
|
|
|
*/
|
2026-01-28 13:03:28 +08:00
|
|
|
|
async update(
|
|
|
|
|
|
userId: string,
|
|
|
|
|
|
groupId: string,
|
|
|
|
|
|
updateGroupDto: UpdateGroupDto,
|
|
|
|
|
|
) {
|
|
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: groupId },
|
|
|
|
|
|
});
|
2026-01-28 10:42:06 +08:00
|
|
|
|
|
|
|
|
|
|
if (!group) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.GROUP_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.GROUP_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查权限(只有组长和管理员可以修改)
|
|
|
|
|
|
await this.checkPermission(userId, groupId, [
|
|
|
|
|
|
GroupMemberRole.OWNER,
|
|
|
|
|
|
GroupMemberRole.ADMIN,
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
Object.assign(group, updateGroupDto);
|
|
|
|
|
|
await this.groupRepository.save(group);
|
|
|
|
|
|
|
|
|
|
|
|
// 清除缓存
|
|
|
|
|
|
this.cacheService.del(groupId, { prefix: this.CACHE_PREFIX });
|
|
|
|
|
|
|
|
|
|
|
|
return this.findOne(groupId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 设置成员角色
|
|
|
|
|
|
*/
|
|
|
|
|
|
async updateMemberRole(
|
|
|
|
|
|
userId: string,
|
|
|
|
|
|
groupId: string,
|
|
|
|
|
|
targetUserId: string,
|
|
|
|
|
|
role: GroupMemberRole,
|
|
|
|
|
|
) {
|
|
|
|
|
|
// 只有组长可以设置管理员
|
|
|
|
|
|
await this.checkPermission(userId, groupId, [GroupMemberRole.OWNER]);
|
|
|
|
|
|
|
|
|
|
|
|
const member = await this.groupMemberRepository.findOne({
|
|
|
|
|
|
where: { groupId, userId: targetUserId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!member) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.NOT_IN_GROUP,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "该用户不在小组中",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不能修改组长角色
|
|
|
|
|
|
if (member.role === GroupMemberRole.OWNER) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "不能修改组长角色",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
member.role = role;
|
|
|
|
|
|
await this.groupMemberRepository.save(member);
|
|
|
|
|
|
|
2026-01-28 13:03:28 +08:00
|
|
|
|
return { message: "角色设置成功" };
|
2026-01-28 10:42:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 踢出成员
|
|
|
|
|
|
*/
|
|
|
|
|
|
async kickMember(userId: string, groupId: string, targetUserId: string) {
|
|
|
|
|
|
// 组长和管理员可以踢人
|
|
|
|
|
|
await this.checkPermission(userId, groupId, [
|
|
|
|
|
|
GroupMemberRole.OWNER,
|
|
|
|
|
|
GroupMemberRole.ADMIN,
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
const member = await this.groupMemberRepository.findOne({
|
|
|
|
|
|
where: { groupId, userId: targetUserId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!member) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.NOT_IN_GROUP,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "该用户不在小组中",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 不能踢出组长
|
|
|
|
|
|
if (member.role === GroupMemberRole.OWNER) {
|
|
|
|
|
|
throw new BadRequestException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "不能踢出组长",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await this.groupMemberRepository.remove(member);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新小组成员数
|
2026-01-28 13:03:28 +08:00
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: groupId },
|
|
|
|
|
|
});
|
2026-01-28 10:42:06 +08:00
|
|
|
|
if (group) {
|
|
|
|
|
|
group.currentMembers = Math.max(0, group.currentMembers - 1);
|
|
|
|
|
|
await this.groupRepository.save(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-28 13:03:28 +08:00
|
|
|
|
return { message: "成员已移除" };
|
2026-01-28 10:42:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 解散小组
|
|
|
|
|
|
*/
|
|
|
|
|
|
async disband(userId: string, groupId: string) {
|
2026-01-28 13:03:28 +08:00
|
|
|
|
const group = await this.groupRepository.findOne({
|
|
|
|
|
|
where: { id: groupId },
|
|
|
|
|
|
});
|
2026-01-28 10:42:06 +08:00
|
|
|
|
|
|
|
|
|
|
if (!group) {
|
|
|
|
|
|
throw new NotFoundException({
|
|
|
|
|
|
code: ErrorCode.GROUP_NOT_FOUND,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.GROUP_NOT_FOUND],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 只有组长可以解散
|
|
|
|
|
|
if (group.ownerId !== userId) {
|
|
|
|
|
|
throw new ForbiddenException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
2026-01-28 13:03:28 +08:00
|
|
|
|
message: "只有组长可以解散小组",
|
2026-01-28 10:42:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
group.isActive = false;
|
|
|
|
|
|
await this.groupRepository.save(group);
|
|
|
|
|
|
|
2026-01-28 13:03:28 +08:00
|
|
|
|
return { message: "小组已解散" };
|
2026-01-28 10:42:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查权限
|
|
|
|
|
|
*/
|
|
|
|
|
|
private async checkPermission(
|
|
|
|
|
|
userId: string,
|
|
|
|
|
|
groupId: string,
|
|
|
|
|
|
allowedRoles: GroupMemberRole[],
|
|
|
|
|
|
) {
|
|
|
|
|
|
const member = await this.groupMemberRepository.findOne({
|
|
|
|
|
|
where: { groupId, userId },
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!member) {
|
|
|
|
|
|
throw new ForbiddenException({
|
|
|
|
|
|
code: ErrorCode.NOT_IN_GROUP,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.NOT_IN_GROUP],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!allowedRoles.includes(member.role)) {
|
|
|
|
|
|
throw new ForbiddenException({
|
|
|
|
|
|
code: ErrorCode.NO_PERMISSION,
|
|
|
|
|
|
message: ErrorMessage[ErrorCode.NO_PERMISSION],
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|