Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rest): Endpoint to add comment on a clearing request. #2549

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions rest/resource-server/src/docs/asciidoc/clearingRequests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,26 @@ include::{snippets}/should_document_get_comments_by_clearing_request_id/curl-req

===== Example response
include::{snippets}/should_document_get_comments_by_clearing_request_id/http-response.adoc[]
[[resources-add-comment-to-clearingrequest]]
==== Add a new comment to a clearing request

A `POST` request will add a new comment to a specific clearing request.

===== Request Parameters

include::{snippets}/should_document_add_comment_to_clearingrequest/request-parameters.adoc[]

===== Request Example

include::{snippets}/should_document_add_comment_to_clearingrequest/curl-request.adoc[]

===== Response Structure

include::{snippets}/should_document_add_comment_to_clearingrequest/response-fields.adoc[]

===== Response Example

include::{snippets}/should_document_add_comment_to_clearingrequest/http-response.adoc[]



Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
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 io.swagger.v3.oas.annotations.Operation;
Expand All @@ -36,13 +37,13 @@
import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException;
import org.eclipse.sw360.datahandler.thrift.ClearingRequestState;
import org.eclipse.sw360.datahandler.thrift.Comment;
import org.eclipse.sw360.datahandler.thrift.components.Release;
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.project.Sw360ProjectService;
import org.jose4j.jwk.Use;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.BasePathAwareController;
Expand Down Expand Up @@ -139,6 +140,7 @@ private HalResource<ClearingRequest> createHalClearingRequestWithAllDetails(Clea
return halClearingRequest;
}


@Operation(
summary = "Get all the Clearing Requests visible to the user.",
description = "Get all the Clearing Requests visible to the user.",
Expand Down Expand Up @@ -181,7 +183,6 @@ public ResponseEntity<CollectionModel<EntityModel<ClearingRequest>>> getMyCleari
return new ResponseEntity<>(resources, status);
}


@Operation(
summary = "Get comments for a specific clearing request",
description = "Fetch a paginated list of comments associated with the given clearing request ID.",
Expand Down Expand Up @@ -225,6 +226,47 @@ public ResponseEntity<CollectionModel<?>> getCommentsByClearingRequestId(
}
}

@Operation(
summary = "Add a new comment to a clearing request.",
description = "Create a new comment for the clearing request.",
tags = {"ClearingRequest"}
)
@PreAuthorize("hasAuthority('WRITE')")
@RequestMapping(value = CLEARING_REQUEST_URL + "/{id}/comments", method = RequestMethod.POST)
public ResponseEntity<?> addComment(
@Parameter(description = "ID of the clearing request")
@PathVariable("id") String crId,
@Parameter(description = "Comment to be added to the clearing request",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = Comment.class)))
@RequestBody Comment comment,
akshitjoshii marked this conversation as resolved.
Show resolved Hide resolved
HttpServletRequest request
) {
try {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
ClearingRequest existingClearingRequest = sw360ClearingRequestService.getClearingRequestById(crId, sw360User);
ClearingRequest updatedClearingRequest = sw360ClearingRequestService.addCommentToClearingRequest(crId, comment, sw360User);
akshitjoshii marked this conversation as resolved.
Show resolved Hide resolved

List<Comment> sortedComments = updatedClearingRequest.getComments().stream()
.sorted((c1, c2) -> Long.compare(c2.getCommentedOn(), c1.getCommentedOn()))
.toList();
List<EntityModel<Comment>> commentList = new ArrayList<>();

for (Comment c : sortedComments) {
HalResource<Comment> resource = createHalComment(c);
commentList.add(resource);
}
CollectionModel<EntityModel<Comment>> resources = CollectionModel.of(commentList);
return new ResponseEntity<>(resources, HttpStatus.OK);
}catch (IllegalArgumentException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}catch (ResourceNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Clearing request not found.");
}catch (TException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred while processing the request.");
}
}

private HalResource<Comment> createHalComment(Comment comment) throws TException {
HalResource<Comment> halComment = new HalResource<>(comment);
User commentinguser = restControllerHelper.getUserByEmail(comment.getCommentedBy());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransportException;
import org.eclipse.sw360.datahandler.thrift.ClearingRequestState;
import org.eclipse.sw360.datahandler.thrift.Comment;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationService;
import org.eclipse.sw360.datahandler.thrift.projects.ClearingRequest;
Expand Down Expand Up @@ -88,4 +90,25 @@ public Set<ClearingRequest> getMyClearingRequests(User sw360User, ClearingReques
return clearingrequests;
}

public ClearingRequest addCommentToClearingRequest(String crId, Comment comment, User sw360User) throws TException {
if (crId == null || crId.isBlank()) {
throw new IllegalArgumentException("Clearing request ID cannot be null or empty.");
}
if (comment.getText() == null || comment.getText().trim().isEmpty()) {
throw new IllegalArgumentException("Comment text cannot be empty.");
}

comment.setCommentedBy(sw360User.getEmail());
comment.setText(comment.getText().trim());

ModerationService.Iface clearingRequestClient = getThriftModerationClient();
RequestStatus requestStatus = clearingRequestClient.addCommentToClearingRequest(crId, comment, sw360User);
if (requestStatus != RequestStatus.SUCCESS) {
throw new TException("Error adding comment to clearing request");
}
return getClearingRequestById(crId, sw360User);
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,14 @@
import static org.mockito.BDDMockito.given;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.restdocs.request.RequestDocumentation.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;

import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.thrift.ClearingRequestPriority;
Expand Down Expand Up @@ -65,6 +60,7 @@ public class ClearingRequestSpecTest extends TestRestDocsSpecBase {
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");
Expand Down Expand Up @@ -132,6 +128,7 @@ public void before() throws TException, IOException {

comments.add(comment);
clearingRequest.setComments(comments);
given(this.clearingRequestServiceMock.addCommentToClearingRequest(eq(clearingRequest.getId()), any(), any())).willReturn(clearingRequest);

given(this.clearingRequestServiceMock.getClearingRequestById(eq(clearingRequest.getId()), any())).willReturn(clearingRequest);
given(this.clearingRequestServiceMock.getClearingRequestByProjectId(eq(clearingRequest.getProjectId()), any())).willReturn(clearingRequest);
Expand Down Expand Up @@ -276,4 +273,28 @@ public void should_document_get_comments_by_clearing_request_id() throws Excepti
)));
}

public void should_add_comment_to_clearing_request() throws Exception {
Map<String, Object> comment = new LinkedHashMap<>();
comment.put("text", "comment text 1");
String accessToken = TestHelper.generateAuthHeader(testUserId, testUserPassword);

this.mockMvc.perform(
post("/api/clearingrequest/" + clearingRequest.getId() + "/comments")
.contentType(MediaTypes.HAL_JSON)
.content(this.objectMapper.writeValueAsString(comment))
.header("Authorization", accessToken))
.andExpect(status().isOk())
.andDo(this.documentationHandler.document(
requestFields(
fieldWithPath("text").description("The text of the comment")
),
responseFields(
fieldWithPath("_embedded.sw360:comments[].text").description("The text of the comment"),
fieldWithPath("_embedded.sw360:comments[].commentedBy").description("The user who made the comment"),
fieldWithPath("_embedded.sw360:comments[].commentedOn").description("Timestamp when the comment was made"),
subsectionWithPath("_embedded.sw360:comments[]._embedded.commentingUser").description("Details of the user who made the comment"),
subsectionWithPath("_links").description("<<resources-index-links,Links>> to other resources")
)
));
}
}