Skip to content

Commit

Permalink
fix(rest): Validate comment message while create a moderation request.
Browse files Browse the repository at this point in the history
Signed-off-by: Nikesh kumar <kumar.nikesh@siemens.com>
  • Loading branch information
nikkuma7 authored and GMishx committed Dec 23, 2024
1 parent dfc187d commit 663ac83
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 0 deletions.
17 changes: 17 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,20 @@ include::{snippets}/should_document_get_moderationrequests_submission/curl-reque

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

[[resources-moderationRequest-validate]]
==== Validate User And Message Moderation Requests

A `POST` will validate the user and will check the comment message is present or not.

===== Request parameter
include::{snippets}/should_document_check_user_message_moderationrequests/query-parameters.adoc[]

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

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

===== Example response
include::{snippets}/should_document_check_user_message_moderationrequests/http-response.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.eclipse.sw360.datahandler.thrift.spdx.documentcreationinformation.*;
import org.eclipse.sw360.datahandler.thrift.spdx.spdxdocument.SPDXDocument;
import org.eclipse.sw360.datahandler.thrift.spdx.spdxpackageinfo.PackageInformation;
import org.eclipse.sw360.datahandler.thrift.users.RequestedAction;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.datahandler.thrift.vendors.Vendor;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.*;
Expand Down Expand Up @@ -102,6 +103,7 @@
import org.springframework.util.MultiValueMap;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
import static org.eclipse.sw360.datahandler.permissions.PermissionUtils.makePermission;

import jakarta.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
Expand Down Expand Up @@ -1687,4 +1689,8 @@ public ClearingRequest updateCRSize(ClearingRequest clearingRequest, Project pro
}
return clearingRequestService.getClearingRequestById(clearingRequest.getId(), sw360User);
}

public boolean isWriteActionAllowed(Object object, User user) {
return makePermission(object, user).isActionAllowed(RequestedAction.WRITE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.media.SchemaProperty;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.thrift.TException;
import org.apache.thrift.transport.TTransportException;
import org.bouncycastle.util.test.TestFailedException;
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.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.components.Component;
import org.eclipse.sw360.datahandler.thrift.components.Release;
import org.eclipse.sw360.datahandler.thrift.licenses.License;
Expand All @@ -50,15 +54,18 @@
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.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
import io.swagger.v3.oas.annotations.media.ExampleObject;

import jakarta.servlet.http.HttpServletRequest;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
Expand Down Expand Up @@ -495,4 +502,121 @@ private <T extends org.apache.thrift.TBase<T, F>, F extends org.apache.thrift.TF
setAddition.apply(addition);
setDeletion.apply(deletion);
}

@PreAuthorize("hasAuthority('WRITE')")
@Operation(
summary = "Validate Moderation Request",
description = "This endpoint validates a user for a moderation request.",
tags = {"Moderation Requests"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200", description = "Moderation request validated successfully.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"Moderation request validated successfully.\"}"
))
}
),
@ApiResponse(
responseCode = "202",
description = "Accepted - Moderation request is pending review.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"Moderation request is pending review.\"}"
))
}
),
@ApiResponse(
responseCode = "400", description = "Bad Request - Invalid input or missing parameters.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"Invalid input or missing required parameters.\"}"
))
}
),
@ApiResponse(
responseCode = "401", description = "Unauthorized - User does not have the required permissions.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"User is not authorized to perform this action.\"}"
))
}
),
@ApiResponse(
responseCode = "403", description = "Forbidden - Access denied.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"Access is denied due to insufficient permissions.\"}"
))
}
),
@ApiResponse(
responseCode = "500", description = "Internal Server Error.",
content = {
@Content(mediaType = "application/json",
examples = @ExampleObject(
value = "{\"message\": \"An unexpected error occurred while validating the moderation request.\"}"
))
}
)
})
@RequestMapping(value = MODERATION_REQUEST_URL + "/validate", method = RequestMethod.POST)
public ResponseEntity<String> validateModerationRequest(
@Parameter(description = "Project id.")
@RequestParam String entityType,
@Parameter(description = "Entity type", example = "Pass entity type like PROJECT/COMPONENT/RELEASE")
@RequestParam String entityId,
HttpServletRequest request) throws TException{

try {
User user = restControllerHelper.getSw360UserFromAuthentication();
Object entity = getEntityByTypeAndId(entityType, entityId, user);
if (entity == null) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body("Entity not found for the given ID: " + entityId);
}
boolean isWriteActionAllowed = restControllerHelper.isWriteActionAllowed(entity, user);
if (!isWriteActionAllowed) {
return ResponseEntity.status(HttpStatus.ACCEPTED).body(
"User allowed to perform write on entity.MR is required.");
}
return ResponseEntity.ok("User can write to the entity. MR is not required.");
} catch (SW360Exception ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Entity not found for the given ID: " + entityId);
} catch (IllegalArgumentException ex) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body("Invalid entity type provided: " + ex.getMessage());
} catch (TException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("An error occurred while processing the request: " + ex.getMessage());
}
}

/**
* Helper method to fetch entity by type and ID.
*/
private Object getEntityByTypeAndId(String entityType, String entityId, User user) throws TException {
try {
switch (entityType.toLowerCase()) {
case "project":
return projectService.getProjectForUserById(entityId, user);
case "component":
return componentService.getComponentForUserById(entityId, user);
case "release":
return releaseService.getReleaseForUserById(entityId, user);
default:
throw new IllegalArgumentException("Unsupported entity type: " + entityType);
}
} catch (TTransportException e) {
throw new RuntimeException("Unable to connect to the service. Please check the server status.", e);
} catch (TException e) {
throw e;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.eclipse.sw360.rest.resourceserver.TestHelper;
import org.eclipse.sw360.rest.resourceserver.moderationrequest.ModerationPatch;
import org.eclipse.sw360.rest.resourceserver.moderationrequest.Sw360ModerationRequestService;
import org.eclipse.sw360.rest.resourceserver.project.Sw360ProjectService;
import org.eclipse.sw360.rest.resourceserver.release.Sw360ReleaseService;
import org.eclipse.sw360.rest.resourceserver.user.Sw360UserService;
import org.junit.Before;
Expand All @@ -40,6 +41,7 @@
import org.springframework.http.MediaType;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MvcResult;

import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -50,12 +52,14 @@
import java.util.Map;
import java.util.Set;

import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
Expand All @@ -81,6 +85,12 @@ public class ModerationRequestSpecTest extends TestRestDocsSpecBase {
@MockBean
private Sw360ModerationRequestService moderationRequestServiceMock;

@MockBean
private Sw360ProjectService projectServiceMock;

@MockBean
private Project project;

@Before
public void before() throws TException, IOException {
Set<String> moderatorList = new HashSet<>();
Expand Down Expand Up @@ -190,6 +200,7 @@ public void before() throws TException, IOException {
user.setId("123456789");
user.setEmail(testUserId);
user.setFullname("John Doe");
user.setDepartment("xyz");

given(this.releaseServiceMock.getReleaseForUserById(eq(moderationRequest.getDocumentId()), any())).willReturn(releaseAdditions);
given(this.userServiceMock.getUserByEmail(moderationRequest.getRequestingUser())).willReturn(new User("test.admin@sw360.org", "DEPT").setId("12345"));
Expand Down Expand Up @@ -483,4 +494,24 @@ public void should_document_get_moderationrequests_submission() throws Exception
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)));
}

@Test
public void should_document_check_user_message_moderationrequests() throws Exception {
project = new Project();
project.setId("98745");
project.setName("Test Project");
project.setProjectType(ProjectType.PRODUCT);
project.setVersion("1");
project.setCreatedOn("2021-04-27");
project.setCreatedBy("admin@sw360.org");
given(this.projectServiceMock.getProjectForUserById(eq(project.getId()), any())).willReturn(project);

this.mockMvc.perform(post("/api/moderationrequest/validate")
.param("entityType", "PROJECT")
.param("entityId", project.getId())
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk())
.andReturn();
}
}

0 comments on commit 663ac83

Please sign in to comment.