diff --git a/src/main/java/com/faforever/api/clan/ClanService.java b/src/main/java/com/faforever/api/clan/ClanService.java index ba7d54a73..bfb135ec6 100644 --- a/src/main/java/com/faforever/api/clan/ClanService.java +++ b/src/main/java/com/faforever/api/clan/ClanService.java @@ -83,6 +83,12 @@ Clan create(String name, String tag, String description, Player creator) { clanRepository.save(clan); return clan; } + + @SneakyThrows + String generatePlayerInvitationToken(Player requester, int clanId) { + // Playerless invitation + return generatePlayerInvitationToken(requester, 0, int clanId); + } @SneakyThrows String generatePlayerInvitationToken(Player requester, int newMemberId, int clanId) { @@ -93,12 +99,14 @@ String generatePlayerInvitationToken(Player requester, int newMemberId, int clan throw new ApiException(new Error(ErrorCode.CLAN_NOT_LEADER, clanId)); } - Player newMember = playerRepository.findById(newMemberId) - .orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_GENERATE_LINK_PLAYER_NOT_FOUND, newMemberId))); + Player newMember = clan.getIsOpen() ? null : + playerRepository.findById(newMemberId) + .orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_GENERATE_LINK_PLAYER_NOT_FOUND, newMemberId))); - long expire = Instant.now() - .plus(fafApiProperties.getClan().getInviteLinkExpireDurationMinutes(), ChronoUnit.MINUTES) - .toEpochMilli(); + long expire = clan.getIsOpen() ? 0 : + Instant.now() + .plus(fafApiProperties.getClan().getInviteLinkExpireDurationMinutes(), ChronoUnit.MINUTES) + .toEpochMilli(); InvitationResult result = new InvitationResult(expire, ClanResult.of(clan), @@ -120,11 +128,12 @@ void acceptPlayerInvitationToken(String stringToken, Authentication authenticati Clan clan = clanRepository.findById(clanId) .orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_NOT_EXISTS, clanId))); - Player newMember = playerRepository.findById(invitation.getNewMember().getId()) - .orElseThrow(() -> new ProgrammingError("ClanMember does not exist: " + invitation.getNewMember().getId())); + Player newMember = clan.getIsOpen() ? null : + playerRepository.findById(invitation.getNewMember().getId()) + .orElseThrow(() -> new ProgrammingError("ClanMember does not exist: " + invitation.getNewMember().getId())); - if (player.getId() != newMember.getId()) { + if (!invitation.getClan().getIsOpen() && player.getId() != newMember.getId()) { throw new ApiException(new Error(ErrorCode.CLAN_ACCEPT_WRONG_PLAYER)); } if (newMember.getClan() != null) { @@ -133,7 +142,7 @@ void acceptPlayerInvitationToken(String stringToken, Authentication authenticati ClanMembership membership = new ClanMembership(); membership.setClan(clan); - membership.setPlayer(newMember); + membership.setPlayer(player); clanMembershipRepository.save(membership); } } diff --git a/src/main/java/com/faforever/api/data/domain/Clan.java b/src/main/java/com/faforever/api/data/domain/Clan.java index eb58b749d..b979316b8 100644 --- a/src/main/java/com/faforever/api/data/domain/Clan.java +++ b/src/main/java/com/faforever/api/data/domain/Clan.java @@ -46,6 +46,7 @@ public class Clan extends AbstractEntity implements OwnableEntity { private String description; private String tagColor; private String websiteUrl; + private boolean isOpen; private List memberships; @Column(name = "name") @@ -107,4 +108,11 @@ public String getWebsiteUrl() { public Login getEntityOwner() { return getLeader(); } + + @Column(name = "isOpen") + @NotNull + @UpdatePermission(expression = IsEntityOwner.EXPRESSION) + public bool getIsOpen() { + return isOpen; + } } diff --git a/src/test/java/com/faforever/api/clan/ClanServiceTest.java b/src/test/java/com/faforever/api/clan/ClanServiceTest.java index 10fbee2b0..b1adb6674 100644 --- a/src/test/java/com/faforever/api/clan/ClanServiceTest.java +++ b/src/test/java/com/faforever/api/clan/ClanServiceTest.java @@ -144,6 +144,7 @@ public void createClanSuccessful() { assertEquals(creator, clanCaptor.getValue().getFounder()); assertEquals(1, clanCaptor.getValue().getMemberships().size()); assertEquals(creator, clanCaptor.getValue().getMemberships().get(0).getPlayer()); + assertEquals(false, clanCaptor.getValue().getIsOpen()); } @Test @@ -231,6 +232,35 @@ public void generatePlayerInvitationToken() throws IOException { assertEquals(clan.getName(), captor.getValue().getClan().getName()); } + @Test + public void generatePlayerOpenInvitationToken() throws IOException { + Player requester = new Player(); + requester.setId(1); + + Clan clan = ClanFactory.builder().leader(requester).build().setIsOpen(false); + + FafApiProperties props = new FafApiProperties(); + + when(clanRepository.findById(clan.getId())).thenReturn(Optional.of(clan)); + when(fafApiProperties.getClan()).thenReturn(props.getClan()); + + instance.generatePlayerInvitationToken(requester, clan.getId()); + + // What do i do with this?? + // Invitation result should be modified to accept null players but i have no IDE here so navigating is a pain + /* + ArgumentCaptor captor = ArgumentCaptor.forClass(InvitationResult.class); + verify(jwtService, Mockito.times(1)).sign(captor.capture()); + assertEquals(captor.getValue().getExpire(), 0); + assertEquals(null, captor.getValue().getNewMember()); + */ + assertEquals(clan.getId(), getValue().getClan().getId()); + /* + assertEquals(clan.getTag(), captor.getValue().getClan().getTag()); + assertEquals(clan.getName(), captor.getValue().getClan().getName()); + */ + } + @Test public void acceptPlayerInvitationTokenExpire() throws IOException { String stringToken = "1234"; @@ -249,6 +279,26 @@ public void acceptPlayerInvitationTokenExpire() throws IOException { } verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); } + + @Test + public void acceptPlayerOpenInvitationCannotExpire() throws IOException { + // Why is the clan passed nowhere here?? How do I make it not expire if the clan is open since no clan is passed as part of the test? + String stringToken = "1234"; + long expire = System.currentTimeMillis(); + Jwt jwtToken = Mockito.mock(Jwt.class); + + when(jwtToken.getClaims()).thenReturn( + String.format("{\"expire\":%s}", expire)); + when(jwtService.decodeAndVerify(any())).thenReturn(jwtToken); + + try { + instance.acceptPlayerInvitationToken(stringToken, null); + fail(); + } catch (ApiException e) { + assertThat(e, hasErrorCode(ErrorCode.CLAN_ACCEPT_TOKEN_EXPIRE)); + } + verify(clanMembershipRepository, Mockito.never()).save(any(ClanMembership.class)); + } @Test public void acceptPlayerInvitationTokenInvalidClan() throws IOException {