-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(rest): create new enpoint to upload component csv file.
Signed-off-by: Nikesh kumar <[email protected]>
- Loading branch information
Nikesh kumar
committed
Feb 12, 2024
1 parent
ecce96c
commit 72b21fd
Showing
6 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// | ||
// Copyright Siemens AG, 2024. Part of the SW360 Portal Project. | ||
// | ||
// This program and the accompanying materials are made | ||
// available under the terms of the Eclipse Public License 2.0 | ||
// which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 | ||
// | ||
|
||
[[resources-importExport]] | ||
=== ImportExport | ||
|
||
The ImportExport resource is used to get and upload request. | ||
|
||
[[upload-component]] | ||
==== upload component csv file. | ||
|
||
A `POST` request help to u;load the component csv file. | ||
|
||
===== Example request | ||
include::{snippets}/should_document_upload_component_file/curl-request.adoc[] | ||
|
||
===== Example response | ||
include::{snippets}/should_document_upload_component_file/http-response.adoc[] |
87 changes: 87 additions & 0 deletions
87
.../main/java/org/eclipse/sw360/rest/resourceserver/importexport/ImportExportController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright Siemens AG, 2024-2025. | ||
* Part of the SW360 Portal Project. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
|
||
package org.eclipse.sw360.rest.resourceserver.importexport; | ||
|
||
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; | ||
|
||
import java.io.IOException; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import org.apache.thrift.TException; | ||
import org.eclipse.sw360.datahandler.common.CommonUtils; | ||
import org.eclipse.sw360.datahandler.thrift.RequestStatus; | ||
import org.eclipse.sw360.datahandler.thrift.RequestSummary; | ||
import org.eclipse.sw360.datahandler.thrift.users.User; | ||
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper; | ||
import org.eclipse.sw360.rest.resourceserver.project.ProjectController; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.data.rest.webmvc.BasePathAwareController; | ||
import org.springframework.data.rest.webmvc.RepositoryLinksResource; | ||
import org.springframework.hateoas.server.RepresentationModelProcessor; | ||
import org.springframework.http.HttpStatus.Series; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.HttpMediaTypeNotAcceptableException; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestMethod; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.security.SecurityRequirement; | ||
import lombok.NonNull; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@BasePathAwareController | ||
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) | ||
@RestController | ||
@SecurityRequirement(name = "tokenAuth") | ||
public class ImportExportController implements RepresentationModelProcessor<RepositoryLinksResource> { | ||
public static final String IMPORTEXPORT_URL = "/importExport"; | ||
|
||
private static final MediaType form = null; | ||
|
||
@NonNull | ||
private final RestControllerHelper restControllerHelper; | ||
|
||
@NonNull | ||
private final Sw360ImportExportService importExportService; | ||
|
||
@Override | ||
public RepositoryLinksResource process(RepositoryLinksResource resource) { | ||
resource.add(linkTo(ImportExportController.class).slash("api/importExport").withRel("importExport")); | ||
return resource; | ||
} | ||
|
||
@Operation( | ||
summary = "Upload component csv file.", | ||
description = "Upload component csv file.", | ||
tags = {"Component"} | ||
) | ||
@RequestMapping(value = IMPORTEXPORT_URL + "/upload", method = RequestMethod.POST, consumes = { MediaType.MULTIPART_FORM_DATA_VALUE}, produces = { MediaType.APPLICATION_JSON_VALUE }) | ||
public ResponseEntity<RequestSummary> uploadComponentCsv( | ||
@Parameter(description = "The component csv file to be uploaded.") | ||
@RequestParam("componentFile") MultipartFile file, HttpServletRequest request, HttpServletResponse response | ||
) throws TException,ServletException,IOException{ | ||
|
||
User sw360User = restControllerHelper.getSw360UserFromAuthentication(); | ||
RequestSummary requestSummary =importExportService.uploadComponent(sw360User, file, request, response); | ||
return ResponseEntity.ok(requestSummary); | ||
} | ||
} |
122 changes: 122 additions & 0 deletions
122
...ain/java/org/eclipse/sw360/rest/resourceserver/importexport/Sw360ImportExportService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Copyright Siemens AG, 2024-2025. | ||
* Part of the SW360 Portal Project. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
|
||
package org.eclipse.sw360.rest.resourceserver.importexport; | ||
|
||
import static org.eclipse.sw360.datahandler.common.ImportCSV.readAsCSVRecords; | ||
import static org.eclipse.sw360.importer.ComponentImportUtils.convertCSVRecordsToCompCSVRecords; | ||
import static org.eclipse.sw360.importer.ComponentImportUtils.writeToDatabase; | ||
|
||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.InputStreamReader; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServlet; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
import javax.servlet.http.HttpSession; | ||
import javax.servlet.http.Part; | ||
|
||
import org.apache.commons.csv.CSVFormat; | ||
import org.apache.commons.csv.CSVParser; | ||
import org.apache.commons.csv.CSVRecord; | ||
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.apache.tomcat.util.http.fileupload.FileItem; | ||
import org.apache.tomcat.util.http.fileupload.RequestContext; | ||
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory; | ||
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload; | ||
import org.eclipse.sw360.datahandler.permissions.PermissionUtils; | ||
import org.eclipse.sw360.datahandler.thrift.RequestSummary; | ||
import org.eclipse.sw360.datahandler.thrift.attachments.AttachmentService; | ||
import org.eclipse.sw360.datahandler.thrift.components.ComponentService; | ||
import org.eclipse.sw360.datahandler.thrift.users.User; | ||
import org.eclipse.sw360.datahandler.thrift.users.UserGroup; | ||
import org.eclipse.sw360.datahandler.thrift.vendors.VendorService; | ||
import org.eclipse.sw360.importer.ComponentCSVRecord; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.http.converter.HttpMessageNotReadableException; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import com.fasterxml.jackson.annotation.JsonInclude; | ||
import com.google.common.base.Joiner; | ||
import com.google.common.collect.FluentIterable; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@SuppressWarnings("serial") | ||
@Service | ||
@RequiredArgsConstructor(onConstructor = @__(@Autowired)) | ||
public class Sw360ImportExportService { | ||
@Value("${sw360.thrift-server-url:http://localhost:8080}") | ||
private String thriftServerUrl; | ||
|
||
@JsonInclude | ||
public RequestSummary uploadComponent(User sw360User, MultipartFile file, HttpServletRequest request, HttpServletResponse response) throws IOException, TException, ServletException { | ||
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, sw360User)) { | ||
throw new RuntimeException("Unable to upload component csv file. User is not admin"); | ||
} | ||
List<CSVRecord> releaseRecords = getCSVFromRequest(request, "file"); | ||
FluentIterable<ComponentCSVRecord> compCSVRecords = convertCSVRecordsToCompCSVRecords(releaseRecords); | ||
ComponentService.Iface sw360ComponentClient = getThriftComponentClient(); | ||
VendorService.Iface sw360VendorClient = getThriftVendorClient(); | ||
AttachmentService.Iface sw360AttachmentClient = getThriftAttachmentClient(); | ||
RequestSummary requestSummary = writeToDatabase(compCSVRecords, sw360ComponentClient, sw360VendorClient, sw360AttachmentClient, sw360User); | ||
return requestSummary; | ||
} | ||
|
||
|
||
private List<CSVRecord> getCSVFromRequest(HttpServletRequest request, String fileUploadFormId) throws IOException, TException, ServletException { | ||
final InputStream stream = getInputStreamFromRequest(request, fileUploadFormId); | ||
return readAsCSVRecords(stream); | ||
} | ||
|
||
private InputStream getInputStreamFromRequest(HttpServletRequest request, String fileUploadFormId) throws IOException, ServletException { | ||
Collection<Part> parts = request.getParts(); | ||
|
||
for (Part part : parts) { | ||
if (!part.getName().equals(fileUploadFormId)) { | ||
return part.getInputStream(); | ||
} | ||
} | ||
|
||
throw new IOException("File not found in the request with the specified field name."); | ||
} | ||
|
||
private ComponentService.Iface getThriftComponentClient() throws TTransportException { | ||
THttpClient thriftClient = new THttpClient(thriftServerUrl + "/components/thrift"); | ||
TProtocol protocol = new TCompactProtocol(thriftClient); | ||
return new ComponentService.Client(protocol); | ||
} | ||
|
||
private VendorService.Iface getThriftVendorClient() throws TTransportException { | ||
THttpClient thriftClient = new THttpClient(thriftServerUrl + "/vendors/thrift"); | ||
TProtocol protocol = new TCompactProtocol(thriftClient); | ||
return new VendorService.Client(protocol); | ||
} | ||
|
||
private AttachmentService.Iface getThriftAttachmentClient() throws TTransportException { | ||
THttpClient thriftClient = new THttpClient(thriftServerUrl + "/attachments/thrift"); | ||
TProtocol protocol = new TCompactProtocol(thriftClient); | ||
return new AttachmentService.Client(protocol); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
...server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ImportExportSpec.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright Siemens AG, 2024-2025. | ||
* Part of the SW360 Portal Project. | ||
* | ||
* This program and the accompanying materials are made | ||
* available under the terms of the Eclipse Public License 2.0 | ||
* which is available at https://www.eclipse.org/legal/epl-2.0/ | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
*/ | ||
|
||
|
||
package org.eclipse.sw360.rest.resourceserver.restdocs; | ||
|
||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.BDDMockito.given; | ||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
import java.io.IOException; | ||
|
||
import javax.servlet.ServletException; | ||
|
||
import org.apache.thrift.TException; | ||
import org.eclipse.sw360.datahandler.thrift.RequestStatus; | ||
import org.eclipse.sw360.datahandler.thrift.RequestSummary; | ||
import org.eclipse.sw360.datahandler.thrift.licenses.LicenseType; | ||
import org.eclipse.sw360.datahandler.thrift.users.User; | ||
import org.eclipse.sw360.rest.resourceserver.TestHelper; | ||
import org.eclipse.sw360.rest.resourceserver.importexport.Sw360ImportExportService; | ||
import org.eclipse.sw360.rest.resourceserver.user.Sw360UserService; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.boot.test.mock.mockito.MockBean; | ||
import org.springframework.mock.web.MockMultipartFile; | ||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; | ||
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; | ||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; | ||
|
||
@RunWith(SpringJUnit4ClassRunner.class) | ||
public class ImportExportSpec extends TestRestDocsSpecBase { | ||
|
||
@Value("${sw360.test-user-id}") | ||
private String testUserId; | ||
|
||
@Value("${sw360.test-user-password}") | ||
private String testUserPassword; | ||
|
||
@MockBean | ||
private Sw360UserService userServiceMock; | ||
|
||
@MockBean | ||
private Sw360ImportExportService importExportService; | ||
|
||
private RequestSummary requestSummary = new RequestSummary(); | ||
|
||
@Before | ||
@SuppressWarnings("unchecked") | ||
public void before() throws TException, IOException, ServletException { | ||
User sw360User = new User(); | ||
sw360User.setId("123456789"); | ||
sw360User.setEmail("[email protected]"); | ||
sw360User.setFullname("John Doe"); | ||
|
||
requestSummary.setRequestStatus(RequestStatus.SUCCESS); | ||
LicenseType licensetype = new LicenseType(); | ||
licensetype.setId("1234"); | ||
licensetype.setLicenseType("wer"); | ||
licensetype.setLicenseTypeId(123); | ||
licensetype.setType("xyz"); | ||
|
||
given(this.importExportService.uploadComponent(any(), any(), any(),any())).willReturn(requestSummary); | ||
given(this.userServiceMock.getUserByEmailOrExternalId("[email protected]")).willReturn(sw360User); | ||
|
||
} | ||
|
||
@Test | ||
public void should_document_upload_component_file() throws Exception { | ||
MockMultipartFile file = new MockMultipartFile("componentFile","file=@/bom.spdx.rdf".getBytes()); | ||
String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword); | ||
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.multipart("/api/licenses/upload") | ||
.file(file) | ||
.header("Authorization", "Bearer " + accessToken) | ||
.queryParam("componentFile", "Must need to attach file."); | ||
this.mockMvc.perform(builder).andExpect(status().isOk()).andDo(this.documentationHandler.document()); | ||
} | ||
|
||
} |