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 committed Nov 28, 2024
1 parent f41b892 commit e322aa1
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 14 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 @@ -146,3 +146,14 @@ include::{snippets}/should_document_get_moderationrequests_submission/curl-reque

===== Example response
include::{snippets}/should_document_get_moderationrequests_submission/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 @@ -25,10 +25,12 @@
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.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 @@ -50,17 +52,22 @@
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;

import jakarta.servlet.http.HttpServletRequest;
import com.google.common.collect.ImmutableMap;

import java.net.URISyntaxException;
import java.util.*;
import java.util.function.Function;
Expand All @@ -74,7 +81,6 @@
@SecurityRequirement(name = "tokenAuth")
@SecurityRequirement(name = "basic")
public class ModerationRequestController implements RepresentationModelProcessor<RepositoryLinksResource> {

public static final String MODERATION_REQUEST_URL = "/moderationrequest";

@Autowired
Expand Down Expand Up @@ -362,6 +368,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 @@ -478,4 +485,89 @@ private <T extends org.apache.thrift.TBase<T, F>, F extends org.apache.thrift.TF
setAddition.apply(addition);
setDeletion.apply(deletion);
}

@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, @RequestBody List<String> ids,
ModerationRequest moderationRequest, ModerationState moderationState) 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 = sw360ModerationRequestService.getModerationRequestById(id);
RequestStatus requestStatus = sw360ModerationRequestService.deleteModerationRequestInfo(sw360User, id,
moderationRequest, moderationState);
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<>();

if (!requestStatusList.isEmpty()) {
if (requestStatusList.contains(RequestStatus.FAILURE)) {
response.put("message", "User doesn't have permission to delete.");
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Deleted moderation request Id/Ids", deletedIds);
response.put("Correct moderation request Id/Ids", correctIds);
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.");
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Deleted moderation request Id/Ids", deletedIds);
response.put("Open moderation request Id/Ids", correctIds);
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (requestStatusList.contains(RequestStatus.SUCCESS)&& incorrectIds.isEmpty()
&& correctIds.isEmpty()) {
response.put("message", "Deleted moderation request Id/Ids.");
response.put("Deleted moderation request Id/Ids", deletedIds);
return ResponseEntity.status(HttpStatus.OK).body(response);
} else if (requestStatusList.contains(null)) {
response.put("message", "MR is in open state and can be deleted by requesting user only.");
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Open moderation request Id/Ids", correctIds);
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
}
}

if (!incorrectIds.isEmpty() && !correctIds.isEmpty()) {
response.put("message", "Some moderation requests are invalid or open.");
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Open moderation request Id/Ids", correctIds);
response.put("Deleted moderation request Id/Ids", deletedIds);
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.");
response.put("Deleted moderation request Id/Ids", deletedIds);
return ResponseEntity.status(HttpStatus.OK).body(response);
} else if (!incorrectIds.isEmpty()) {
response.put("message", "Some moderation requests are invalid.");
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Deleted moderation request Id/Ids", deletedIds);
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (!correctIds.isEmpty()) {
response.put("message", "Some moderation requests are in an open state.");
response.put("Open moderation request Id/Ids", correctIds);
response.put("Deleted moderation request Id/Ids", deletedIds);
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 All @@ -61,7 +65,7 @@ public class Sw360ModerationRequestService {
private String thriftServerUrl;

public static boolean isOpenModerationRequest(@NotNull ModerationRequest moderationRequest) {
return moderationRequest.getModerationState() == ModerationState.PENDING || moderationRequest.getModerationState() == ModerationState.INPROGRESS;
return moderationRequest.getModerationState() == ModerationState.PENDING || moderationRequest.getModerationState() == ModerationState.INPROGRESS ;
}

private ModerationService.Iface getThriftModerationClient() throws TTransportException {
Expand Down Expand Up @@ -116,20 +120,24 @@ 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("Error fetching moderation request by id: " + tAppExp.getMessage());
throw new ResourceNotFoundException("Requested ModerationRequest not found: " + requestId, tAppExp);
} catch (SW360Exception sw360Exp) {
if (sw360Exp.getErrorCode() == 404) {
throw new ResourceNotFoundException("Requested ModerationRequest not found");
throw new ResourceNotFoundException("Requested ModerationRequest not found: " + requestId);
} else if (sw360Exp.getErrorCode() == 403) {
throw new AccessDeniedException(
"ModerationRequest or its Linked Project are restricted and / or not accessible");
throw new AccessDeniedException("ModerationRequest or its Linked Project are restricted and / or not accessible");
} else {
log.error("Error fetching moderation request by id: " + sw360Exp.getMessage());
throw sw360Exp;
}
}
return moderationRequest;
}

/**
Expand Down Expand Up @@ -439,12 +447,41 @@ public ModerationState assignRequest(@NotNull ModerationRequest request, @NotNul
* @return Count of open critical CRs
* @throws TException Throws exception in case of errors.
*/
public Integer getOpenCriticalCrCountByGroup(String group) {
try {
return getThriftModerationClient().getOpenCriticalCrCountByGroup(group);
} catch (TException e) {
log.error("Error in getting open critical CR count by group: ", e);
return 0;
public Integer getOpenCriticalCrCountByGroup(String group) {
try {
return getThriftModerationClient().getOpenCriticalCrCountByGroup(group);
} catch (TException e) {
log.error("Error in getting open critical CR count by group: ", e);
return 0;
}
}
public RequestStatus deleteModerationRequestInfo(@NotNull User sw360User, @NotNull String id,
@NotNull ModerationRequest moderationRequest, ModerationState moderationState)
throws TTransportException, TException {
RequestStatus requestStatus = null;
Set<String> moderators = moderationRequest.getModerators();
String requestingUser = moderationRequest.getRequestingUser();
if (moderators.contains(sw360User.getEmail())) {
if (moderationRequest.getModerators().contains(sw360User.getEmail())) {
if (moderationRequest.getModerationState() == ModerationState.REJECTED
|| moderationRequest.getModerationState() == ModerationState.APPROVED) {
requestStatus = getThriftModerationClient().deleteModerationRequest(id, sw360User);
}
} else if (!sw360User.getEmail().equals(requestingUser)) {
if ((moderationRequest.getModerationState() == ModerationState.PENDING
|| moderationRequest.getModerationState() == ModerationState.INPROGRESS)) {
requestStatus = requestStatus.FAILURE;
}
} else {
requestStatus = null;
}
} else {
if (moderationState != null
&& (moderationState != ModerationState.REJECTED && moderationState != ModerationState.APPROVED)) {
throw new IllegalArgumentException("Moderation request is not in a deletable state.");
}
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 @@ -62,6 +63,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 @@ -81,6 +83,9 @@ public class ModerationRequestSpecTest extends TestRestDocsSpecBase {
@MockBean
private Sw360ModerationRequestService moderationRequestServiceMock;

@MockBean
private ModerationRequest moderationRequest;

@Before
public void before() throws TException, IOException {
Set<String> moderatorList = new HashSet<>();
Expand Down Expand Up @@ -126,7 +131,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 @@ -482,4 +487,33 @@ public void should_document_get_moderationrequests_submission() throws Exception
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

@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(), 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 e322aa1

Please sign in to comment.