Skip to content

Commit 17da62d

Browse files
committed
Remove complexity errors from community invite service
1 parent d5bd068 commit 17da62d

File tree

4 files changed

+130
-51
lines changed

4 files changed

+130
-51
lines changed

src/main/java/org/spacehub/entities/Community/CommunityInvite.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,20 @@ public class CommunityInvite {
3131
@Column(unique = true, nullable = false)
3232
private String inviteCode;
3333

34+
@Builder.Default
3435
private int maxUses = 10;
36+
37+
@Builder.Default
3538
private int uses = 0;
36-
private LocalDateTime expiresAt;
39+
40+
@Builder.Default
41+
private LocalDateTime expiresAt = null;
3742

3843
@Enumerated(EnumType.STRING)
44+
@Builder.Default
3945
private InviteStatus status = InviteStatus.ACTIVE;
4046

47+
@Builder.Default
4148
private LocalDateTime createdAt = LocalDateTime.now();
4249

4350
private UUID notificationReference;

src/main/java/org/spacehub/service/chatRoom/ChatMessageQueue.java

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
import org.spacehub.entities.ChatRoom.ChatMessage;
55
import org.spacehub.entities.ChatRoom.ChatRoom;
66
import org.spacehub.entities.ChatRoom.NewChatRoom;
7-
import org.spacehub.handler.ChatWebSocketHandler;
87
import org.spacehub.service.chatRoom.chatroomInterfaces.IChatMessageQueue;
9-
import org.springframework.beans.factory.annotation.Autowired;
10-
import org.springframework.context.annotation.Lazy;
118
import org.springframework.scheduling.annotation.Scheduled;
129
import org.springframework.stereotype.Service;
1310

@@ -21,16 +18,9 @@ public class ChatMessageQueue implements IChatMessageQueue {
2118
private final Map<String, List<ChatMessage>> pendingByRoom = new ConcurrentHashMap<>();
2219

2320
private final ChatMessageService chatMessageService;
24-
private ChatWebSocketHandler chatWebSocketHandler;
2521

2622
private static final int FLUSH_BATCH_SIZE = 10;
2723

28-
@Autowired
29-
@Lazy
30-
public void setChatWebSocketHandler(ChatWebSocketHandler handler) {
31-
this.chatWebSocketHandler = handler;
32-
}
33-
3424
public synchronized void enqueue(ChatMessage message) {
3525
pendingByRoom.computeIfAbsent(message.getRoomCode(), k -> Collections.synchronizedList(new ArrayList<>()))
3626
.add(message);
@@ -61,13 +51,15 @@ private synchronized void flushRoom(String roomCode) {
6151
chatMessageService.saveAll(batch);
6252
}
6353
catch (Exception e) {
64-
pendingByRoom.computeIfAbsent(roomCode, k -> Collections.synchronizedList(new ArrayList<>())).addAll(batch);
54+
pendingByRoom.computeIfAbsent(roomCode, k ->
55+
Collections.synchronizedList(new ArrayList<>())).addAll(batch);
6556
}
6657
}
6758

6859
public synchronized boolean deleteMessageByUuid(String messageUuid) {
6960
boolean removedFromMemory = pendingByRoom.values().stream()
70-
.anyMatch(list -> list.removeIf(m -> Objects.equals(m.getMessageUuid(), messageUuid)));
61+
.anyMatch(list -> list.removeIf(m ->
62+
Objects.equals(m.getMessageUuid(), messageUuid)));
7163

7264
boolean removedFromDb = chatMessageService.deleteMessageByUuid(messageUuid);
7365

src/main/java/org/spacehub/service/chatRoom/ChatMessageService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public boolean deleteMessageByUuid(String messageUuid) {
4545
return chatMessageRepository.findByMessageUuid(messageUuid)
4646
.map(m -> {
4747
chatMessageRepository.deleteByMessageUuid(messageUuid);
48-
return true;}).orElse(false);
48+
return true;
49+
}).orElse(false);
4950
}
5051
}

src/main/java/org/spacehub/service/community/CommunityInviteService.java

Lines changed: 116 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -45,71 +45,142 @@ private String generateInviteCode() {
4545
}
4646

4747
public ApiResponse<CommunityInviteResponseDTO> createInvite(UUID communityId, CommunityInviteRequestDTO request) {
48+
ValidationContext ctx = new ValidationContext();
49+
ApiResponse<CommunityInviteResponseDTO> validationError = validateCreateInviteRequest(communityId, request, ctx);
50+
if (validationError != null) {
51+
return validationError;
52+
}
53+
54+
CommunityInvite invite = buildInvite(communityId, request.getInviterEmail(), request.getMaxUses(),
55+
request.getExpiresInHours());
56+
inviteRepository.save(invite);
57+
58+
CommunityInviteResponseDTO response = toDto(invite, communityId);
59+
return new ApiResponse<>(200, "Invite created successfully", response);
60+
}
61+
62+
private static class ValidationContext {
63+
Community community;
64+
User inviter;
65+
CommunityUser membership;
66+
}
67+
68+
private ApiResponse<CommunityInviteResponseDTO> validateCreateInviteRequest(UUID communityId,
69+
CommunityInviteRequestDTO request,
70+
ValidationContext ctx) {
71+
72+
ApiResponse<CommunityInviteResponseDTO> err;
73+
74+
err = validateRequestShape(request);
75+
if (err != null) {
76+
return err;
77+
}
78+
79+
err = loadCommunity(communityId, ctx);
80+
if (err != null) {
81+
return err;
82+
}
83+
84+
err = loadInviter(request.getInviterEmail(), ctx);
85+
if (err != null) {
86+
return err;
87+
}
88+
89+
err = loadMembership(communityId, ctx);
90+
if (err != null) {
91+
return err;
92+
}
93+
94+
err = authorizeInviter(ctx);
95+
if (err != null) {
96+
return err;
97+
}
98+
99+
err = validateLimits(request);
100+
return err;
101+
102+
}
103+
104+
private ApiResponse<CommunityInviteResponseDTO> validateRequestShape(CommunityInviteRequestDTO request) {
48105
if (request == null || request.getInviterEmail() == null || request.getInviterEmail().isBlank()) {
49106
return new ApiResponse<>(400, "inviterEmail is required", null);
50107
}
108+
return null;
109+
}
51110

111+
private ApiResponse<CommunityInviteResponseDTO> loadCommunity(UUID communityId, ValidationContext ctx) {
52112
Community community = communityRepository.findById(communityId).orElse(null);
53113
if (community == null) {
54114
return new ApiResponse<>(404, "Community not found", null);
55115
}
116+
ctx.community = community;
117+
return null;
118+
}
56119

57-
User inviter = userRepository.findByEmail(request.getInviterEmail()).orElse(null);
120+
private ApiResponse<CommunityInviteResponseDTO> loadInviter(String inviterEmail, ValidationContext ctx) {
121+
User inviter = userRepository.findByEmail(inviterEmail).orElse(null);
58122
if (inviter == null) {
59123
return new ApiResponse<>(404, "Inviter not found", null);
60124
}
125+
ctx.inviter = inviter;
126+
return null;
127+
}
61128

129+
private ApiResponse<CommunityInviteResponseDTO> loadMembership(UUID communityId, ValidationContext ctx) {
62130
CommunityUser membership = communityUserRepository
63-
.findByCommunityIdAndUserId(communityId, inviter.getId())
64-
.orElse(null);
65-
131+
.findByCommunityIdAndUserId(communityId, ctx.inviter.getId())
132+
.orElse(null);
66133
if (membership == null) {
67134
return new ApiResponse<>(403, "You are not a member of this community", null);
68135
}
136+
ctx.membership = membership;
137+
return null;
138+
}
69139

70-
Role role = membership.getRole();
71-
boolean hasPermission = (role == Role.ADMIN || role == Role.WORKSPACE_OWNER);
72-
73-
if (!hasPermission) {
140+
private ApiResponse<CommunityInviteResponseDTO> authorizeInviter(ValidationContext ctx) {
141+
Role role = ctx.membership.getRole();
142+
if (!(role == Role.ADMIN || role == Role.WORKSPACE_OWNER)) {
74143
return new ApiResponse<>(403, "Only admins or owners can create invites", null);
75144
}
145+
return null;
146+
}
76147

148+
private ApiResponse<CommunityInviteResponseDTO> validateLimits(CommunityInviteRequestDTO request) {
77149
if (request.getMaxUses() <= 0) {
78150
return new ApiResponse<>(400, "maxUses must be >= 1", null);
79151
}
80-
81152
if (request.getExpiresInHours() <= 0) {
82153
return new ApiResponse<>(400, "expiresInHours must be >= 1", null);
83154
}
155+
return null;
156+
}
84157

85-
CommunityInvite invite = CommunityInvite.builder()
86-
.communityId(communityId)
87-
.inviterEmail(request.getInviterEmail())
88-
.maxUses(request.getMaxUses())
89-
.inviteCode(generateInviteCode())
90-
.expiresAt(LocalDateTime.now().plusHours(request.getExpiresInHours()))
91-
.status(InviteStatus.ACTIVE)
92-
.build();
93-
94-
inviteRepository.save(invite);
95-
96-
String inviteLink = "https://codewithketan.me/invite/"
97-
+ communityId + "/" + invite.getInviteCode();
98-
99-
CommunityInviteResponseDTO response = CommunityInviteResponseDTO.builder()
100-
.inviteCode(invite.getInviteCode())
101-
.inviteLink(inviteLink)
102-
.communityId(communityId)
103-
.inviterEmail(invite.getInviterEmail())
104-
.maxUses(invite.getMaxUses())
105-
.uses(invite.getUses())
106-
.expiresAt(invite.getExpiresAt())
107-
.status(invite.getStatus().name())
108-
.build();
158+
private CommunityInvite buildInvite(UUID communityId, String inviterEmail, int maxUses, int expiresInHours) {
159+
return CommunityInvite.builder()
160+
.communityId(communityId)
161+
.inviterEmail(inviterEmail)
162+
.maxUses(maxUses)
163+
.inviteCode(generateInviteCode())
164+
.expiresAt(LocalDateTime.now().plusHours(expiresInHours))
165+
.status(InviteStatus.ACTIVE)
166+
.build();
167+
}
109168

110-
return new ApiResponse<>(200, "Invite created successfully", response);
169+
private CommunityInviteResponseDTO toDto(CommunityInvite invite, UUID communityId) {
170+
String inviteLink = "https://codewithketan.me/invite/" + communityId + "/" + invite.getInviteCode();
171+
return CommunityInviteResponseDTO.builder()
172+
.inviteCode(invite.getInviteCode())
173+
.inviteLink(inviteLink)
174+
.communityId(communityId)
175+
.inviterEmail(invite.getInviterEmail())
176+
.maxUses(invite.getMaxUses())
177+
.uses(invite.getUses())
178+
.expiresAt(invite.getExpiresAt())
179+
.status(invite.getStatus().name())
180+
.build();
111181
}
112182

183+
113184
@Override
114185
public ApiResponse<?> acceptInvite(CommunityInviteAcceptDTO request) {
115186

@@ -173,16 +244,24 @@ public ApiResponse<?> acceptInvite(CommunityInviteAcceptDTO request) {
173244
}
174245

175246
private String extractInviteCode(String rawCode) {
176-
return rawCode.contains("/") ? rawCode.substring(rawCode.lastIndexOf("/") + 1) : rawCode;
247+
int i = rawCode.lastIndexOf('/');
248+
if (i == -1) {
249+
return rawCode;
250+
}
251+
return rawCode.substring(i + 1);
177252
}
178253

179254
private CommunityInvite validateInvite(String inviteCode, UUID communityId) {
180255
Optional<CommunityInvite> inviteOpt = inviteRepository.findByInviteCode(inviteCode);
181-
if (inviteOpt.isEmpty()) return null;
256+
if (inviteOpt.isEmpty()) {
257+
return null;
258+
}
182259

183260
CommunityInvite invite = inviteOpt.get();
184261

185-
if (!invite.getCommunityId().equals(communityId)) return null;
262+
if (!invite.getCommunityId().equals(communityId)) {
263+
return null;
264+
}
186265

187266
if (invite.getExpiresAt().isBefore(LocalDateTime.now())) {
188267
invite.setStatus(InviteStatus.EXPIRED);

0 commit comments

Comments
 (0)