From d6947ce6d187d98d9b4b247e794d5a5c0283074f Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 May 2026 16:47:36 +0200 Subject: [PATCH] fix(invites): deduplicate groupIds before size check in createInvite Client-submitted duplicate UUIDs were causing a false GROUP_NOT_FOUND: size(deduplicated_db_result)==1 != size(submitted)==2. Deduplicate input with HashSet before calling findGroupsByIds so the size comparison is always against unique IDs. Co-Authored-By: Claude Sonnet 4.6 --- .../familienarchiv/user/InviteService.java | 5 +++-- .../familienarchiv/user/InviteServiceTest.java | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/user/InviteService.java b/backend/src/main/java/org/raddatz/familienarchiv/user/InviteService.java index 1836d7e1..4cf89625 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/user/InviteService.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/user/InviteService.java @@ -52,8 +52,9 @@ public class InviteService { public InviteToken createInvite(CreateInviteRequest dto, AppUser creator) { Set groupIds = new HashSet<>(); if (dto.getGroupIds() != null && !dto.getGroupIds().isEmpty()) { - List groups = userService.findGroupsByIds(dto.getGroupIds()); - if (groups.size() != dto.getGroupIds().size()) { + Set uniqueIds = new HashSet<>(dto.getGroupIds()); + List groups = userService.findGroupsByIds(new ArrayList<>(uniqueIds)); + if (groups.size() != uniqueIds.size()) { throw DomainException.notFound(ErrorCode.GROUP_NOT_FOUND, "One or more group IDs do not exist"); } groups.forEach(g -> groupIds.add(g.getId())); diff --git a/backend/src/test/java/org/raddatz/familienarchiv/user/InviteServiceTest.java b/backend/src/test/java/org/raddatz/familienarchiv/user/InviteServiceTest.java index 60e87066..df74378a 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/user/InviteServiceTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/user/InviteServiceTest.java @@ -159,7 +159,7 @@ class InviteServiceTest { @Test void createInvite_throwsGroupNotFound_whenSubmittedGroupIdDoesNotExist() { UUID unknownGroupId = UUID.randomUUID(); - when(userService.findGroupsByIds(List.of(unknownGroupId))).thenReturn(List.of()); + when(userService.findGroupsByIds(anyList())).thenReturn(List.of()); CreateInviteRequest req = new CreateInviteRequest(); req.setGroupIds(List.of(unknownGroupId)); @@ -170,6 +170,21 @@ class InviteServiceTest { .isEqualTo(ErrorCode.GROUP_NOT_FOUND); } + @Test + void createInvite_doesNotThrowGroupNotFound_whenDuplicateGroupIdsSubmitted() { + UUID groupId = UUID.randomUUID(); + UserGroup group = UserGroup.builder().id(groupId).name("Familie").build(); + when(inviteTokenRepository.findByCode(anyString())).thenReturn(Optional.empty()); + when(userService.findGroupsByIds(anyList())).thenReturn(List.of(group)); + when(inviteTokenRepository.save(any())).thenAnswer(inv -> inv.getArgument(0)); + + CreateInviteRequest req = new CreateInviteRequest(); + req.setGroupIds(List.of(groupId, groupId)); // same UUID submitted twice + + // before deduplication: size(groups)==1 != size(submitted)==2 → false GROUP_NOT_FOUND + assertThatCode(() -> inviteService.createInvite(req, admin)).doesNotThrowAnyException(); + } + // ─── redeemInvite ───────────────────────────────────────────────────────── @Test