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
Nikesh kumar committed Apr 14, 2024
1 parent f051d63 commit 45e31e4
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 17 deletions.
12 changes: 12 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,15 @@ 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_get_moderationrequests_delete/curl-request.adoc[]

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

Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.common.CommonUtils;
import org.eclipse.sw360.datahandler.common.SW360Constants;
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.moderation.DocumentType;
Expand All @@ -45,16 +47,21 @@
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 com.google.common.collect.ImmutableMap;

import javax.servlet.http.HttpServletRequest;
import java.net.URISyntaxException;
import java.util.*;
Expand All @@ -67,6 +74,8 @@
@RestController
@SecurityRequirement(name = "tokenAuth")
public class ModerationRequestController implements RepresentationModelProcessor<RepositoryLinksResource> {
private static final ImmutableMap<String, String> RESPONSE_BODY_FOR_MODERATION_REQUEST = ImmutableMap.<String, String>builder()
.put("message", "MR is in open state and can be deleted by requesting user only.").build();

public static final String MODERATION_REQUEST_URL = "/moderationrequest";

Expand Down Expand Up @@ -342,4 +351,58 @@ private ResponseEntity<CollectionModel<ModerationRequest>> getModerationResponse
HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK;
return new ResponseEntity<>(resources, status);
}

@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<>();

for (String id : ids) {
try {
moderationRequest = sw360ModerationRequestService.getModerationRequestById(id);
String requestingUser = moderationRequest.getRequestingUser();
if (sw360User.getEmail().equals(requestingUser)
|| (PermissionUtils.isAdmin(sw360User) && isOpenModerationRequest(moderationRequest))) {

RequestStatus requestStatus = sw360ModerationRequestService.deleteModerationRequestInfo(sw360User,
id, moderationRequest, moderationState);
requestStatusList.add(requestStatus);
correctIds.add(id);
} else {
incorrectIds.add(id);
}
} catch (ResourceNotFoundException ex) {
incorrectIds.add(id);
}
}
Map<String, Object> response = new HashMap<>();
if (requestStatusList.contains(null)) {
return new ResponseEntity<>(RESPONSE_BODY_FOR_MODERATION_REQUEST, HttpStatus.FORBIDDEN);
} else if (!incorrectIds.isEmpty() && !correctIds.isEmpty()) {
response.put("Incorrect moderation request Id/Ids", incorrectIds);
response.put("Deleted moderation request Id/Ids", correctIds);
return ResponseEntity.status(HttpStatus.CONFLICT).body(response);
} else if (incorrectIds.isEmpty() && correctIds.isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response);
} else if (!incorrectIds.isEmpty()) {
response.put("Incorrect moderation request Id/Ids", incorrectIds);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
} else {
response.put("Deleted moderation request Id/Ids", correctIds);
return ResponseEntity.status(HttpStatus.OK).body(response);
}
}

public static boolean isOpenModerationRequest(@NotNull ModerationRequest moderationRequest) {
return moderationRequest.getModerationState() == ModerationState.PENDING || moderationRequest.getModerationState() == ModerationState.INPROGRESS;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,22 @@
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.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.thrift.ModerationState;
import org.eclipse.sw360.datahandler.thrift.PaginationData;
import org.eclipse.sw360.datahandler.thrift.RemoveModeratorRequestStatus;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest;
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService;
import org.eclipse.sw360.datahandler.thrift.users.User;
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 @@ -49,7 +53,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 || moderationRequest.getModerationState() == ModerationState.APPROVED;
}

private ModerationService.Iface getThriftModerationClient() throws TTransportException {
Expand All @@ -65,21 +69,28 @@ private ModerationService.Iface getThriftModerationClient() throws TTransportExc
* @return Moderation Request
* @throws TException Appropriate exception if request does not exists or not accessible.
*/
public ModerationRequest getModerationRequestById(String requestId) throws TException {
try {
return getThriftModerationClient().getModerationRequestById(requestId);
} catch (SW360Exception sw360Exp) {
if (sw360Exp.getErrorCode() == 404) {
throw new ResourceNotFoundException("Requested ModerationRequest not found");
} else if (sw360Exp.getErrorCode() == 403) {
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;
}
}
}
public ModerationRequest getModerationRequestById(String requestId) throws TException, TApplicationException {
ModerationRequest moderationRequest = null;
Map<String, String> responseMap = new HashMap<>();
try {
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: " + requestId);
} else if (sw360Exp.getErrorCode() == 403) {
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;
}

/**
* Get paginated list of moderation requests where user is one of the
Expand Down Expand Up @@ -253,4 +264,31 @@ public ModerationState assignRequest(@NotNull ModerationRequest request, @NotNul
getThriftModerationClient().setInProgress(request.getId(), reviewer);
return ModerationState.INPROGRESS;
}

public RequestStatus deleteModerationRequestInfo(@NotNull User sw360User, @NotNull String id, @NotNull ModerationRequest moderationRequest, ModerationState moderationState)
throws TTransportException, TException {
RequestStatus requestStatus = null;
if (PermissionUtils.isUserAtLeast(UserGroup.ADMIN, sw360User)) {
if (moderationRequest.getModerators().contains(sw360User.getEmail())) {
if (moderationRequest.getModerationState() == ModerationState.REJECTED
|| moderationRequest.getModerationState() == ModerationState.APPROVED) {
requestStatus = getThriftModerationClient().deleteModerationRequest(id, sw360User);
}
} else if (moderationRequest.getModerationState() == ModerationState.PENDING || moderationRequest.getModerationState() == ModerationState.INPROGRESS){
requestStatus = null;
}
} else {
if (!isOpenModerationRequest(moderationRequest)) {
throw new InvalidParameterException("Moderation request is not in an open state.");
} 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 @@ -52,8 +53,10 @@

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
Expand All @@ -62,6 +65,7 @@
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
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 @@ -84,6 +88,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 @@ -129,7 +136,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 @@ -494,4 +501,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_get_moderationrequests_delete() throws Exception {
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword);
User sw360User = new User();
sw360User.setEmail("[email protected]");
ModerationRequest moderationRequest1 = new ModerationRequest();
moderationRequest1.setRequestingUser("[email protected]");
when(moderationRequestServiceMock.getModerationRequestById("id1")).thenReturn(moderationRequest1);
when(moderationRequestServiceMock.deleteModerationRequestInfo(any(User.class), anyString(),
any(ModerationRequest.class), any(ModerationState.class)));
if (testUserId != "[email protected]") {
mockMvc.perform(delete("/api/moderationrequest/delete/")
.content("[\"id1\", \"id2\"]")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaTypes.HAL_JSON))
.andExpect(status()
.isInternalServerError());
} else {
mockMvc.perform(delete("/api/moderationrequest/delete/")
.content("[\"id1\", \"id2\"]")
.header("Authorization", "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaTypes.HAL_JSON))
.andExpect(status()
.isOk());
}
}
}

0 comments on commit 45e31e4

Please sign in to comment.