diff --git a/server/services/core/group/group.service.ts b/server/services/core/group/group.service.ts index 95dc207d..10c83ce8 100644 --- a/server/services/core/group/group.service.ts +++ b/server/services/core/group/group.service.ts @@ -190,6 +190,12 @@ class GroupService extends TcService { muteMs: 'number', }, }); + this.registerAction('deleteGroupMember', this.deleteGroupMember, { + params: { + groupId: 'string', + memberId: 'string', + }, + }); } /** @@ -968,6 +974,50 @@ class GroupService extends TcService { } } + async deleteGroupMember( + ctx: TcContext<{ + groupId: string; + memberId: string; + }> + ) { + const { groupId, memberId } = ctx.params; + const userId = ctx.meta.userId; + const t = ctx.meta.t; + + const [hasPermission] = await call(ctx).checkUserPermissions( + groupId, + userId, + [PERMISSION.core.manageUser] + ); + if (!hasPermission) { + throw new NoPermissionError(t('没有操作权限')); + } + + if (String(memberId) === String(userId)) { + throw new Error(t('不允许踢出自己')); + } + + const group = await this.adapter.model.findByIdAndUpdate( + groupId, + { + $pull: { + members: { + userId: String(memberId), + }, + }, + }, + { new: true } + ); + + this.notifyGroupInfoUpdate(ctx, group); + + const memberInfo = await call(ctx).getUserInfo(memberId); + await call(ctx).addGroupSystemMessage( + groupId, + `${ctx.meta.user.nickname} 将 ${memberInfo.nickname} 移出了本群组` + ); + } + /** * 发送通知群组信息发生变更 * diff --git a/server/test/integration/group/group.spec.ts b/server/test/integration/group/group.spec.ts index bd111818..ecc78bc8 100644 --- a/server/test/integration/group/group.spec.ts +++ b/server/test/integration/group/group.spec.ts @@ -44,6 +44,9 @@ describe('Test "group" service', () => { if (actionName === 'group.getUserAllPermissions') { return [PERMISSION.core.owner]; } + if (actionName === 'user.getUserInfo') { + return { nickname: 'test-nickname' }; + } }, }); @@ -548,4 +551,50 @@ describe('Test "group" service', () => { muteUntil ); }); + + test('Test "group.deleteGroupMember"', async () => { + const userId = new Types.ObjectId(); + const userId2 = new Types.ObjectId(); + const testGroup = await insertTestData( + createTestGroup(userId, { + members: [ + { + roles: [], + userId: userId, + }, + { + roles: [], + userId: userId2, + }, + ], + }) + ); + + const beforeGroup = await service.adapter.model.findById(testGroup._id); + + expect(beforeGroup.members.map((m) => String(m.userId))).toEqual([ + String(userId), + String(userId2), + ]); + + await broker.call( + 'group.deleteGroupMember', + { + groupId: String(testGroup._id), + memberId: String(userId2), + }, + { + meta: { + userId: String(userId), + user: { nickname: 'foo' }, + }, + } + ); + + const finalGroup = await service.adapter.model.findById(testGroup._id); + + expect(finalGroup.members.map((m) => String(m.userId))).toEqual([ + String(userId), + ]); + }); });