diff --git a/fluxer_api/src/api/guild/services/GuildModerationService.ts b/fluxer_api/src/api/guild/services/GuildModerationService.ts index b511969d7..e6c325bae 100644 --- a/fluxer_api/src/api/guild/services/GuildModerationService.ts +++ b/fluxer_api/src/api/guild/services/GuildModerationService.ts @@ -8,6 +8,7 @@ import {MissingPermissionsError} from '@fluxer/errors/src/domains/core/MissingPe import {BannedFromGuildError} from '@fluxer/errors/src/domains/guild/BannedFromGuildError'; import {IpBannedFromGuildError} from '@fluxer/errors/src/domains/guild/IpBannedFromGuildError'; import {UnknownGuildMemberError} from '@fluxer/errors/src/domains/guild/UnknownGuildMemberError'; +import {UnknownUserError} from '@fluxer/errors/src/domains/user/UnknownUserError'; import {isSameIpDecisionMatch} from '@fluxer/ip_utils/src/IpAddress'; import type {GuildBanResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas'; import type {IpInfoService} from '@pkgs/geoip/src/IpInfoService'; @@ -62,6 +63,10 @@ export class GuildModerationService { }); if (!hasPermission) throw new MissingPermissionsError(); if (userId === targetId) throw new UnknownGuildMemberError(); + const targetUser = await this.userRepository.findUnique(targetId); + if (!targetUser) { + throw new UnknownUserError(); + } const targetMember = await this.guildRepository.getMember(guildId, targetId); if (targetMember) { const canManage = await this.gatewayService.checkTargetMember({guildId, userId, targetUserId: targetId}); @@ -74,9 +79,8 @@ export class GuildModerationService { days: deleteMessageDays, }); } - const targetUser = await this.userRepository.findUnique(targetId); - const targetIp = targetUser?.lastActiveIp || null; - const targetEmail = targetUser?.email?.toLowerCase() || null; + const targetIp = targetUser.lastActiveIp || null; + const targetEmail = targetUser.email?.toLowerCase() || null; let expiresAt: Date | null = null; if (banDurationSeconds && banDurationSeconds > 0) { expiresAt = new Date(Date.now() + banDurationSeconds * 1000); diff --git a/fluxer_api/src/api/guild/tests/GuildMemberManagement.test.ts b/fluxer_api/src/api/guild/tests/GuildMemberManagement.test.ts index 9ae3ae0ff..24f0ca9fc 100644 --- a/fluxer_api/src/api/guild/tests/GuildMemberManagement.test.ts +++ b/fluxer_api/src/api/guild/tests/GuildMemberManagement.test.ts @@ -186,6 +186,24 @@ describe('Guild Member Management', () => { .expect(HTTP_STATUS.NO_CONTENT) .execute(); }); + test('should ban non-member from guild', async () => { + const {owner, guild} = await setupTestGuildWithMembers(harness, 1); + const nonMember = await createTestAccount(harness); + await createBuilder(harness, owner.token) + .put(`/guilds/${guild.id}/bans/${nonMember.userId}`) + .body({}) + .expect(HTTP_STATUS.NO_CONTENT) + .execute(); + }); + test('should disallow banning nonexistent user from guild', async () => { + const {owner, guild} = await setupTestGuildWithMembers(harness, 1); + const nonExistentId = '1234567890123456789'; + await createBuilder(harness, owner.token) + .put(`/guilds/${guild.id}/bans/${nonExistentId}`) + .body({}) + .expect(HTTP_STATUS.NOT_FOUND) + .execute(); + }); test('should fall back to audit log reason header when ban reason is omitted', async () => { const {owner, members, guild} = await setupTestGuildWithMembers(harness, 1); const member = members[0];