-
-
Notifications
You must be signed in to change notification settings - Fork 29
Expand file tree
/
Copy pathClanService.java
More file actions
148 lines (124 loc) · 5.47 KB
/
ClanService.java
File metadata and controls
148 lines (124 loc) · 5.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package com.faforever.api.clan;
import com.faforever.api.clan.result.ClanResult;
import com.faforever.api.clan.result.InvitationResult;
import com.faforever.api.clan.result.PlayerResult;
import com.faforever.api.config.FafApiProperties;
import com.faforever.api.data.domain.Clan;
import com.faforever.api.data.domain.ClanMembership;
import com.faforever.api.data.domain.Player;
import com.faforever.api.error.ApiException;
import com.faforever.api.error.Error;
import com.faforever.api.error.ErrorCode;
import com.faforever.api.error.ProgrammingError;
import com.faforever.api.player.PlayerRepository;
import com.faforever.api.player.PlayerService;
import com.faforever.api.security.JwtService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.security.core.Authentication;
import org.springframework.security.jwt.Jwt;
import org.springframework.stereotype.Service;
import javax.inject.Inject;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
@Service
public class ClanService {
private final ClanRepository clanRepository;
private final PlayerRepository playerRepository;
private final FafApiProperties fafApiProperties;
private final JwtService jwtService;
private final ObjectMapper objectMapper;
private final PlayerService playerService;
private final ClanMembershipRepository clanMembershipRepository;
@Inject
public ClanService(ClanRepository clanRepository,
PlayerRepository playerRepository,
FafApiProperties fafApiProperties,
JwtService jwtService,
PlayerService playerService,
ClanMembershipRepository clanMembershipRepository,
ObjectMapper objectMapper) {
this.clanRepository = clanRepository;
this.playerRepository = playerRepository;
this.fafApiProperties = fafApiProperties;
this.jwtService = jwtService;
this.playerService = playerService;
this.clanMembershipRepository = clanMembershipRepository;
this.objectMapper = objectMapper;
}
@SneakyThrows
Clan create(String name, String tag, String description, Player creator) {
if (!creator.getClanMemberships().isEmpty()) {
throw new ApiException(new Error(ErrorCode.CLAN_CREATE_CREATOR_IS_IN_A_CLAN));
}
if (clanRepository.findOneByName(name).isPresent()) {
throw new ApiException(new Error(ErrorCode.CLAN_NAME_EXISTS, name));
}
if (clanRepository.findOneByTag(tag).isPresent()) {
throw new ApiException(new Error(ErrorCode.CLAN_TAG_EXISTS, tag));
}
Clan clan = new Clan();
clan.setName(name);
clan.setTag(tag);
clan.setDescription(description);
clan.setFounder(creator);
clan.setLeader(creator);
ClanMembership membership = new ClanMembership();
membership.setClan(clan);
membership.setPlayer(creator);
clan.setMemberships(Collections.singletonList(membership));
// clan membership is saved over cascading, otherwise validation will fail
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) {
Clan clan = clanRepository.findById(clanId)
.orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_NOT_EXISTS, clanId)));
if (requester.getId() != clan.getLeader().getId()) {
throw new ApiException(new Error(ErrorCode.CLAN_NOT_LEADER, clanId));
}
Player newMember = clan.getIsOpen() ? null :
playerRepository.findById(newMemberId)
.orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_GENERATE_LINK_PLAYER_NOT_FOUND, newMemberId)));
long expire = clan.getIsOpen() ? 0 :
Instant.now()
.plus(fafApiProperties.getClan().getInviteLinkExpireDurationMinutes(), ChronoUnit.MINUTES)
.toEpochMilli();
InvitationResult result = new InvitationResult(expire,
ClanResult.of(clan),
PlayerResult.of(newMember));
return jwtService.sign(result);
}
@SneakyThrows
void acceptPlayerInvitationToken(String stringToken, Authentication authentication) {
Jwt token = jwtService.decodeAndVerify(stringToken);
InvitationResult invitation = objectMapper.readValue(token.getClaims(), InvitationResult.class);
if (invitation.isExpired()) {
throw new ApiException(new Error(ErrorCode.CLAN_ACCEPT_TOKEN_EXPIRE));
}
final Integer clanId = invitation.getClan().getId();
Player player = playerService.getPlayer(authentication);
Clan clan = clanRepository.findById(clanId)
.orElseThrow(() -> new ApiException(new Error(ErrorCode.CLAN_NOT_EXISTS, clanId)));
Player newMember = clan.getIsOpen() ? null :
playerRepository.findById(invitation.getNewMember().getId())
.orElseThrow(() -> new ProgrammingError("ClanMember does not exist: " + invitation.getNewMember().getId()));
if (!invitation.getClan().getIsOpen() && player.getId() != newMember.getId()) {
throw new ApiException(new Error(ErrorCode.CLAN_ACCEPT_WRONG_PLAYER));
}
if (newMember.getClan() != null) {
throw new ApiException(new Error(ErrorCode.CLAN_ACCEPT_PLAYER_IN_A_CLAN));
}
ClanMembership membership = new ClanMembership();
membership.setClan(clan);
membership.setPlayer(player);
clanMembershipRepository.save(membership);
}
}