Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rest): endpoint to remove orphaned obligations from project. #2597

Merged
merged 1 commit into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions rest/resource-server/src/docs/asciidoc/projects.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,20 @@ include::{snippets}/should_document_delete_project/curl-request.adoc[]
===== Example response
include::{snippets}/should_document_delete_project/http-response.adoc[]

[[resources-projects-remove-orphaned-obligations]]
==== Remove orphaned obligations

A `PATCH` request will update the project's obligations.

===== Request structure 1
Pass an array of orphaned obligations title in request body.

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

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

[[resources-project-link-projects]]
==== Link project to the projects

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2527,6 +2527,44 @@ private Map<String, Object> createPaginationMetadata(Pageable pageable, Map<Stri
return responseBody;
}

@PreAuthorize("hasAuthority('WRITE')")
@Operation(
summary = "delete orphan obligations",
description = "Pass an array of orphan obligation titles in request body.",
tags = {"Projects"}
)
@RequestMapping(value = PROJECTS_URL + "/{id}/orphanObligation", method = RequestMethod.PATCH)
public ResponseEntity<?> removeOrphanObligation(
@Parameter(description = "Project ID.")
@PathVariable("id") String id,
@Parameter(description = "Array of orphaned obligations title",
examples = {
@ExampleObject(value = "[\"title1\",\"title2\",\"title3\"]")
// TODO: Add example for MAP value
}
)
@RequestBody List<String> obligationTitlesInRequestBody
) throws URISyntaxException, TException {
final User sw360User = restControllerHelper.getSw360UserFromAuthentication();
final Project sw360Project = projectService.getProjectForUserById(id, sw360User);

ObligationList obligation = new ObligationList();
RequestStatus status = null;
Map<String, ObligationStatusInfo> obligationStatusMap = Maps.newHashMap();

if (CommonUtils.isNotNullEmptyOrWhitespace(sw360Project.getLinkedObligationId())) {
obligation = projectService.getObligationData(sw360Project.getLinkedObligationId(), sw360User);
obligationStatusMap = CommonUtils.nullToEmptyMap(obligation.getLinkedObligationStatus());
status = projectService.removeOrphanObligations(obligationStatusMap, obligationTitlesInRequestBody, sw360Project, sw360User, obligation);
} else {
return new ResponseEntity<>("No linked obligation found for the project", HttpStatus.NOT_FOUND);
}
if (status == RequestStatus.SUCCESS) {
return new ResponseEntity<>("Orphaned Obligation Removed Successfully", HttpStatus.OK);
}
return new ResponseEntity<>("Failed to Remove Orphaned Obligation", HttpStatus.NOT_FOUND);
}

@Operation(
description = "Get license obligation data of project tab.",
tags = {"Project"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,28 @@ static AttachmentUsage mergeAttachmentUsages(AttachmentUsage u1, AttachmentUsage
return mergedUsage;
}

public RequestStatus removeOrphanObligations(Map<String, ObligationStatusInfo> obligationStatusMap, List<String> obligationTitlesInRequestBody, Project project, User user, ObligationList obligation) {
try {
ThriftClients thriftClients = new ThriftClients();
ProjectService.Iface client = thriftClients.makeProjectClient();
RequestStatus status = null;

for (String topic : obligationTitlesInRequestBody) {
if (obligationStatusMap.containsKey(topic)) {
obligationStatusMap.remove(topic);
} else {
status = RequestStatus.FAILURE;
return status;
}
}
status = client.updateLinkedObligations(obligation, user);
return status;
} catch (TException exception) {
log.error("Failed to remove orphan obligation for project: " + project.getId(), exception);
}
return RequestStatus.FAILURE;
}

public Map<String, ObligationStatusInfo> getLicenseObligationData(Map<String, Set<Release>> licensesFromAttachmentUsage, User user) {
ThriftClients thriftClients = new ThriftClients();
LicenseService.Iface licenseClient = thriftClients.makeLicenseClient();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -444,9 +444,10 @@ public void before() throws TException, IOException {
project8.setId("123456733");
project8.setName("oblProject");
project8.setVersion("3");
project8.setLinkedObligationId("0001");
project8.setLinkedObligationId("009");
linkedReleases3.put("376527651233", projectReleaseRelationship);
project8.setReleaseIdToUsage(linkedReleases3);
List<String> title = Arrays.asList("obligation_title");

Source ownerSrc3 = Source.releaseId("376527651233");
Source usedBySrc3 = Source.projectId("123456733");
Expand Down Expand Up @@ -599,6 +600,7 @@ public void before() throws TException, IOException {
given(this.projectServiceMock.validate(any(), any(), any(), any())).willReturn(true);
given(this.projectServiceMock.deselectedAttachmentUsagesFromRequest(any(), eq(selectedUsages), any(), any(), any())).willReturn(deselectedUsagesFromRequest);
given(this.projectServiceMock.selectedAttachmentUsagesFromRequest(any(), eq(selectedUsages), any(), any(), any())).willReturn(selectedUsagesFromRequest);
given(this.projectServiceMock.removeOrphanObligations(eq(obligationStatusMap), any(), eq(project8), any(), eq(obligationLists))).willReturn(RequestStatus.SUCCESS);
given(this.projectServiceMock.getProjectForUserById(eq(projectForAtt.getId()), any())).willReturn(projectForAtt);
given(this.projectServiceMock.getProjectForUserById(eq(SPDXProject.getId()), any())).willReturn(SPDXProject);
given(this.projectServiceMock.getProjectForUserById(eq(cycloneDXProject.getId()), any())).willReturn(cycloneDXProject);
Expand Down Expand Up @@ -2226,6 +2228,17 @@ public void should_document_delete_project() throws Exception {
.andExpect(status().isOk());
}

@Test
public void should_document_remove_orphaned_obligations() throws Exception {
List<String> orphanedObligationTitles = Arrays.asList("obligation_title");
mockMvc.perform(patch("/api/projects/" + project8.getId() + "/orphanObligation")
.content(this.objectMapper.writeValueAsString(orphanedObligationTitles))
.header("Authorization", TestHelper.generateAuthHeader(testUserId, testUserPassword))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaTypes.HAL_JSON))
.andExpect(status().isOk());
}

private void add_patch_releases(MockHttpServletRequestBuilder requestBuilder) throws Exception {
List<String> releaseIds = Arrays.asList("3765276512", "5578999", "3765276513");

Expand Down