Skip to content

Commit

Permalink
fix(Rest): Create new endpoint to activate the department manually.
Browse files Browse the repository at this point in the history
Signed-off-by: Nikesh kumar <[email protected]>
  • Loading branch information
nikkuma7 committed Feb 14, 2025
1 parent de15ed5 commit 275565c
Show file tree
Hide file tree
Showing 7 changed files with 343 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public class SW360Constants {
public static final String PROJECTS = "projects";
public static final String LICENSES = "licenses";
public static final String PROJECT_RELEASE_SPREADSHEET_WITH_ECCINFO = "projectReleaseSpreadSheetWithEcc";
public static final String IMPORT_DEPARTMENT_MANUALLY = "importdepartmentmanually";

/**
* Hashmap containing the name field for each type.
Expand Down
1 change: 1 addition & 0 deletions rest/resource-server/src/docs/asciidoc/api-guide.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -312,3 +312,4 @@ include::importExport.adoc[]
include::attachmentCleanUp.adoc[]
include::databaseSanitation.adoc[]
include::importExport.adoc[]
include::department.adoc[]
38 changes: 38 additions & 0 deletions rest/resource-server/src/docs/asciidoc/department.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// 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
// SPDX-FileCopyrightText: 2024, Siemens AG. Part of the SW360 Portal Project.
// SPDX-FileContributor: Nikesh kumar <[email protected]>
//

[[resources-department]]
=== Department

The department resource is used to upload a department and its members.

[[manually-active]]
==== Manually Activating Department Import

A `GET` request is used to import department data.

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

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

[[schedule-department]]
==== Import Schedule Department.

A `POST` request is used to import schedule department.

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

===== Example Response
include::{snippets}/should_document_import_schedule_department/http-response.adoc[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* 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.department;

import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.common.SW360Constants;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.RequestSummary;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
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.server.RepresentationModelProcessor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
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 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 DepartmentController implements RepresentationModelProcessor<RepositoryLinksResource>{
public static final String DEPARTMENT_URL = "/department";
private static final Logger log = LogManager.getLogger(DepartmentController.class);

@NonNull
private final Sw360DepartmentService departmentService;

@NonNull
private final RestControllerHelper restControllerHelper;

@Override
public RepositoryLinksResource process(RepositoryLinksResource resource) {
resource.add(linkTo(DepartmentController.class).slash("api" + DEPARTMENT_URL).withRel("department"));
return resource;
}

@Operation(
description = "Manually active the service.",
tags = {"Department"}
)
@RequestMapping(value = DEPARTMENT_URL + "/manuallyactive", method = RequestMethod.POST)
public ResponseEntity<RequestSummary> importDepartmentManually(
@Parameter(description = "Request body containing the action key for manual import")
@RequestBody Map<String, String> requestBody)
throws TException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();

String action = requestBody.get("action");
if (action == null || !SW360Constants.IMPORT_DEPARTMENT_MANUALLY.equals(action)) {
log.warn("Unsupported or missing action: " + action);
return ResponseEntity.badRequest().build();
}
return processAction(sw360User);
}

private ResponseEntity<RequestSummary> processAction(User sw360User) {
try {
RequestSummary requestSummary = departmentService.importDepartmentManually(sw360User);
return ResponseEntity.ok(requestSummary);
} catch (TException e) {
log.error("Error importing department", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}

@RequestMapping(value = DEPARTMENT_URL + "/scheduleImport", method = RequestMethod.POST)
public ResponseEntity<Map<String, String>> scheduleImportDepartment(
@Parameter(description = "The email of the user")
@RequestParam String userEmail) {
try {
User user = restControllerHelper.getUserByEmail(userEmail);

if (departmentService.isDepartmentScheduled(user)) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(Collections.singletonMap("message", "Department import is already scheduled."));
}

RequestSummary requestSummary = departmentService.scheduleImportDepartment(user);

Map<String, String> response = new HashMap<>();
response.put("status", requestSummary.getRequestStatus().name());
response.put("message", "Department import scheduled successfully");

return ResponseEntity.ok(response);
} catch (SW360Exception e) {
log.error("Schedule check failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(Collections.singletonMap("error", e.getMessage()));
} catch (TException e) {
log.error("Schedule import department: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(Collections.singletonMap("error", "Failed to schedule department import"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* 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.department;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
import org.eclipse.sw360.datahandler.thrift.RequestStatusWithBoolean;
import org.eclipse.sw360.datahandler.thrift.RequestSummary;
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
import org.eclipse.sw360.datahandler.thrift.ThriftClients;
import org.eclipse.sw360.datahandler.thrift.schedule.ScheduleService;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.datahandler.thrift.users.UserGroup;
import org.eclipse.sw360.datahandler.thrift.users.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Sw360DepartmentService {
private static final Logger log = LogManager.getLogger(Sw360DepartmentService.class);

@Value("${sw360.thrift-server-url:http://localhost:8080}")
private String thriftServerUrl;

public RequestSummary importDepartmentManually(User sw360User) throws TException {
try {
if (PermissionUtils.isUserAtLeast(UserGroup.ADMIN, sw360User)) {
ThriftClients thriftClients = new ThriftClients();
UserService.Iface userClient = thriftClients.makeUserClient();
RequestSummary request = userClient.importFileToDB();
return request;
} else {
throw new AccessDeniedException("User is not admin");
}
} catch (TException e) {
log.error("Error occurred while scheduling service: " + e);
throw e;
}
}

public boolean isDepartmentScheduled(User user) throws TException {
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, user)) {
throw new AccessDeniedException("User is not an admin");
}
ScheduleService.Iface scheduleClient = new ThriftClients().makeScheduleClient();
RequestStatusWithBoolean requestStatus = scheduleClient
.isServiceScheduled(ThriftClients.IMPORT_DEPARTMENT_SERVICE, user);
if (RequestStatus.SUCCESS.equals(requestStatus.getRequestStatus())) {
return requestStatus.isAnswerPositive();
} else {
throw new SW360Exception("Backend query for schedule status of department failed.");
}
}

public RequestSummary scheduleImportDepartment(User user) throws TException {
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, user)) {
throw new AccessDeniedException("User is not an admin");
}
ScheduleService.Iface scheduleClient = new ThriftClients().makeScheduleClient();
RequestStatusWithBoolean requestStatus = scheduleClient.isServiceScheduled(ThriftClients.IMPORT_DEPARTMENT_SERVICE, user);
if (RequestStatus.SUCCESS.equals(requestStatus.getRequestStatus()) && requestStatus.isAnswerPositive()) {
throw new SW360Exception("Department import is already scheduled.");
}
return scheduleClient.scheduleService(ThriftClients.IMPORT_DEPARTMENT_SERVICE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public void should_document_index() throws Exception {
linkWithRel("sw360:ecc").description("The <<resources-ecc,Ecc resource>>"),
linkWithRel("sw360:attachmentCleanUp").description("The <<resources-attachmentCleanUp,attachmentCleanUp resource>>"),
linkWithRel("sw360:importExport").description("The <<resources-importExport,ImportExport resource>>"),
linkWithRel("sw360:department").description("The <<resources-department,Department resource>>"),
linkWithRel("curies").description("The Curies for documentation"),
linkWithRel("profile").description("The profiles of the REST resources")
),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* 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.mockito.Mockito.when;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.HashMap;
import java.util.Map;

import org.apache.thrift.TException;
import org.eclipse.sw360.datahandler.common.SW360Constants;
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.TestHelper;
import org.eclipse.sw360.rest.resourceserver.department.Sw360DepartmentService;
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.http.MediaType;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.fasterxml.jackson.databind.ObjectMapper;

@RunWith(SpringJUnit4ClassRunner.class)
public class DepartmentSpecTest extends TestRestDocsSpecBase {
@Value("${sw360.test-user-id}")
private String testUserId;

@Value("${sw360.test-user-password}")
private String testUserPassword;

@MockBean
private Sw360DepartmentService departmentServiceMock;
private RequestSummary requestSummary = new RequestSummary();

@Before
public void before() throws TException {
User sw360User = new User();
sw360User.setId("123456789");
sw360User.setEmail("[email protected]");
sw360User.setFullname("John Doe");
given(this.userServiceMock.getUserByEmailOrExternalId("[email protected]")).willReturn(sw360User);
given(this.departmentServiceMock.importDepartmentManually(any())).willReturn(requestSummary);
given(this.departmentServiceMock.scheduleImportDepartment(any())).willReturn(requestSummary);
when(departmentServiceMock.isDepartmentScheduled(sw360User)).thenReturn(false);
}

@Test
public void should_document_import_department_manually() throws Exception {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("action", SW360Constants.IMPORT_DEPARTMENT_MANUALLY);

mockMvc.perform(post("/api/department/manuallyactive")
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestBody))
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk());
}

@Test
public void should_document_import_schedule_department() throws Exception {
String userEmail = "[email protected]";
RequestSummary mockRequestSummary = new RequestSummary();
mockRequestSummary.setRequestStatus(RequestStatus.SUCCESS);
when(departmentServiceMock.scheduleImportDepartment(any())).thenReturn(mockRequestSummary);
mockMvc.perform(post("/api/department/scheduleImport")
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
.param("userEmail", userEmail)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}

}

0 comments on commit 275565c

Please sign in to comment.