From a387789e5a50527f695614324d24ce381e46c7be Mon Sep 17 00:00:00 2001 From: Nikesh kumar Date: Tue, 28 Nov 2023 12:02:21 +0530 Subject: [PATCH] fix(rest): Create a new endpoint for dataBaseSanitation. Signed-off-by: Nikesh kumar --- .../src/docs/asciidoc/api-guide.adoc | 1 + .../src/docs/asciidoc/databaseSanitation.adoc | 25 ++++ .../DatabaseSanitationController.java | 67 +++++++++ .../Sw360DatabaseSanitationService.java | 97 +++++++++++++ .../resourceserver/restdocs/ApiSpecTest.java | 1 + .../restdocs/DatabaseSanitationSpecTest.java | 134 ++++++++++++++++++ 6 files changed, 325 insertions(+) create mode 100644 rest/resource-server/src/docs/asciidoc/databaseSanitation.adoc create mode 100644 rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/DatabaseSanitationController.java create mode 100644 rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/Sw360DatabaseSanitationService.java create mode 100644 rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/DatabaseSanitationSpecTest.java diff --git a/rest/resource-server/src/docs/asciidoc/api-guide.adoc b/rest/resource-server/src/docs/asciidoc/api-guide.adoc index 31feb10efe..716cd4ea16 100644 --- a/rest/resource-server/src/docs/asciidoc/api-guide.adoc +++ b/rest/resource-server/src/docs/asciidoc/api-guide.adoc @@ -307,3 +307,4 @@ include::obligations.adoc[] include::moderationRequests.adoc[] include::fossology.adoc[] include::schedule.adoc[] +include::databaseSanitation.adoc[] diff --git a/rest/resource-server/src/docs/asciidoc/databaseSanitation.adoc b/rest/resource-server/src/docs/asciidoc/databaseSanitation.adoc new file mode 100644 index 0000000000..8989e885d9 --- /dev/null +++ b/rest/resource-server/src/docs/asciidoc/databaseSanitation.adoc @@ -0,0 +1,25 @@ +// +// Copyright Siemens AG, 2023. 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-databaseSanitation]] +=== DatabaseSanitation + +The Database sanitation is used to get the duplicate releases and components. + +[[search-duplicate]] +==== search duplicate identifiers + +A `GET` request will fetch the duplicate project and components. + +===== Example request +include::{snippets}/should_document_search_duplicate/curl-request.adoc[] + +===== Example response +include::{snippets}/should_document_search_duplicate/http-response.adoc[] \ No newline at end of file diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/DatabaseSanitationController.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/DatabaseSanitationController.java new file mode 100644 index 0000000000..06c93b8b98 --- /dev/null +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/DatabaseSanitationController.java @@ -0,0 +1,67 @@ +/* + * Copyright Siemens AG, 2023-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 + */ + +package org.eclipse.sw360.rest.resourceserver.databasesanitation; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.thrift.TException; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper; +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.CollectionModel; +import org.springframework.hateoas.server.RepresentationModelProcessor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +@BasePathAwareController +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +@RestController +@SecurityRequirement(name = "tokenAuth") +public class DatabaseSanitationController implements RepresentationModelProcessor { + + public static final String DATABASESANITATION_URL = "/databaseSanitation"; + + @NonNull + Sw360DatabaseSanitationService dataSanitationService; + + @NonNull + private final RestControllerHelper restControllerHelper; + + @Override + public RepositoryLinksResource process(RepositoryLinksResource resource) { + resource.add(linkTo(DatabaseSanitationController.class).slash("api" + DATABASESANITATION_URL).withRel("databaseSanitation")); + return resource; + } + @RequestMapping(value = DATABASESANITATION_URL + "/searchDuplicate", method = RequestMethod.GET) + public ResponseEntity searchDuplicateIdentifiers()throws TException { + User sw360User = restControllerHelper.getSw360UserFromAuthentication(); + Map resource = new HashMap<>(); + resource = dataSanitationService.duplicateIdentifiers(sw360User); + if (!resource.isEmpty()) { + return new ResponseEntity<>(resource, HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + } +} \ No newline at end of file diff --git a/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/Sw360DatabaseSanitationService.java b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/Sw360DatabaseSanitationService.java new file mode 100644 index 0000000000..adfeade535 --- /dev/null +++ b/rest/resource-server/src/main/java/org/eclipse/sw360/rest/resourceserver/databasesanitation/Sw360DatabaseSanitationService.java @@ -0,0 +1,97 @@ +/* + * Copyright Siemens AG, 2023-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 + */ + +package org.eclipse.sw360.rest.resourceserver.databasesanitation; + +import static org.eclipse.sw360.datahandler.common.CommonUtils.allAreEmptyOrNull; +import static org.eclipse.sw360.datahandler.common.CommonUtils.oneIsNull; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +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.SW360Exception; +import org.eclipse.sw360.datahandler.thrift.components.ComponentService; +import org.eclipse.sw360.datahandler.thrift.projects.ProjectService; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.users.UserGroup; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class Sw360DatabaseSanitationService { + + @Value("${sw360.thrift-server-url:http://localhost:8080}") + private String thriftServerUrl; + + public Map duplicateIdentifiers(User sw360User) throws TException { + Map responseMap = new HashMap<>(); + + Map> duplicateComponents=null; + Map> duplicateReleases=null; + Map> duplicateReleaseSources=null; + Map> duplicateProjects=null; + try { + if (PermissionUtils.isUserAtLeast(UserGroup.ADMIN, sw360User)) { + ComponentService.Iface componentClient = getThriftComponentClient(); + ProjectService.Iface projectClient = getThriftProjectClient(); + duplicateComponents = componentClient.getDuplicateComponents(); + duplicateReleases = componentClient.getDuplicateReleases(); + duplicateReleaseSources = componentClient.getDuplicateReleaseSources(); + duplicateProjects = projectClient.getDuplicateProjects(); + } else { + throw new RuntimeException("User is not admin"); + } + } catch (SW360Exception exp) { + if (exp.getErrorCode() == 404) { + throw new ResourceNotFoundException(exp.getWhy()); + } else { + throw new RuntimeException(exp.getWhy()); + } + } + if (oneIsNull(duplicateComponents, duplicateReleases, duplicateProjects, duplicateReleaseSources)) { + throw new RuntimeException("Some duplicates are null"); + } else if (allAreEmptyOrNull(duplicateComponents, duplicateReleases, duplicateProjects, duplicateReleaseSources)) { + throw new RuntimeException("No duplicates found"); + } else { + responseMap.put("duplicateReleases", duplicateReleases); + responseMap.put("duplicateReleaseSources", duplicateReleaseSources); + responseMap.put("duplicateComponents", duplicateComponents); + responseMap.put("duplicateProjects", duplicateProjects); + } + return responseMap; + } + public ComponentService.Iface getThriftComponentClient() throws TTransportException { + THttpClient thriftClient = new THttpClient(thriftServerUrl + "/components/thrift"); + TProtocol protocol = new TCompactProtocol(thriftClient); + return new ComponentService.Client(protocol); + } + + public ProjectService.Iface getThriftProjectClient() throws TTransportException { + THttpClient thriftClient = new THttpClient(thriftServerUrl + "/projects/thrift"); + TProtocol protocol = new TCompactProtocol(thriftClient); + return new ProjectService.Client(protocol); + } + +} diff --git a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ApiSpecTest.java b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ApiSpecTest.java index ab953728f2..7c2e47f3ab 100644 --- a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ApiSpecTest.java +++ b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/ApiSpecTest.java @@ -181,6 +181,7 @@ public void should_document_index() throws Exception { linkWithRel("sw360:changeLogs").description("The <>"), linkWithRel("sw360:clearingRequests").description("The <>"), linkWithRel("sw360:obligations").description("The <>"), + linkWithRel("sw360:databaseSanitation").description("The <>"), linkWithRel("sw360:moderationRequests").description("The <>"), linkWithRel("sw360:fossology").description("The <>"), linkWithRel("sw360:schedule").description("The <>"), diff --git a/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/DatabaseSanitationSpecTest.java b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/DatabaseSanitationSpecTest.java new file mode 100644 index 0000000000..da5a5fcc41 --- /dev/null +++ b/rest/resource-server/src/test/java/org/eclipse/sw360/rest/resourceserver/restdocs/DatabaseSanitationSpecTest.java @@ -0,0 +1,134 @@ +/* + * Copyright Siemens AG, 2023-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 + */ + +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.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +import org.apache.thrift.TException; +import org.eclipse.sw360.datahandler.thrift.components.Component; +import org.eclipse.sw360.datahandler.thrift.components.Release; +import org.eclipse.sw360.datahandler.thrift.projects.Project; +import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.rest.resourceserver.TestHelper; +import org.eclipse.sw360.rest.resourceserver.databasesanitation.Sw360DatabaseSanitationService; +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.hateoas.MediaTypes; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.cloudant.client.api.model.Attachment; + +@RunWith(SpringJUnit4ClassRunner.class) +public class DatabaseSanitationSpecTest extends TestRestDocsSpecBase { + @Value("${sw360.test-user-id}") + private String testUserId; + + @Value("${sw360.test-user-password}") + private String testUserPassword; + + @MockBean + private Sw360UserService userServiceMock; + + @MockBean + private Sw360DatabaseSanitationService sanitationService; + + private Component component; + private Release release; + private Project project; + private Attachment attachment,attachment1 ; + + @Before + public void before() throws TException, IOException { + Map responseMap = new HashMap<>(); + + List attachmentList = new ArrayList(); + attachment = new Attachment(); + attachment.setContentType("12345"); + attachment1 = new Attachment(); + attachment.setContentType("1234"); + attachmentList.add(attachment); + attachmentList.add(attachment1); + attachment.setContentType("12345"); + + List componentList = new ArrayList<>(); + component = new Component(); + component.setName("Angular"); + component.unsetType(); + component.unsetVisbility(); + componentList.add(component); + + List releaseList = new ArrayList<>(); + release = new Release(); + release.setId("123456"); + release.unsetType(); + releaseList.add(release); + + List projectList = new ArrayList<>(); + project = new Project(); + project.setName("Emerald Web"); + project.unsetState(); + project.unsetSecurityResponsibles(); + project.unsetEnableSvm(); + project.unsetConsiderReleasesFromExternalList(); + project.unsetEnableVulnerabilitiesDisplay(); + project.unsetProjectType(); + project.unsetVisbility(); + projectList.add(project); + + User sw360User = new User(); + sw360User.setId("123456789"); + sw360User.setEmail("admin@sw360.org"); + sw360User.setFullname("John Doe"); + given(this.userServiceMock.getUserByEmailOrExternalId("admin@sw360.org")).willReturn( + new User("admin@sw360.org", "sw360").setId("123456789")); + Map> componentResponse = new HashMap<>(); + componentResponse.put("component", componentList); + + Map> releaseResponse = new HashMap<>(); + releaseResponse.put("release", releaseList); + + Map> releaseSourcesResponse = new HashMap<>(); + releaseSourcesResponse.put("attachment", attachmentList); + + Map> projectResponse = new HashMap<>(); + projectResponse.put("project", projectList); + + responseMap.put("duplicateReleases", releaseResponse); + responseMap.put("duplicateReleaseSources", releaseSourcesResponse); + responseMap.put("duplicateComponents", componentResponse); + responseMap.put("duplicateProjects", projectResponse); + given(this.sanitationService.duplicateIdentifiers(any())).willReturn(responseMap); + } + + @Test + public void should_document_search_duplicate() throws Exception { + String accessToken = TestHelper.getAccessToken(mockMvc, testUserId, testUserPassword); + mockMvc.perform(get("/api/databaseSanitation/searchDuplicate") + .header("Authorization", "Bearer " + accessToken) + .accept(MediaTypes.HAL_JSON)) + .andExpect(status().isOk()).andDo(this.documentationHandler.document()); + } +}