Skip to content

Commit

Permalink
feat(rest): Add endpoint to handle updation of clearing requests.
Browse files Browse the repository at this point in the history
Signed-off-by: sameed.ahmad <[email protected]>
  • Loading branch information
sameed20 authored and GMishx committed Nov 14, 2024
1 parent 952a11a commit 75e3bc8
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,17 @@ public static boolean isValidDate(String date, DateTimeFormatter format, Long gr
}
}

public static boolean isValidDate(String currRequestedClearingDate, String newRequestedClearingDate, DateTimeFormatter format) {
try {
LocalDate currLocalDate = LocalDate.parse(currRequestedClearingDate, format);
LocalDate requestedLocalDate = LocalDate.parse(newRequestedClearingDate, format);

return requestedLocalDate.isAfter(currLocalDate);
} catch (DateTimeParseException e) {
return false;
}
}

public static String printFullname(Release release) {
if (release == null || isNullOrEmpty(release.getName())) {
return "New Release";
Expand Down
13 changes: 13 additions & 0 deletions rest/resource-server/src/docs/asciidoc/clearingRequests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,17 @@ include::{snippets}/should_document_add_comment_to_clearingrequest/response-fiel
include::{snippets}/should_document_add_comment_to_clearingrequest/http-response.adoc[]


[[resources-clearingRequest-update]]
==== Update a clearingRequest

A `PATCH` request is used to update an existing clearingRequest

===== Response structure
include::{snippets}/should_document_patch_clearingrequest/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_patch_clearingrequest/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_patch_clearingrequest/http-response.adoc[]

Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;
import java.time.format.DateTimeFormatter;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

import jakarta.servlet.http.HttpServletRequest;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
Expand All @@ -35,11 +39,16 @@
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
import org.eclipse.sw360.datahandler.thrift.ClearingRequestState;
import org.eclipse.sw360.datahandler.thrift.Comment;
import org.eclipse.sw360.datahandler.common.CommonUtils;
import org.eclipse.sw360.datahandler.common.SW360Utils;
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.projects.ClearingRequest;
import org.eclipse.sw360.datahandler.thrift.projects.Project;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.rest.resourceserver.core.HalResource;
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
import org.eclipse.sw360.rest.resourceserver.moderationrequest.Sw360ModerationRequestService;
import org.eclipse.sw360.rest.resourceserver.project.Sw360ProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -84,6 +93,8 @@ public class ClearingRequestController implements RepresentationModelProcessor<R
@NonNull
private final com.fasterxml.jackson.databind.Module sw360Module;

@NonNull
private final Sw360ModerationRequestService moderationRequestService;

@Operation(
summary = "Get clearing request by id.",
Expand Down Expand Up @@ -297,4 +308,98 @@ public RepositoryLinksResource process(RepositoryLinksResource resource) {
resource.add(linkTo(ClearingRequestController.class).slash("api" + CLEARING_REQUEST_URL).withRel("clearingRequests"));
return resource;
}

@PreAuthorize("hasAuthority('WRITE')")
@Operation(
summary = "Update clearing request",
description = "Update a clearing request by id.",
tags = {"ClearingRequest"}
)
@RequestMapping(value = CLEARING_REQUEST_URL + "/{id}", method = RequestMethod.PATCH)
public ResponseEntity<?> patchClearingRequest(
@Parameter(description = "id of the clearing request")
@PathVariable("id") String id,
@Parameter(description = "The updated fields of clearing request.",
schema = @Schema(implementation = ClearingRequest.class))
@RequestBody Map<String, Object> reqBodyMap,
HttpServletRequest request
) throws TException {

try{
User sw360User = restControllerHelper.getSw360UserFromAuthentication();

ClearingRequest clearingRequest = sw360ClearingRequestService.getClearingRequestById(id, sw360User);
String projectId = clearingRequest.getProjectId();

ClearingRequest updatedClearingRequest = convertToClearingRequest(reqBodyMap);
updatedClearingRequest.setId(clearingRequest.getId());
updatedClearingRequest.setProjectId(clearingRequest.getProjectId());
updatedClearingRequest.setTimestamp(clearingRequest.getTimestamp());
updatedClearingRequest.setProjectBU(clearingRequest.getProjectBU());
updatedClearingRequest.setComments(clearingRequest.getComments());
updatedClearingRequest.setModifiedOn(System.currentTimeMillis());

if(CommonUtils.isNotNullEmptyOrWhitespace(updatedClearingRequest.getRequestingUser()) && PermissionUtils.isAdmin(sw360User)){
User updatedRequestingUser = restControllerHelper.getUserByEmailOrNull(updatedClearingRequest.getRequestingUser());
if (updatedRequestingUser == null) {
return new ResponseEntity<String>("Requesting user is not a valid", HttpStatus.BAD_REQUEST);
}else{
updatedClearingRequest.setRequestingUser(updatedRequestingUser.getEmail());
}
}

if (CommonUtils.isNotNullEmptyOrWhitespace(updatedClearingRequest.getRequestedClearingDate())) {
if (!clearingRequest.getRequestingUser().equals(sw360User.getEmail())) {
return new ResponseEntity<String>("Requested Clearing Date can only be updated by the requesting user", HttpStatus.FORBIDDEN);
}
if (!SW360Utils.isValidDate(clearingRequest.getRequestedClearingDate(), updatedClearingRequest.getRequestedClearingDate(), DateTimeFormatter.ISO_LOCAL_DATE)) {
return new ResponseEntity<String>("Invalid clearing date requested", HttpStatus.BAD_REQUEST);
}
}

if ((updatedClearingRequest.getClearingType() != null || updatedClearingRequest.getPriority() != null ) &&
!(PermissionUtils.isClearingAdmin(sw360User) || PermissionUtils.isAdmin(sw360User))) {
return new ResponseEntity<String>("Update not allowed for field ClearingType, Priority with user role", HttpStatus.FORBIDDEN);
}

if (updatedClearingRequest.getClearingTeam() != null) {
User updatedClearingTeam = restControllerHelper.getUserByEmailOrNull(updatedClearingRequest.getClearingTeam());
if (updatedClearingTeam == null) {
return new ResponseEntity<String>("ClearingTeam is not a valid user", HttpStatus.BAD_REQUEST);
}
}

if (updatedClearingRequest.getAgreedClearingDate() != null) {
if (PermissionUtils.isClearingAdmin(sw360User) || PermissionUtils.isAdmin(sw360User)) {
String currentAgreedClearingDate = CommonUtils.isNotNullEmptyOrWhitespace(clearingRequest.getAgreedClearingDate()) ? clearingRequest.getAgreedClearingDate() : "1980-01-01";
if (!SW360Utils.isValidDate(currentAgreedClearingDate, updatedClearingRequest.getAgreedClearingDate(), DateTimeFormatter.ISO_LOCAL_DATE)) {
return new ResponseEntity<String>("Invalid agreed clearing date requested", HttpStatus.BAD_REQUEST);
}
} else {
return new ResponseEntity<String>("Update not allowed for field Agreed Clearing Date with user role", HttpStatus.FORBIDDEN);
}
}

clearingRequest = this.restControllerHelper.updateClearingRequest(clearingRequest, updatedClearingRequest);

String baseURL = restControllerHelper.getBaseUrl(request);
RequestStatus updateCRStatus = sw360ClearingRequestService.updateClearingRequest(clearingRequest, sw360User, baseURL, projectId);
HalResource<ClearingRequest> halClearingRequest = createHalClearingRequestWithAllDetails(clearingRequest, sw360User, true);

if (updateCRStatus == RequestStatus.ACCESS_DENIED) {
return new ResponseEntity<String>("Edit action is not allowed for this user role", HttpStatus.FORBIDDEN);
}

return new ResponseEntity<>(halClearingRequest, HttpStatus.OK);
}catch (Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST);
}
}

private ClearingRequest convertToClearingRequest(Map<String, Object> requestBody){
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.registerModule(sw360Module);
return mapper.convertValue(requestBody, ClearingRequest.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ public ClearingRequest addCommentToClearingRequest(String crId, Comment comment,
return getClearingRequestById(crId, sw360User);
}

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

RequestStatus requestStatus;
requestStatus = sw360ModerationClient.updateClearingRequest(clearingRequest, sw360User, projectUrl);

if (requestStatus == RequestStatus.FAILURE) {
throw new RuntimeException("Clearing Request with id '" + clearingRequest.getId() + " cannot be updated.");
}
return requestStatus;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,16 @@ public Package updatePackage(Package packageToUpdate, Package requestBodyPackage
return packageToUpdate;
}

public ClearingRequest updateClearingRequest(ClearingRequest crToUpdate, ClearingRequest requestBodyCR) {
for(ClearingRequest._Fields field: ClearingRequest._Fields.values()) {
Object fieldValue = requestBodyCR.getFieldValue(field);
if (fieldValue != null) {
crToUpdate.setFieldValue(field, fieldValue);
}
}
return crToUpdate;
}

public User updateUserProfile(User userToUpdate, Map<String, Object> requestBodyUser, ImmutableSet<User._Fields> setOfUserProfileFields) {
for (User._Fields field : setOfUserProfileFields) {
Object fieldValue = requestBodyUser.get(field.getFieldName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

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

@MockBean
private Sw360ClearingRequestService clearingRequestServiceMock;

ClearingRequest clearingRequest = new ClearingRequest();
ClearingRequest cr1 = new ClearingRequest();
ClearingRequest cr2 = new ClearingRequest();
List<Comment> comments = new ArrayList<Comment>();

@Before
public void before() throws TException, IOException {

clearingRequest.setId("CR-101");
clearingRequest.setAgreedClearingDate("12-07-2020");
clearingRequest.setClearingState(ClearingRequestState.ACCEPTED);
Expand Down Expand Up @@ -399,4 +405,48 @@ public void should_add_comment_to_clearing_request() throws Exception {
)
));
}

@Test
public void should_document_patch_clearingrequest () throws Exception {
ClearingRequest updateClearingRequest = new ClearingRequest()
.setClearingTeam("[email protected]")
.setClearingState(ClearingRequestState.SANITY_CHECK);

mockMvc.perform(patch("/api/clearingrequest/" + clearingRequest.getId())
.contentType(MediaTypes.HAL_JSON)
.content(this.objectMapper.writeValueAsString(updateClearingRequest))
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
requestFields(
fieldWithPath("clearingTeam").description("The clearing team email id."),
fieldWithPath("clearingState").description("The clearing state of request")
),
responseFields(
fieldWithPath("id").description("The id of the clearing request"),
fieldWithPath("agreedClearingDate").description("The agreed clearing date of the request, on / before which CR should be cleared"),
fieldWithPath("clearingState").description("The clearing state of the request. Possible values are: " + Arrays.asList(ClearingRequestState.values())),
fieldWithPath("clearingTeam").description("The clearing team email id."),
fieldWithPath("projectBU").description("The Business Unit / Group of the Project, for which the clearing request is created"),
fieldWithPath("projectId").description("The id of the Project, for which the clearing request is created"),
fieldWithPath("requestedClearingDate").description("The requested clearing date of releases"),
fieldWithPath("requestingUser").description("The user who created the clearing request"),
fieldWithPath("requestingUserComment").description("The comment from the requesting user"),
fieldWithPath("priority").description("The priority of the clearing request. Possible values are: " + Arrays.asList(ClearingRequestPriority.values())),
subsectionWithPath("comments").description("The clearing request comments"),
subsectionWithPath("comments[].text").description("The clearing request comment text"),
subsectionWithPath("comments[].commentedBy").description("The user who added the comment on the clearing request"),
subsectionWithPath("_embedded.sw360:project").description("The Project associated with the ClearingRequest"),
subsectionWithPath("_embedded.clearingTeam").description("Clearing team user detail"),
subsectionWithPath("_embedded.requestingUser").description("Requesting user detail"),
subsectionWithPath("_links").description("Links to other resources"),
fieldWithPath("clearingType").description("The type of clearing, e.g., DEEP"),
fieldWithPath("_embedded.totalRelease").description("Total number of releases"),
fieldWithPath("_embedded.openRelease").description("Number of open releases"),
fieldWithPath("_embedded.lastUpdatedOn").description("Last updated date for the clearing request"),
fieldWithPath("_embedded.createdOn").description("Creation date for the clearing request")

)));
}
}

0 comments on commit 75e3bc8

Please sign in to comment.