Skip to content

Commit b5cd1bd

Browse files
committed
fix(Rest): Create new endpoint to activate the department manually.
Signed-off-by: Nikesh kumar <[email protected]>
1 parent de15ed5 commit b5cd1bd

File tree

9 files changed

+471
-3
lines changed

9 files changed

+471
-3
lines changed

backend/users/src/main/java/org/eclipse/sw360/users/db/UserDatabaseHandler.java

+1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ public RequestSummary importFileToDB(String pathFolder) {
221221
return requestSummary;
222222
}
223223

224+
224225
public Map<String, List<String>> readFileCsv(String filePath) {
225226
Map<String, List<String>> listMap = new HashMap<>();
226227
List<String> emailCsv = new ArrayList<>();

backend/users/src/main/java/org/eclipse/sw360/users/util/ReadFileDepartmentConfig.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ protected String getPathConfig() throws IOException {
3535
String pathFile = file.getPath();
3636
String[] parts = pathFile.split("/");
3737
for (int i = 0; i < parts.length; i++) {
38-
if (!parts[i+1].contains("liferay"))
38+
if (!parts[i+1].contains("tomcat"))
3939
path.append(parts[i+1]).append("/");
4040
else {
4141
path.append(parts[i+1]).append("/");
@@ -75,9 +75,9 @@ public DepartmentConfigDTO readFileJson() {
7575
}
7676

7777
public void writePathFolderConfig(String pathFolder) {
78-
DepartmentConfigDTO configDTO = readFileJson();
7978
BufferedWriter writer = null;
8079
try {
80+
DepartmentConfigDTO configDTO = readFileJson();
8181
writer = Files.newBufferedWriter(Paths.get(getPathConfig()));
8282
Map<String, Object> config = new HashMap<>();
8383
Map<String, Object> map = new HashMap<>();
@@ -125,4 +125,4 @@ public void writeLastRunningTimeConfig(String lastRunningTime) {
125125
}
126126
}
127127
}
128-
}
128+
}

libraries/datahandler/src/main/java/org/eclipse/sw360/datahandler/common/SW360Constants.java

+4
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ public class SW360Constants {
134134
public static final String PROJECTS = "projects";
135135
public static final String LICENSES = "licenses";
136136
public static final String PROJECT_RELEASE_SPREADSHEET_WITH_ECCINFO = "projectReleaseSpreadSheetWithEcc";
137+
public static final String IMPORT_DEPARTMENT_MANUALLY = "importdepartmentmanually";
138+
public static final String ADD_LIST_EMAIL = "listEmail";
139+
public static final String DEPARTMENT_KEY = "departmentKey";
140+
public static final String DELETE_LIST_EMAIL = "deleteEmail";
137141

138142
/**
139143
* Hashmap containing the name field for each type.

rest/resource-server/src/docs/asciidoc/api-guide.adoc

+1
Original file line numberDiff line numberDiff line change
@@ -312,3 +312,4 @@ include::importExport.adoc[]
312312
include::attachmentCleanUp.adoc[]
313313
include::databaseSanitation.adoc[]
314314
include::importExport.adoc[]
315+
include::department.adoc[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
//
2+
// Copyright Siemens AG, 2025. Part of the SW360 Portal Project.
3+
//
4+
// This program and the accompanying materials are made
5+
// available under the terms of the Eclipse Public License 2.0
6+
// which is available at https://www.eclipse.org/legal/epl-2.0/
7+
//
8+
// SPDX-License-Identifier: EPL-2.0
9+
// SPDX-FileCopyrightText: 2025, Siemens AG. Part of the SW360 Portal Project.
10+
// SPDX-FileContributor: Nikesh kumar <[email protected]>
11+
//
12+
13+
[[resources-department]]
14+
=== Department
15+
16+
The department resource is used to upload a department and its members.
17+
18+
[[manually-active]]
19+
==== Manually Activating Department Import
20+
21+
A `GET` request is used to import department data.
22+
23+
===== Example Request
24+
include::{snippets}/should_document_import_department_manually/curl-request.adoc[]
25+
26+
===== Example Response
27+
include::{snippets}/should_document_import_department_manually/http-response.adoc[]
28+
29+
[[schedule-department]]
30+
==== Import Schedule Department.
31+
32+
A `POST` request is used to import schedule department.
33+
34+
===== Example Request
35+
include::{snippets}/should_document_import_schedule_department/curl-request.adoc[]
36+
37+
===== Example Response
38+
include::{snippets}/should_document_import_schedule_department/http-response.adoc[]
39+
40+
[[cancel-department]]
41+
==== Cancel Schedule Department.
42+
43+
A `POST` request is used to cancel import schedule department.
44+
45+
===== Example Request
46+
include::{snippets}/should_document_cancel_import_schedule_department/curl-request.adoc[]
47+
48+
===== Example Response
49+
include::{snippets}/should_document_cancel_import_schedule_department/http-response.adoc[]
50+
51+
[[update-folder-path]]
52+
==== Update Folder Path.
53+
54+
A POST request is used to update the folder path in the department.
55+
56+
===== Example Request
57+
include::{snippets}/should_document_update_folder_path/curl-request.adoc[]
58+
59+
===== Example Response
60+
include::{snippets}/should_document_update_folder_path/http-response.adoc[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright Siemens AG,2025.
3+
* Part of the SW360 Portal Project.
4+
*
5+
* This program and the accompanying materials are made
6+
* available under the terms of the Eclipse Public License 2.0
7+
* which is available at https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*/
11+
12+
package org.eclipse.sw360.rest.resourceserver.department;
13+
14+
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
15+
16+
import java.util.Collections;
17+
import java.util.HashMap;
18+
import java.util.Map;
19+
20+
import org.apache.logging.log4j.LogManager;
21+
import org.apache.logging.log4j.Logger;
22+
import org.apache.thrift.TException;
23+
import org.eclipse.sw360.datahandler.common.SW360Constants;
24+
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
25+
import org.eclipse.sw360.datahandler.thrift.RequestSummary;
26+
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
27+
import org.eclipse.sw360.datahandler.thrift.users.User;
28+
import org.eclipse.sw360.rest.resourceserver.core.RestControllerHelper;
29+
import org.springframework.beans.factory.annotation.Autowired;
30+
import org.springframework.data.rest.webmvc.BasePathAwareController;
31+
import org.springframework.data.rest.webmvc.RepositoryLinksResource;
32+
import org.springframework.hateoas.server.RepresentationModelProcessor;
33+
import org.springframework.http.HttpStatus;
34+
import org.springframework.http.ResponseEntity;
35+
import org.springframework.security.access.prepost.PreAuthorize;
36+
import org.springframework.web.bind.annotation.RequestBody;
37+
import org.springframework.web.bind.annotation.RequestMapping;
38+
import org.springframework.web.bind.annotation.RequestMethod;
39+
import org.springframework.web.bind.annotation.RequestParam;
40+
import org.springframework.web.bind.annotation.RestController;
41+
42+
import com.google.common.base.Strings;
43+
44+
import io.swagger.v3.oas.annotations.Operation;
45+
import io.swagger.v3.oas.annotations.Parameter;
46+
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
47+
import jakarta.servlet.http.HttpServletRequest;
48+
import lombok.NonNull;
49+
import lombok.RequiredArgsConstructor;
50+
51+
@BasePathAwareController
52+
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
53+
@RestController
54+
@SecurityRequirement(name = "tokenAuth")
55+
@PreAuthorize("hasAuthority('ADMIN')")
56+
public class DepartmentController implements RepresentationModelProcessor<RepositoryLinksResource>{
57+
public static final String DEPARTMENT_URL = "/departments";
58+
private static final Logger log = LogManager.getLogger(DepartmentController.class);
59+
60+
@NonNull
61+
private final Sw360DepartmentService departmentService;
62+
63+
@NonNull
64+
private final RestControllerHelper restControllerHelper;
65+
66+
@Override
67+
public RepositoryLinksResource process(RepositoryLinksResource resource) {
68+
resource.add(linkTo(DepartmentController.class).slash("api" + DEPARTMENT_URL).withRel("department"));
69+
return resource;
70+
}
71+
72+
@Operation(
73+
description = "Manually active the service.",
74+
tags = {"Department"}
75+
)
76+
@RequestMapping(value = DEPARTMENT_URL + "/manuallyActive", method = RequestMethod.POST)
77+
public ResponseEntity<RequestSummary> importDepartmentManually()
78+
throws TException {
79+
try {
80+
User user = restControllerHelper.getSw360UserFromAuthentication();
81+
RequestSummary requestSummary = departmentService.importDepartmentManually(user);
82+
return ResponseEntity.ok(requestSummary);
83+
} catch (TException e) {
84+
log.error("Error importing department", e);
85+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
86+
}
87+
}
88+
89+
@Operation(
90+
description = "Schedule import.",
91+
tags = {"Department"}
92+
)
93+
@RequestMapping(value = DEPARTMENT_URL + "/scheduleImport", method = RequestMethod.POST)
94+
public ResponseEntity<Map<String, String>> scheduleImportDepartment() {
95+
try {
96+
User user = restControllerHelper.getSw360UserFromAuthentication();
97+
98+
if (departmentService.isDepartmentScheduled(user)) {
99+
return ResponseEntity.status(HttpStatus.CONFLICT)
100+
.body(Collections.singletonMap("message", "Department import is already scheduled."));
101+
}
102+
103+
RequestSummary requestSummary = departmentService.scheduleImportDepartment(user);
104+
105+
Map<String, String> response = new HashMap<>();
106+
response.put("status", requestSummary.getRequestStatus().name());
107+
response.put("message", "Department import scheduled successfully");
108+
109+
return ResponseEntity.ok(response);
110+
} catch (SW360Exception e) {
111+
log.error("Schedule check failed: {}", e.getMessage());
112+
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
113+
.body(Collections.singletonMap("error", e.getMessage()));
114+
} catch (TException e) {
115+
log.error("Schedule import department: {}", e.getMessage());
116+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
117+
.body(Collections.singletonMap("error", "Failed to schedule department import"));
118+
}
119+
}
120+
121+
@Operation(summary = "Unschedule Department Import",
122+
description = "Cancels the scheduled import task for the department.",
123+
tags = {"Department"})
124+
@RequestMapping(value = DEPARTMENT_URL + "/unscheduleImport", method = RequestMethod.POST)
125+
public ResponseEntity<Map<String, String>> unScheduleImportDepartment() throws TException {
126+
127+
try {
128+
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
129+
RequestStatus requestStatus = departmentService.unScheduleImportDepartment(sw360User);
130+
131+
Map<String, String> response = new HashMap<>();
132+
response.put("status", requestStatus.name());
133+
response.put("message", "Department import unscheduled successfully");
134+
135+
return ResponseEntity.ok(response);
136+
} catch (TException e) {
137+
log.error("Failed to cancel scheduled department import: {}", e.getMessage());
138+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
139+
.body(Collections.singletonMap("error", "Failed to unschedule department import"));
140+
}
141+
}
142+
143+
@Operation(summary = "Update Folder Path Configuration",
144+
description = "Updates the department folder path configuration.")
145+
@RequestMapping(value = DEPARTMENT_URL + "/writePathFolder", method = RequestMethod.POST)
146+
public ResponseEntity<String> updatePath(
147+
@Parameter(description = "The path of the folder")
148+
@RequestParam String pathFolder) {
149+
try {
150+
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
151+
departmentService.writePathFolderConfig(pathFolder, sw360User);
152+
return ResponseEntity.ok("Path updated successfully.");
153+
} catch (Exception e) {
154+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
155+
.body("Error updating path: " + e.getMessage());
156+
}
157+
}
158+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright Siemens AG,2025.
3+
* Part of the SW360 Portal Project.
4+
*
5+
* This program and the accompanying materials are made
6+
* available under the terms of the Eclipse Public License 2.0
7+
* which is available at https://www.eclipse.org/legal/epl-2.0/
8+
*
9+
* SPDX-License-Identifier: EPL-2.0
10+
*/
11+
12+
package org.eclipse.sw360.rest.resourceserver.department;
13+
14+
import java.io.BufferedWriter;
15+
import java.io.File;
16+
import java.io.FileNotFoundException;
17+
import java.io.IOException;
18+
import java.io.Reader;
19+
import java.nio.file.Files;
20+
import java.nio.file.Paths;
21+
import java.util.ArrayList;
22+
import java.util.Arrays;
23+
import java.util.Collections;
24+
import java.util.HashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.stream.Collectors;
28+
29+
import org.apache.logging.log4j.LogManager;
30+
import org.apache.logging.log4j.Logger;
31+
import org.apache.thrift.TException;
32+
import org.eclipse.sw360.datahandler.common.SW360Constants;
33+
import org.eclipse.sw360.datahandler.permissions.PermissionUtils;
34+
import org.eclipse.sw360.datahandler.thrift.RequestStatus;
35+
import org.eclipse.sw360.datahandler.thrift.RequestStatusWithBoolean;
36+
import org.eclipse.sw360.datahandler.thrift.RequestSummary;
37+
import org.eclipse.sw360.datahandler.thrift.SW360Exception;
38+
import org.eclipse.sw360.datahandler.thrift.ThriftClients;
39+
import org.eclipse.sw360.datahandler.thrift.schedule.ScheduleService;
40+
import org.eclipse.sw360.datahandler.thrift.users.DepartmentConfigDTO;
41+
import org.eclipse.sw360.datahandler.thrift.users.User;
42+
import org.eclipse.sw360.datahandler.thrift.users.UserGroup;
43+
import org.eclipse.sw360.datahandler.thrift.users.UserService;
44+
import org.springframework.beans.factory.annotation.Autowired;
45+
import org.springframework.beans.factory.annotation.Value;
46+
import org.springframework.security.access.AccessDeniedException;
47+
import org.springframework.stereotype.Service;
48+
49+
import com.fasterxml.jackson.databind.JsonNode;
50+
import com.fasterxml.jackson.databind.ObjectMapper;
51+
import com.fasterxml.jackson.databind.node.ObjectNode;
52+
53+
import jakarta.servlet.http.HttpServletRequest;
54+
import jakarta.servlet.http.HttpServletResponse;
55+
import lombok.RequiredArgsConstructor;
56+
57+
@Service
58+
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
59+
public class Sw360DepartmentService {
60+
private static final Logger log = LogManager.getLogger(Sw360DepartmentService.class);
61+
@Value("${sw360.thrift-server-url:http://localhost:8080}")
62+
private String thriftServerUrl;
63+
ThriftClients thriftClients = new ThriftClients();
64+
65+
public RequestSummary importDepartmentManually(User sw360User) throws TException {
66+
try {
67+
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, sw360User)) {
68+
throw new AccessDeniedException("User is not admin");
69+
}
70+
UserService.Iface userClient = thriftClients.makeUserClient();
71+
return userClient.importFileToDB();
72+
} catch (TException e) {
73+
log.error("Error occurred while scheduling service", e);
74+
throw e;
75+
}
76+
}
77+
78+
public boolean isDepartmentScheduled(User user) throws TException {
79+
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, user)) {
80+
throw new AccessDeniedException("User is not an admin");
81+
}
82+
ScheduleService.Iface scheduleClient = thriftClients.makeScheduleClient();
83+
RequestStatusWithBoolean requestStatus = scheduleClient
84+
.isServiceScheduled(ThriftClients.IMPORT_DEPARTMENT_SERVICE, user);
85+
if (RequestStatus.SUCCESS.equals(requestStatus.getRequestStatus())) {
86+
return requestStatus.isAnswerPositive();
87+
} else {
88+
throw new SW360Exception("Backend query for schedule status of department failed.");
89+
}
90+
}
91+
92+
public RequestSummary scheduleImportDepartment(User user) throws TException {
93+
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, user)) {
94+
throw new AccessDeniedException("User is not an admin");
95+
}
96+
ScheduleService.Iface scheduleClient = thriftClients.makeScheduleClient();
97+
RequestStatusWithBoolean requestStatus = scheduleClient
98+
.isServiceScheduled(ThriftClients.IMPORT_DEPARTMENT_SERVICE, user);
99+
if (RequestStatus.SUCCESS.equals(requestStatus.getRequestStatus()) && requestStatus.isAnswerPositive()) {
100+
throw new SW360Exception("Department import is already scheduled.");
101+
}
102+
return scheduleClient.scheduleService(ThriftClients.IMPORT_DEPARTMENT_SERVICE);
103+
}
104+
105+
public RequestStatus unScheduleImportDepartment(User user) throws TException {
106+
return thriftClients.makeScheduleClient().unscheduleService(ThriftClients.IMPORT_DEPARTMENT_SERVICE,
107+
user);
108+
}
109+
110+
public void writePathFolderConfig(String pathFolder, User user) throws TException {
111+
if (!PermissionUtils.isUserAtLeast(UserGroup.ADMIN, user)) {
112+
throw new AccessDeniedException("User is not an admin");
113+
}
114+
UserService.Iface userClient = thriftClients.makeUserClient();
115+
if (userClient == null) {
116+
throw new TException("Failed to create UserService client");
117+
}
118+
userClient.writePathFolderConfig(pathFolder);
119+
}
120+
}
121+

0 commit comments

Comments
 (0)