Skip to content

Commit

Permalink
feat(rest): create new endpoint to delete ModerationRequests by id.
Browse files Browse the repository at this point in the history
Signed-off-by: Nikesh kumar <[email protected]>
  • Loading branch information
nikkuma7 authored and GMishx committed Jan 8, 2025
1 parent 5f002e0 commit c273f19
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 7 deletions.
11 changes: 11 additions & 0 deletions rest/resource-server/src/docs/asciidoc/moderationRequests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,14 @@ include::{snippets}/should_document_check_user_message_moderationrequests/curl-r

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

[[resources-moderationRequest-delete]]
==== Delete Moderation Requests

A `DELETE` method will delete list of moderation request.

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

===== Example response
include::{snippets}/should_document_delete_moderationrequests/http-response.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@
import org.apache.thrift.transport.TTransportException;
import org.eclipse.sw360.datahandler.common.CommonUtils;
import org.eclipse.sw360.datahandler.common.SW360Constants;
import org.eclipse.sw360.datahandler.resourcelists.PaginationParameterException;
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.resourcelists.PaginationResult;
import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException;
import org.eclipse.sw360.datahandler.thrift.ModerationState;
import org.eclipse.sw360.datahandler.thrift.PaginationData;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.components.Component;
import org.eclipse.sw360.datahandler.thrift.components.Release;
import org.eclipse.sw360.datahandler.thrift.licenses.License;
Expand All @@ -52,13 +55,15 @@
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.BasePathAwareController;
import org.springframework.data.rest.webmvc.RepositoryLinksResource;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.MediaTypes;
import org.springframework.hateoas.server.RepresentationModelProcessor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
Expand All @@ -70,6 +75,8 @@
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;

import java.net.URISyntaxException;
import java.util.*;
import java.util.function.Function;
Expand Down Expand Up @@ -383,6 +390,7 @@ private ResponseEntity<CollectionModel<ModerationRequest>> getModerationResponse
return new ResponseEntity<>(resources, status);
}


/**
* Filter moderation request to remove duplicate additions and deletions data.
* @param moderationRequest Moderation request to filter
Expand Down Expand Up @@ -614,4 +622,75 @@ private Object getEntityByTypeAndId(String entityType, String entityId, User use
throw new RuntimeException("Unable to connect to the service. Please check the server status.", e);
}
}
@Operation(
summary = "Delete moderation request.",
description = "Delete delete moderation request of the service.",
tags = {"ModerationRequest"}
)
@PreAuthorize("hasAuthority('WRITE')")
@RequestMapping(value = MODERATION_REQUEST_URL + "/delete", method = RequestMethod.DELETE)
public ResponseEntity<?> deleteModerationRequest(
HttpServletRequest request,
@Parameter(description = "List of moderation request IDs to delete")
@RequestBody List<String> ids) throws TException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
List<RequestStatus> requestStatusList = new ArrayList<>();
List<String> incorrectIds = new ArrayList<>();
List<String> correctIds = new ArrayList<>();
List<String> deletedIds = new ArrayList<>();

for (String id : ids) {
try {
ModerationRequest moderationRequest = sw360ModerationRequestService.getModerationRequestById(id);
RequestStatus requestStatus = sw360ModerationRequestService.deleteModerationRequestInfo(sw360User, id,
moderationRequest);
requestStatusList.add(requestStatus);
if (requestStatus == RequestStatus.SUCCESS) {
deletedIds.add(id);
} else {
correctIds.add(id);
}
} catch (ResourceNotFoundException ex) {
incorrectIds.add(id);
}
}

Map<String, Object> response = new HashMap<>();
response.put("deleted", deletedIds);
response.put("incorrect", incorrectIds);
response.put("correct", correctIds);

if (!requestStatusList.isEmpty()) {
if (requestStatusList.contains(RequestStatus.FAILURE)) {
response.put("message", "User doesn't have permission to delete.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (requestStatusList.contains(RequestStatus.SUCCESS) && requestStatusList.contains(null)) {
response.put("message", "Some requests were deleted, but some are in an open state.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (requestStatusList.contains(RequestStatus.SUCCESS) && incorrectIds.isEmpty() && correctIds.isEmpty()) {
response.put("message", "All specified moderation requests were successfully deleted.");
return ResponseEntity.status(HttpStatus.OK).body(response);
} else if (requestStatusList.contains(null)) {
response.put("message", "MR is in open state or user don't have permission.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
}
}

if (!incorrectIds.isEmpty() && !correctIds.isEmpty()) {
response.put("message", "Some moderation requests are invalid or open.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (incorrectIds.isEmpty() && correctIds.isEmpty() && !deletedIds.isEmpty()) {
response.put("message", "All specified moderation requests were successfully deleted.");
return ResponseEntity.status(HttpStatus.OK).body(response);
} else if (!incorrectIds.isEmpty()) {
response.put("message", "Some moderation requests are invalid.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (!correctIds.isEmpty()) {
response.put("message", "Some moderation requests are in an open state.");
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else {
response.put("message", "No valid moderation requests found.");
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
import lombok.RequiredArgsConstructor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TApplicationException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TCompactProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransportException;
import org.eclipse.sw360.datahandler.common.SW360Utils;
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.thrift.ModerationState;
import org.eclipse.sw360.datahandler.thrift.PaginationData;
import org.eclipse.sw360.datahandler.thrift.RemoveModeratorRequestStatus;
Expand All @@ -37,6 +39,7 @@
import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformationService;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.datahandler.thrift.users.UserService;
import org.eclipse.sw360.datahandler.thrift.users.UserGroup;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -51,6 +54,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
Expand Down Expand Up @@ -116,22 +120,35 @@ private UserService.Iface getThriftUserClient() throws TTransportException {
* @return Moderation Request
* @throws TException Appropriate exception if request does not exists or not accessible.
*/
public ModerationRequest getModerationRequestById(String requestId) throws TException {
public ModerationRequest getModerationRequestById(String requestId) throws TException, TApplicationException {
ModerationRequest moderationRequest = null;
try {
return getThriftModerationClient().getModerationRequestById(requestId);
moderationRequest = getThriftModerationClient().getModerationRequestById(requestId);
} catch (TApplicationException tAppExp) {
log.error("TApplicationException while fetching moderation request by ID: {}. Exception: {}",
requestId, tAppExp.getMessage(), tAppExp);
throw new ResourceNotFoundException("Requested ModerationRequest not found: " + requestId, tAppExp);
} catch (SW360Exception sw360Exp) {
if (sw360Exp.getErrorCode() == 404) {
throw new ResourceNotFoundException("Requested ModerationRequest not found");
log.warn("ModerationRequest not found with ID: {}", requestId);
throw new ResourceNotFoundException("Requested ModerationRequest not found: " + requestId, sw360Exp);
} else if (sw360Exp.getErrorCode() == 403) {
throw new AccessDeniedException(
"ModerationRequest or its Linked Project are restricted and / or not accessible");
log.warn("Access denied for ModerationRequest or its linked project with ID: {}", requestId);
throw new AccessDeniedException("ModerationRequest or its Linked Project are restricted and/or not accessible", sw360Exp);
} else {
log.error("Error fetching moderation request by id: " + sw360Exp.getMessage());
log.error("Unhandled SW360Exception while fetching moderation request by ID: {}. Exception: {}",
requestId, sw360Exp.getMessage(), sw360Exp);
throw sw360Exp;
}
} catch (Exception ex) {
log.error("Unexpected exception while fetching moderation request by ID: {}. Exception: {}",
requestId, ex.getMessage(), ex);
throw new RuntimeException("An unexpected error occurred while fetching the ModerationRequest: " + requestId, ex);
}
return moderationRequest;
}


/**
* Get paginated list of moderation requests where user is one of the
* moderators.
Expand Down Expand Up @@ -447,4 +464,27 @@ public Integer getOpenCriticalCrCountByGroup(String group) {
return 0;
}
}

public RequestStatus deleteModerationRequestInfo(@NotNull User sw360User, @NotNull String id,
@NotNull ModerationRequest moderationRequest)
throws TTransportException, TException {
RequestStatus requestStatus = null;
Set<String> moderators = moderationRequest.getModerators();
String requestingUser = moderationRequest.getRequestingUser();
ModerationState moderationState = moderationRequest.getModerationState();

if (moderators.contains(sw360User.getEmail())) {
if (moderationState == ModerationState.REJECTED || moderationState == ModerationState.APPROVED) {
requestStatus = getThriftModerationClient().deleteModerationRequest(id, sw360User);
}
} else if (!sw360User.getEmail().equals(requestingUser)) {
if (moderationState == ModerationState.PENDING || moderationState == ModerationState.INPROGRESS) {
requestStatus = RequestStatus.FAILURE;
}
} else {
requestStatus = getThriftModerationClient().deleteModerationRequest(id, sw360User);
}

return requestStatus;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.thrift.ModerationState;
import org.eclipse.sw360.datahandler.thrift.PaginationData;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.Visibility;
import org.eclipse.sw360.datahandler.thrift.components.ComponentType;
import org.eclipse.sw360.datahandler.thrift.components.ECCStatus;
Expand Down Expand Up @@ -66,6 +67,7 @@
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.queryParameters;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
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;
Expand All @@ -90,6 +92,7 @@ public class ModerationRequestSpecTest extends TestRestDocsSpecBase {

@MockBean
private Project project;
private ModerationRequest moderationRequest;

@Before
public void before() throws TException, IOException {
Expand Down Expand Up @@ -136,7 +139,7 @@ public void before() throws TException, IOException {
project2Deletions.setProjectType(ProjectType.CUSTOMER);
project2Deletions.setVisbility(Visibility.BUISNESSUNIT_AND_MODERATORS);

ModerationRequest moderationRequest = new ModerationRequest();
moderationRequest = new ModerationRequest();
moderationRequest.setId("MR-101");
moderationRequest.setTimestamp(System.currentTimeMillis() / 1000L - 172800);
moderationRequest.setDocumentId("R-101");
Expand Down Expand Up @@ -514,4 +517,33 @@ public void should_document_check_user_message_moderationrequests() throws Excep
.andExpect(status().isOk())
.andReturn();
}

@Test
public void should_document_delete_moderationrequests() throws Exception {
String accessToken = TestHelper.generateAuthHeader(testUserId, testUserPassword);
ModerationRequest mr3 = new ModerationRequest();
mr3.setId("MR-20443");
mr3.setRevision("1");
mr3.setTimestamp(System.currentTimeMillis() / 1000L - 172800);
mr3.setTimestampOfDecision(System.currentTimeMillis() / 1000L - 155000);
mr3.setDocumentId("P-102");
mr3.setDocumentType(DocumentType.PROJECT);
mr3.setRequestingUser("[email protected]");
mr3.setDocumentName("Project 2");
mr3.setModerationState(ModerationState.REJECTED);
mr3.setReviewer("[email protected]");
mr3.setRequestingUserDepartment("DEPT");
mr3.setComponentType(ComponentType.OSS);
mr3.setCommentRequestingUser("Update project version");

given(this.moderationRequestServiceMock.deleteModerationRequestInfo(any(), any(), any()))
.willReturn(RequestStatus.SUCCESS);

mockMvc.perform(delete("/api/moderationrequest/delete")
.content("[\"" + mr3.getId() + "\"]")
.header("Authorization", accessToken)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk());
}
}

0 comments on commit c273f19

Please sign in to comment.