From 8c8359b3e108fa092564e8b0f8b01d1b4b5d3c29 Mon Sep 17 00:00:00 2001 From: Rudra Chopra Date: Thu, 16 Jan 2025 12:55:11 +0530 Subject: [PATCH] feat(rest): endpoint to merge vendor. Signed-off-by: Rudra Chopra --- .../src/docs/asciidoc/vendors.adoc | 14 +++++++++ .../vendor/Sw360VendorService.java | 18 +++++++++++ .../vendor/VendorController.java | 21 +++++++++++++ .../restdocs/VendorSpecTest.java | 30 +++++++++++++++++-- 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/rest/resource-server/src/docs/asciidoc/vendors.adoc b/rest/resource-server/src/docs/asciidoc/vendors.adoc index 65c3ea3086..431d1de9c2 100644 --- a/rest/resource-server/src/docs/asciidoc/vendors.adoc +++ b/rest/resource-server/src/docs/asciidoc/vendors.adoc @@ -118,3 +118,17 @@ include::{snippets}/should_document_get_export_vendor/curl-request.adoc[] ===== Example response include::{snippets}/should_document_get_export_vendor/http-response.adoc[] + +[[resources-vendor-merge]] +==== Merge vendors + +A `PATCH` request will merge the source vendor with the target vendor. + +===== Request structure +include::{snippets}/should_document_merge_vendor/request-fields.adoc[] + +===== Example request +include::{snippets}/should_document_merge_vendor/curl-request.adoc[] + +===== Example response +include::{snippets}/should_document_merge_vendor/http-response.adoc[] \ No newline at end of file diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/Sw360VendorService.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/Sw360VendorService.java index f4bade9696..f137a4272d 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/Sw360VendorService.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/Sw360VendorService.java @@ -14,6 +14,7 @@ import org.apache.thrift.TException; import org.apache.thrift.transport.TTransportException; import org.eclipse.sw360.datahandler.common.CommonUtils; +import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException; import org.eclipse.sw360.datahandler.thrift.AddDocumentRequestStatus; import org.eclipse.sw360.datahandler.thrift.AddDocumentRequestSummary; import org.eclipse.sw360.datahandler.thrift.RequestStatus; @@ -27,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; import java.nio.ByteBuffer; @@ -186,4 +188,20 @@ public Set getAllReleaseList(String vendorId) throws TException { Set releases = componentsClient.getReleasesByVendorId(vendorId); return releases; } + + public RequestStatus mergeVendors(String vendorTargetId, String vendorSourceId, Vendor vendorSelection, User user) throws TException, ResourceClassNotFoundException { + VendorService.Iface sw360VendorClient = getThriftVendorClient(); + RequestStatus requestStatus; + requestStatus = sw360VendorClient.mergeVendors(vendorTargetId, vendorSourceId, vendorSelection, user); + + if (requestStatus == RequestStatus.IN_USE) { + throw new HttpMessageNotReadableException("Vendor already in use as source or target vendor has an open MR"); + } else if (requestStatus == RequestStatus.FAILURE) { + throw new ResourceClassNotFoundException("Internal server error while merging the vendors"); + } else if (requestStatus == RequestStatus.ACCESS_DENIED) { + throw new AccessDeniedException("Access denied"); + } + + return requestStatus; + } } diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java index eae860e1a9..25560d34c5 100644 --- a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/vendor/VendorController.java @@ -274,6 +274,27 @@ public ResponseEntity exportVendor(HttpServletResponse response) throws TExce return ResponseEntity.ok(HttpStatus.OK); } + @PreAuthorize("hasAuthority('WRITE')") + @Operation( + summary = "Merge two vendors.", + description = "Merge source vendor into target vendor.", + tags = {"Vendor"} + ) + @RequestMapping(value = VENDORS_URL + "/mergeVendors", method = RequestMethod.PATCH) + public ResponseEntity mergeVendors( + @Parameter(description = "The id of the merge target vendor.") + @RequestParam(value = "mergeTargetId", required = true) String mergeTargetId, + @Parameter(description = "The id of the merge source vendor.") + @RequestParam(value = "mergeSourceId", required = true) String mergeSourceId, + @Parameter(description = "The merge selection.") + @RequestBody Vendor mergeSelection + ) throws TException, ResourceClassNotFoundException { + User sw360User = restControllerHelper.getSw360UserFromAuthentication(); + // perform the real merge, update merge target and delete merge sources + RequestStatus requestStatus = vendorService.mergeVendors(mergeTargetId, mergeSourceId, mergeSelection, sw360User); + return new ResponseEntity<>(requestStatus, HttpStatus.OK); + } + private void copyDataStreamToResponse(HttpServletResponse response, ByteBuffer buffer) throws IOException { FileCopyUtils.copy(buffer.array(), response.getOutputStream()); } diff --git a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java index ce51eed399..680b9767b4 100644 --- a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java +++ b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/VendorSpecTest.java @@ -10,6 +10,7 @@ package org.eclipse.sw360.rest.resourceserver.restdocs; import org.apache.thrift.TException; +import org.eclipse.sw360.datahandler.resourcelists.ResourceClassNotFoundException; import org.eclipse.sw360.datahandler.thrift.RequestStatus; import org.eclipse.sw360.datahandler.thrift.vendors.Vendor; import org.eclipse.sw360.datahandler.thrift.components.Release; @@ -36,11 +37,10 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; -import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; -import static org.springframework.restdocs.request.RequestDocumentation.queryParameters; @RunWith(SpringJUnit4ClassRunner.class) public class VendorSpecTest extends TestRestDocsSpecBase { @@ -58,7 +58,7 @@ public class VendorSpecTest extends TestRestDocsSpecBase { private Vendor vendor3; @Before - public void before() throws TException{ + public void before() throws TException, ResourceClassNotFoundException { vendor = new Vendor(); vendor.setId("876876776"); vendor.setFullname("Google Inc."); @@ -99,6 +99,7 @@ public void before() throws TException{ given(this.vendorServiceMock.getAllReleaseList(eq(vendor.getId()))).willReturn(releases); given(this.vendorServiceMock.getVendors()).willReturn(vendorList); + given(this.vendorServiceMock.mergeVendors(eq(vendor.getId()),eq(vendor2.getId()), any(), any())).willReturn(RequestStatus.SUCCESS); given(this.vendorServiceMock.vendorUpdate(any(), any(), any())).willReturn(RequestStatus.SUCCESS); given(this.vendorServiceMock.getVendorById(eq(vendor.getId()))).willReturn(vendor); given(this.vendorServiceMock.deleteVendorByid(any(), any())).willReturn(RequestStatus.SUCCESS); @@ -235,4 +236,27 @@ public void should_document_get_export_vendor() throws Exception{ .andExpect(status().isOk()) .andDo(this.documentationHandler.document()); } + + @Test + public void should_document_merge_vendor() throws Exception{ + mockMvc.perform(patch("/api/vendors/mergeVendors") + .contentType(MediaTypes.HAL_JSON) + .content(this.objectMapper.writeValueAsString(vendor)) + .header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword)) + .param("mergeTargetId", "87654321") + .param("mergeSourceId", "17653524") + .accept(MediaTypes.HAL_JSON)) + .andExpect(status().isOk()) + .andDo(this.documentationHandler.document( + queryParameters( + parameterWithName("mergeSourceId").description("Id of a source vendor to merge"), + parameterWithName("mergeTargetId").description("Id of a target vendor to merge") + ), + requestFields( + fieldWithPath("fullName").description("The full name of the vendor"), + fieldWithPath("shortName").description("The short name of the vendor"), + fieldWithPath("url").description("The vendor's home page URL"), + fieldWithPath("type").description("The type of document") + ))); + } }