@@ -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