Skip to content

Commit 75e3bc8

Browse files
sameed20GMishx
authored andcommitted
feat(rest): Add endpoint to handle updation of clearing requests.
Signed-off-by: sameed.ahmad <sameed.ahmad@siemens-healthineers.com>
1 parent 952a11a commit 75e3bc8

File tree

6 files changed

+201
-1
lines changed

6 files changed

+201
-1
lines changed

libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Utils.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,17 @@ public static boolean isValidDate(String date, DateTimeFormatter format, Long gr
277277
}
278278
}
279279

280+
public static boolean isValidDate(String currRequestedClearingDate, String newRequestedClearingDate, DateTimeFormatter format) {
281+
try {
282+
LocalDate currLocalDate = LocalDate.parse(currRequestedClearingDate, format);
283+
LocalDate requestedLocalDate = LocalDate.parse(newRequestedClearingDate, format);
284+
285+
return requestedLocalDate.isAfter(currLocalDate);
286+
} catch (DateTimeParseException e) {
287+
return false;
288+
}
289+
}
290+
280291
public static String printFullname(Release release) {
281292
if (release == null || isNullOrEmpty(release.getName())) {
282293
return "New Release";

rest/resource-server/src/docs/asciidoc/clearingRequests.adoc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,17 @@ include::{snippets}/should_document_add_comment_to_clearingrequest/response-fiel
115115
include::{snippets}/should_document_add_comment_to_clearingrequest/http-response.adoc[]
116116

117117

118+
[[resources-clearingRequest-update]]
119+
==== Update a clearingRequest
120+
121+
A `PATCH` request is used to update an existing clearingRequest
122+
123+
===== Response structure
124+
include::{snippets}/should_document_patch_clearingrequest/response-fields.adoc[]
125+
126+
===== Example request
127+
include::{snippets}/should_document_patch_clearingrequest/curl-request.adoc[]
128+
129+
===== Example response
130+
include::{snippets}/should_document_patch_clearingrequest/http-response.adoc[]
118131

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/clearingrequest/ClearingRequestController.java

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
import java.util.Comparator;
1818
import java.util.List;
1919
import java.util.stream.Collectors;
20+
import java.util.Map;
21+
import java.time.format.DateTimeFormatter;
2022

2123
import io.swagger.v3.oas.annotations.media.Content;
2224
import io.swagger.v3.oas.annotations.responses.ApiResponse;
2325
import io.swagger.v3.oas.annotations.responses.ApiResponses;
2426

2527
import jakarta.servlet.http.HttpServletRequest;
2628

29+
import com.fasterxml.jackson.databind.DeserializationFeature;
30+
import com.fasterxml.jackson.databind.ObjectMapper;
2731
import io.swagger.v3.oas.annotations.Operation;
2832
import io.swagger.v3.oas.annotations.Parameter;
2933
import io.swagger.v3.oas.annotations.media.Schema;
@@ -35,11 +39,16 @@
3539
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
3640
import org.eclipse.sw360.datahandler.thrift.ClearingRequestState;
3741
import org.eclipse.sw360.datahandler.thrift.Comment;
42+
import org.eclipse.sw360.datahandler.common.CommonUtils;
43+
import org.eclipse.sw360.datahandler.common.SW360Utils;
44+
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
45+
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
3846
import org.eclipse.sw360.datahandler.thrift.projects.ClearingRequest;
3947
import org.eclipse.sw360.datahandler.thrift.projects.Project;
4048
import org.eclipse.sw360.datahandler.thrift.users.User;
4149
import org.eclipse.sw360.rest.resourceserver.core.HalResource;
4250
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
51+
import org.eclipse.sw360.rest.resourceserver.moderationrequest.Sw360ModerationRequestService;
4352
import org.eclipse.sw360.rest.resourceserver.project.Sw360ProjectService;
4453
import org.springframework.beans.factory.annotation.Autowired;
4554
import org.springframework.data.domain.Pageable;
@@ -84,6 +93,8 @@ public class ClearingRequestController implements RepresentationModelProcessor<R
8493
@NonNull
8594
private final com.fasterxml.jackson.databind.Module sw360Module;
8695

96+
@NonNull
97+
private final Sw360ModerationRequestService moderationRequestService;
8798

8899
@Operation(
89100
summary = "Get clearing request by id.",
@@ -297,4 +308,98 @@ public RepositoryLinksResource process(RepositoryLinksResource resource) {
297308
resource.add(linkTo(ClearingRequestController.class).slash("api" + CLEARING_REQUEST_URL).withRel("clearingRequests"));
298309
return resource;
299310
}
311+
312+
@PreAuthorize("hasAuthority('WRITE')")
313+
@Operation(
314+
summary = "Update clearing request",
315+
description = "Update a clearing request by id.",
316+
tags = {"ClearingRequest"}
317+
)
318+
@RequestMapping(value = CLEARING_REQUEST_URL + "/{id}", method = RequestMethod.PATCH)
319+
public ResponseEntity<?> patchClearingRequest(
320+
@Parameter(description = "id of the clearing request")
321+
@PathVariable("id") String id,
322+
@Parameter(description = "The updated fields of clearing request.",
323+
schema = @Schema(implementation = ClearingRequest.class))
324+
@RequestBody Map<String, Object> reqBodyMap,
325+
HttpServletRequest request
326+
) throws TException {
327+
328+
try{
329+
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
330+
331+
ClearingRequest clearingRequest = sw360ClearingRequestService.getClearingRequestById(id, sw360User);
332+
String projectId = clearingRequest.getProjectId();
333+
334+
ClearingRequest updatedClearingRequest = convertToClearingRequest(reqBodyMap);
335+
updatedClearingRequest.setId(clearingRequest.getId());
336+
updatedClearingRequest.setProjectId(clearingRequest.getProjectId());
337+
updatedClearingRequest.setTimestamp(clearingRequest.getTimestamp());
338+
updatedClearingRequest.setProjectBU(clearingRequest.getProjectBU());
339+
updatedClearingRequest.setComments(clearingRequest.getComments());
340+
updatedClearingRequest.setModifiedOn(System.currentTimeMillis());
341+
342+
if(CommonUtils.isNotNullEmptyOrWhitespace(updatedClearingRequest.getRequestingUser()) && PermissionUtils.isAdmin(sw360User)){
343+
User updatedRequestingUser = restControllerHelper.getUserByEmailOrNull(updatedClearingRequest.getRequestingUser());
344+
if (updatedRequestingUser == null) {
345+
return new ResponseEntity<String>("Requesting user is not a valid", HttpStatus.BAD_REQUEST);
346+
}else{
347+
updatedClearingRequest.setRequestingUser(updatedRequestingUser.getEmail());
348+
}
349+
}
350+
351+
if (CommonUtils.isNotNullEmptyOrWhitespace(updatedClearingRequest.getRequestedClearingDate())) {
352+
if (!clearingRequest.getRequestingUser().equals(sw360User.getEmail())) {
353+
return new ResponseEntity<String>("Requested Clearing Date can only be updated by the requesting user", HttpStatus.FORBIDDEN);
354+
}
355+
if (!SW360Utils.isValidDate(clearingRequest.getRequestedClearingDate(), updatedClearingRequest.getRequestedClearingDate(), DateTimeFormatter.ISO_LOCAL_DATE)) {
356+
return new ResponseEntity<String>("Invalid clearing date requested", HttpStatus.BAD_REQUEST);
357+
}
358+
}
359+
360+
if ((updatedClearingRequest.getClearingType() != null || updatedClearingRequest.getPriority() != null ) &&
361+
!(PermissionUtils.isClearingAdmin(sw360User) || PermissionUtils.isAdmin(sw360User))) {
362+
return new ResponseEntity<String>("Update not allowed for field ClearingType, Priority with user role", HttpStatus.FORBIDDEN);
363+
}
364+
365+
if (updatedClearingRequest.getClearingTeam() != null) {
366+
User updatedClearingTeam = restControllerHelper.getUserByEmailOrNull(updatedClearingRequest.getClearingTeam());
367+
if (updatedClearingTeam == null) {
368+
return new ResponseEntity<String>("ClearingTeam is not a valid user", HttpStatus.BAD_REQUEST);
369+
}
370+
}
371+
372+
if (updatedClearingRequest.getAgreedClearingDate() != null) {
373+
if (PermissionUtils.isClearingAdmin(sw360User) || PermissionUtils.isAdmin(sw360User)) {
374+
String currentAgreedClearingDate = CommonUtils.isNotNullEmptyOrWhitespace(clearingRequest.getAgreedClearingDate()) ? clearingRequest.getAgreedClearingDate() : "1980-01-01";
375+
if (!SW360Utils.isValidDate(currentAgreedClearingDate, updatedClearingRequest.getAgreedClearingDate(), DateTimeFormatter.ISO_LOCAL_DATE)) {
376+
return new ResponseEntity<String>("Invalid agreed clearing date requested", HttpStatus.BAD_REQUEST);
377+
}
378+
} else {
379+
return new ResponseEntity<String>("Update not allowed for field Agreed Clearing Date with user role", HttpStatus.FORBIDDEN);
380+
}
381+
}
382+
383+
clearingRequest = this.restControllerHelper.updateClearingRequest(clearingRequest, updatedClearingRequest);
384+
385+
String baseURL = restControllerHelper.getBaseUrl(request);
386+
RequestStatus updateCRStatus = sw360ClearingRequestService.updateClearingRequest(clearingRequest, sw360User, baseURL, projectId);
387+
HalResource<ClearingRequest> halClearingRequest = createHalClearingRequestWithAllDetails(clearingRequest, sw360User, true);
388+
389+
if (updateCRStatus == RequestStatus.ACCESS_DENIED) {
390+
return new ResponseEntity<String>("Edit action is not allowed for this user role", HttpStatus.FORBIDDEN);
391+
}
392+
393+
return new ResponseEntity<>(halClearingRequest, HttpStatus.OK);
394+
}catch (Exception e) {
395+
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
396+
}
397+
}
398+
399+
private ClearingRequest convertToClearingRequest(Map<String, Object> requestBody){
400+
ObjectMapper mapper = new ObjectMapper();
401+
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
402+
mapper.registerModule(sw360Module);
403+
return mapper.convertValue(requestBody, ClearingRequest.class);
404+
}
300405
}

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/clearingrequest/Sw360ClearingRequestService.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,17 @@ public ClearingRequest addCommentToClearingRequest(String crId, Comment comment,
109109
return getClearingRequestById(crId, sw360User);
110110
}
111111

112+
public RequestStatus updateClearingRequest(ClearingRequest clearingRequest, User sw360User, String baseUrl, String projectId) throws TException {
113+
ModerationService.Iface sw360ModerationClient = getThriftModerationClient();
114+
String projectUrl = baseUrl + "/projects/-/project/detail/" + projectId;
112115

116+
RequestStatus requestStatus;
117+
requestStatus = sw360ModerationClient.updateClearingRequest(clearingRequest, sw360User, projectUrl);
118+
119+
if (requestStatus == RequestStatus.FAILURE) {
120+
throw new RuntimeException("Clearing Request with id '" + clearingRequest.getId() + " cannot be updated.");
121+
}
122+
return requestStatus;
123+
}
113124

114125
}

rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/core/RestControllerHelper.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,16 @@ public Package updatePackage(Package packageToUpdate, Package requestBodyPackage
659659
return packageToUpdate;
660660
}
661661

662+
public ClearingRequest updateClearingRequest(ClearingRequest crToUpdate, ClearingRequest requestBodyCR) {
663+
for(ClearingRequest._Fields field: ClearingRequest._Fields.values()) {
664+
Object fieldValue = requestBodyCR.getFieldValue(field);
665+
if (fieldValue != null) {
666+
crToUpdate.setFieldValue(field, fieldValue);
667+
}
668+
}
669+
return crToUpdate;
670+
}
671+
662672
public User updateUserProfile(User userToUpdate, Map<String, Object> requestBodyUser, ImmutableSet<User._Fields> setOfUserProfileFields) {
663673
for (User._Fields field : setOfUserProfileFields) {
664674
Object fieldValue = requestBodyUser.get(field.getFieldName());

rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ClearingRequestSpecTest.java

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
import static org.mockito.ArgumentMatchers.any;
1616
import static org.mockito.ArgumentMatchers.eq;
1717
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
18-
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
18+
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
19+
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
20+
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
21+
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
1922
import static org.springframework.restdocs.request.RequestDocumentation.*;
2023
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
24+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
2125
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
2226

2327
import java.io.IOException;
@@ -56,13 +60,15 @@ public class ClearingRequestSpecTest extends TestRestDocsSpecBase {
5660

5761
@MockBean
5862
private Sw360ClearingRequestService clearingRequestServiceMock;
63+
5964
ClearingRequest clearingRequest = new ClearingRequest();
6065
ClearingRequest cr1 = new ClearingRequest();
6166
ClearingRequest cr2 = new ClearingRequest();
6267
List<Comment> comments = new ArrayList<Comment>();
6368

6469
@Before
6570
public void before() throws TException, IOException {
71+
6672
clearingRequest.setId("CR-101");
6773
clearingRequest.setAgreedClearingDate("12-07-2020");
6874
clearingRequest.setClearingState(ClearingRequestState.ACCEPTED);
@@ -399,4 +405,48 @@ public void should_add_comment_to_clearing_request() throws Exception {
399405
)
400406
));
401407
}
408+
409+
@Test
410+
public void should_document_patch_clearingrequest () throws Exception {
411+
ClearingRequest updateClearingRequest = new ClearingRequest()
412+
.setClearingTeam("clearing.team@sw60.org")
413+
.setClearingState(ClearingRequestState.SANITY_CHECK);
414+
415+
mockMvc.perform(patch("/api/clearingrequest/" + clearingRequest.getId())
416+
.contentType(MediaTypes.HAL_JSON)
417+
.content(this.objectMapper.writeValueAsString(updateClearingRequest))
418+
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
419+
.accept(MediaTypes.HAL_JSON))
420+
.andExpect(status().isOk())
421+
.andDo(this.documentationHandler.document(
422+
requestFields(
423+
fieldWithPath("clearingTeam").description("The clearing team email id."),
424+
fieldWithPath("clearingState").description("The clearing state of request")
425+
),
426+
responseFields(
427+
fieldWithPath("id").description("The id of the clearing request"),
428+
fieldWithPath("agreedClearingDate").description("The agreed clearing date of the request, on / before which CR should be cleared"),
429+
fieldWithPath("clearingState").description("The clearing state of the request. Possible values are: " + Arrays.asList(ClearingRequestState.values())),
430+
fieldWithPath("clearingTeam").description("The clearing team email id."),
431+
fieldWithPath("projectBU").description("The Business Unit / Group of the Project, for which the clearing request is created"),
432+
fieldWithPath("projectId").description("The id of the Project, for which the clearing request is created"),
433+
fieldWithPath("requestedClearingDate").description("The requested clearing date of releases"),
434+
fieldWithPath("requestingUser").description("The user who created the clearing request"),
435+
fieldWithPath("requestingUserComment").description("The comment from the requesting user"),
436+
fieldWithPath("priority").description("The priority of the clearing request. Possible values are: " + Arrays.asList(ClearingRequestPriority.values())),
437+
subsectionWithPath("comments").description("The clearing request comments"),
438+
subsectionWithPath("comments[].text").description("The clearing request comment text"),
439+
subsectionWithPath("comments[].commentedBy").description("The user who added the comment on the clearing request"),
440+
subsectionWithPath("_embedded.sw360:project").description("The Project associated with the ClearingRequest"),
441+
subsectionWithPath("_embedded.clearingTeam").description("Clearing team user detail"),
442+
subsectionWithPath("_embedded.requestingUser").description("Requesting user detail"),
443+
subsectionWithPath("_links").description("Links to other resources"),
444+
fieldWithPath("clearingType").description("The type of clearing, e.g., DEEP"),
445+
fieldWithPath("_embedded.totalRelease").description("Total number of releases"),
446+
fieldWithPath("_embedded.openRelease").description("Number of open releases"),
447+
fieldWithPath("_embedded.lastUpdatedOn").description("Last updated date for the clearing request"),
448+
fieldWithPath("_embedded.createdOn").description("Creation date for the clearing request")
449+
450+
)));
451+
}
402452
}

0 commit comments

Comments
 (0)