Skip to content

Commit 096518f

Browse files
fix: fix bugs in the endpoint for updating endorsements (#208)
* fix: ensure empty endorsements msg not allowed * fix: add feature-flag in endorsement controller * fix: update service impl to ensure no unauthorized endorsement update, user-not-found bug * fix: enable disabled test cases * fix: disable endorsements update when not in dev mode * fix: run all tests in dev mode, add test case to validate updation is no allowed in non-dev mode * fix: update name of test case * fix: import only used exceptions * fix: update control flow
1 parent 526e35a commit 096518f

File tree

7 files changed

+74
-34
lines changed

7 files changed

+74
-34
lines changed

skill-tree/src/main/java/com/RDS/skilltree/apis/EndorsementsApi.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ public class EndorsementsApi {
2222

2323
@PatchMapping("/{id}")
2424
public ResponseEntity<EndorsementViewModel> update(
25-
@PathVariable Integer id, @Valid @RequestBody UpdateEndorsementViewModel body) {
26-
return new ResponseEntity<>(endorsementService.update(id, body), HttpStatus.OK);
25+
@PathVariable Integer id,
26+
@Valid @RequestBody UpdateEndorsementViewModel body,
27+
@RequestParam(name = "dev", required = false, defaultValue = "false") boolean isDev) {
28+
return new ResponseEntity<>(endorsementService.update(id, body, isDev), HttpStatus.OK);
2729
}
2830
}

skill-tree/src/main/java/com/RDS/skilltree/exceptions/GlobalExceptionHandler.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,11 @@ public ResponseEntity<?> handleEndorsementAlreadyExistsException(
140140
return new ResponseEntity<>(
141141
new GenericResponse<>(ex.getMessage()), HttpStatus.METHOD_NOT_ALLOWED);
142142
}
143+
144+
@ExceptionHandler(IllegalStateException.class)
145+
public ResponseEntity<?> handleIllegalStateException(IllegalStateException ex) {
146+
log.error("IllegalStateException - Error : {}", ex.getMessage());
147+
return new ResponseEntity<>(
148+
new GenericResponse<>(ex.getMessage()), HttpStatus.METHOD_NOT_ALLOWED);
149+
}
143150
}

skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementService.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ public interface EndorsementService {
1010

1111
EndorsementViewModel create(CreateEndorsementViewModel endorsement);
1212

13-
EndorsementViewModel update(Integer endorsementId, UpdateEndorsementViewModel endorsement);
13+
EndorsementViewModel update(
14+
Integer endorsementId, UpdateEndorsementViewModel endorsement, boolean isDev);
1415
}

skill-tree/src/main/java/com/RDS/skilltree/services/EndorsementServiceImplementation.java

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.RDS.skilltree.dtos.RdsGetUserDetailsResDto;
44
import com.RDS.skilltree.exceptions.EndorsementAlreadyExistsException;
55
import com.RDS.skilltree.exceptions.EndorsementNotFoundException;
6+
import com.RDS.skilltree.exceptions.ForbiddenException;
67
import com.RDS.skilltree.exceptions.SelfEndorsementNotAllowedException;
78
import com.RDS.skilltree.exceptions.SkillNotFoundException;
89
import com.RDS.skilltree.models.Endorsement;
@@ -130,30 +131,39 @@ public EndorsementViewModel create(CreateEndorsementViewModel endorsementViewMod
130131
}
131132

132133
@Override
133-
public EndorsementViewModel update(Integer endorsementId, UpdateEndorsementViewModel body) {
134-
Optional<Endorsement> exitingEndorsement = endorsementRepository.findById(endorsementId);
135-
136-
if (exitingEndorsement.isEmpty()) {
137-
log.info(String.format("Endorsement with id: %s not found", endorsementId));
138-
throw new EndorsementNotFoundException(ExceptionMessages.ENDORSEMENT_NOT_FOUND);
134+
public EndorsementViewModel update(
135+
Integer endorsementId, UpdateEndorsementViewModel body, boolean isDev) {
136+
if (isDev) {
137+
Optional<Endorsement> existingEndorsement = endorsementRepository.findById(endorsementId);
138+
139+
if (existingEndorsement.isEmpty()) {
140+
log.info("Endorsement with id: {} not found", endorsementId);
141+
throw new EndorsementNotFoundException(ExceptionMessages.ENDORSEMENT_NOT_FOUND);
142+
}
143+
144+
Endorsement endorsement = existingEndorsement.get();
145+
146+
JwtUser jwtDetails =
147+
(JwtUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
148+
String userId = jwtDetails.getRdsUserId();
149+
150+
if (endorsement.getEndorserId().equals(userId)) {
151+
RdsGetUserDetailsResDto endorseDetails =
152+
rdsService.getUserDetails(endorsement.getEndorseId());
153+
RdsGetUserDetailsResDto endorserDetails = rdsService.getUserDetails(userId);
154+
155+
endorsement.setMessage(body.getMessage());
156+
Endorsement savedEndorsementDetails = endorsementRepository.save(endorsement);
157+
158+
return EndorsementViewModel.toViewModel(
159+
savedEndorsementDetails,
160+
UserViewModel.toViewModel(endorseDetails.getUser()),
161+
UserViewModel.toViewModel(endorserDetails.getUser()));
162+
} else {
163+
log.warn("User: {} is not authorized to update endorsement: {}", userId, endorsementId);
164+
throw new ForbiddenException(ExceptionMessages.UNAUTHORIZED_ENDORSEMENT_UPDATE);
165+
}
139166
}
140-
141-
Endorsement endorsement = exitingEndorsement.get();
142-
String updatedMessage = body.getMessage();
143-
144-
if (updatedMessage != null) {
145-
endorsement.setMessage(updatedMessage);
146-
}
147-
148-
Endorsement savedEndorsementDetails = endorsementRepository.save(endorsement);
149-
RdsGetUserDetailsResDto endorseDetails =
150-
rdsService.getUserDetails(savedEndorsementDetails.getEndorseId());
151-
RdsGetUserDetailsResDto endorserDetails =
152-
rdsService.getUserDetails(savedEndorsementDetails.getEndorserId());
153-
154-
return EndorsementViewModel.toViewModel(
155-
savedEndorsementDetails,
156-
UserViewModel.toViewModel(endorseDetails.getUser()),
157-
UserViewModel.toViewModel(endorserDetails.getUser()));
167+
throw new IllegalStateException(ExceptionMessages.UPDATE_DISABLED_IN_NON_DEV_MODE);
158168
}
159169
}

skill-tree/src/main/java/com/RDS/skilltree/utils/Constants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ public static final class ExceptionMessages {
1515
public static final String INVALID_ACCESS_TOKEN =
1616
"The access token provided is expired, revoked, malformed, or invalid for other reasons.";
1717
public static final String ACCESS_DENIED = "Access Denied";
18+
public static final String UPDATE_DISABLED_IN_NON_DEV_MODE =
19+
"Update is not allowed outside of development mode";
1820
}
1921
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.RDS.skilltree.viewmodels;
22

33
import com.RDS.skilltree.utils.Constants.ExceptionMessages;
4-
import jakarta.validation.constraints.NotNull;
4+
import jakarta.validation.constraints.NotBlank;
55
import lombok.Getter;
66
import lombok.Setter;
77

88
@Getter
99
@Setter
1010
public class UpdateEndorsementViewModel {
11-
@NotNull(message = ExceptionMessages.ENDORSEMENT_MESSAGE_EMPTY)
11+
@NotBlank(message = ExceptionMessages.ENDORSEMENT_MESSAGE_EMPTY)
1212
private String message;
1313
}

skill-tree/src/test/java/com/RDS/skilltree/integration/skills/UpdateEndorsementsIntegrationTest.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ private MvcResult performPatchRequest(String url, String requestBody) throws Exc
108108
}
109109

110110
private String createUrl(Integer endorsementId) {
111-
return String.format("/v1/endorsements/%d", endorsementId);
111+
String isDev = "?dev=true";
112+
return String.format("/v1/endorsements/%d" + isDev, endorsementId);
112113
}
113114

114115
private UpdateEndorsementViewModel createRequestModel(String newMessage) {
@@ -192,7 +193,6 @@ public void updateEndorsement_whenEndorsementIdDoesNotExist_shouldReturnNotFound
192193
}
193194

194195
@Test
195-
@Disabled("Fails due to authorization bug tracked in #206 – re-enable once fixed")
196196
@DisplayName("when user is not the endorser, should not update endorsement")
197197
@WithCustomMockUser(
198198
username = userId1,
@@ -217,7 +217,6 @@ public void updateEndorsement_othersEndorsement_shouldNotUpdateEndorsement() thr
217217
}
218218

219219
@Test
220-
@Disabled("Fails due to validation bug tracked in #206 – re-enable once fixed")
221220
@DisplayName("Message is empty string, request is not valid")
222221
@WithCustomMockUser(
223222
username = userId1,
@@ -238,7 +237,6 @@ public void updateEndorsement_whenMessageIsValidAndEmpty_shouldReturnBadRequest(
238237
}
239238

240239
@Test
241-
@Disabled("Fails due to bug tracked in #206 – re-enable once fixed")
242240
@DisplayName("RdsService fails to get 'endorser' details, should return 404")
243241
@WithCustomMockUser(
244242
username = "non-existent-endorser-id",
@@ -267,7 +265,6 @@ public void updateEndorsement_whenRdsServiceFailsForEndorserDetails_shouldReturn
267265
}
268266

269267
@Test
270-
@Disabled("Fails due to bug tracked in #206 – re-enable once fixed")
271268
@DisplayName("RdsService fails to get 'endorse' details, should return 404")
272269
@WithCustomMockUser(
273270
username = userId1,
@@ -352,4 +349,25 @@ public void updateEndorsement_whenUserIsUnauthenticated_shouldReturn401() throws
352349
assertThat(result.getResponse().getContentAsString())
353350
.contains(ExceptionMessages.INVALID_ACCESS_TOKEN);
354351
}
352+
353+
@Test
354+
@DisplayName("Endorsement update not allowed in non-dev mode, should return 405")
355+
@WithCustomMockUser(
356+
username = userId1,
357+
authorities = {"USER"})
358+
public void updateEndorsement_nonDevMode_shouldReturn405() throws Exception {
359+
Skill skill = createAndSaveSkill(SKILL_NAME);
360+
Endorsement existingEndorsement =
361+
createAndSaveEndorsement(skill, userId2, userId1, INITIAL_MESSAGE);
362+
363+
UpdateEndorsementViewModel updateEndorsementViewModel = createRequestModel(NEW_MESSAGE);
364+
String updateBody = objectMapper.writeValueAsString(updateEndorsementViewModel);
365+
366+
String url = String.format("/v1/endorsements/%d", existingEndorsement.getId());
367+
MvcResult result = performPatchRequest(url, updateBody);
368+
369+
assertThat(result.getResponse().getStatus()).isEqualTo(405);
370+
assertThat(result.getResponse().getContentAsString())
371+
.contains(ExceptionMessages.UPDATE_DISABLED_IN_NON_DEV_MODE);
372+
}
355373
}

0 commit comments

Comments
 (0)