Skip to content

Implement location and archiving api #496

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

Draft
wants to merge 23 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
1a3b6eb
merge feature/data-resource-history
cgutmann Feb 27, 2025
1304b93
updated archiving API, added search endpoint
cgutmann Nov 4, 2024
2f4a638
added location to resource & assignedResources to location
cgutmann Nov 6, 2024
164392b
feat: implement location api
cgutmann Nov 18, 2024
bdd0a2c
feat: implement archiving api search endpoint
cgutmann Nov 19, 2024
3e2de88
feat: implement archiving api WIP disabled security
cgutmann Dec 12, 2024
4e02a58
feat: implement api changes
cgutmann Dec 17, 2024
09a7f9b
fix: Fix listHistoryVersionsByUUID query
cgutmann Dec 17, 2024
d242091
test: Add test case for archiving api retrieveArchivedResourceHistory…
cgutmann Dec 17, 2024
1a29c25
test: Add missing ArchivedResourceVersionTestDataBuilder file
cgutmann Dec 17, 2024
15a2d62
feat: implement automatic location assigning on scl resource update
cgutmann Jan 9, 2025
1224a3a
chore: split up archived scl data persistence from CompasSclDataService
cgutmann Jan 14, 2025
143119e
fix: fix unassigning resources from location
cgutmann Jan 17, 2025
f02c3a7
chore: rename function for saving related resources to FS
cgutmann Jan 21, 2025
ce73d9f
feat: implement storing archived resources in elo client
cgutmann Feb 20, 2025
91d3b16
chore: add elo connector and wiremock to docker compose file
cgutmann Feb 20, 2025
4e08ef8
chore: update elo tags for resources and locations
cgutmann Feb 20, 2025
dc9fa97
chore: remove elo connector setup from docker-compose.yml
cgutmann Feb 24, 2025
b0f20e9
feat: implement creating location in elo
cgutmann Feb 24, 2025
86d8284
chore: move location creation to when resource is archived
cgutmann Feb 27, 2025
00b2b01
chore: use location key instead of location name for archiving
cgutmann Mar 3, 2025
990f355
chore: use location key instead of location name as resource tag
cgutmann Mar 3, 2025
ada4773
test: fix scl data service unit tests
cgutmann Mar 3, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ target
out
lib
bin
data
.java-version
*.orig
*.rej
Expand Down
81 changes: 78 additions & 3 deletions app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ SPDX-License-Identifier: Apache-2.0
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jaxb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets</artifactId>
Expand Down Expand Up @@ -191,6 +195,79 @@ SPDX-License-Identifier: Apache-2.0
</executions>
</plugin>

<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.8.0</version>
<executions>
<execution>
<id>generate-history-api</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/openapi/history-api.yaml</inputSpec>
<generatorName>jaxrs-spec</generatorName>
<output>${project.build.directory}/generated-sources/openapi</output>
<library>quarkus</library>
<apiPackage>org.lfenergy.compas.scl.data.rest.api.scl</apiPackage>
<modelPackage>org.lfenergy.compas.scl.data.rest.api.scl.model</modelPackage>
<generateSupportingFiles>false</generateSupportingFiles>
<configOptions>
<useTags>true</useTags>
<interfaceOnly>true</interfaceOnly>
<dateLibrary>java8</dateLibrary>
<supportAsync>true</supportAsync>
<useMutiny>true</useMutiny>
<useJakartaEe>true</useJakartaEe>
</configOptions>
</configuration>
</execution>
<!-- <execution> &lt;!&ndash; note: disabled because bug in maven codegen doesn't allow custom properties&ndash;&gt;-->
<!-- <id>generate-archiving-api</id>-->
<!-- <goals>-->
<!-- <goal>generate</goal>-->
<!-- </goals>-->
<!-- <configuration>-->
<!-- <inputSpec>${project.basedir}/src/main/openapi/archiving-api.yaml</inputSpec>-->
<!-- <generatorName>jaxrs-spec</generatorName>-->
<!-- <output>${project.build.directory}/generated-sources/openapi</output>-->
<!-- <library>quarkus</library>-->
<!-- <apiPackage>org.lfenergy.compas.scl.data.rest.api.locations</apiPackage>-->
<!-- <modelPackage>org.lfenergy.compas.scl.data.rest.api.locations.model</modelPackage>-->
<!-- <generateSupportingFiles>false</generateSupportingFiles>-->
<!-- <configOptions>-->
<!-- <useTags>true</useTags>-->
<!-- <interfaceOnly>true</interfaceOnly>-->
<!-- <dateLibrary>java8</dateLibrary>-->
<!-- <supportAsync>true</supportAsync>-->
<!-- <useMutiny>true</useMutiny>-->
<!-- <useJakartaEe>true</useJakartaEe>-->
<!-- </configOptions>-->
<!-- </configuration>-->
<!-- </execution>-->
</executions>
</plugin>

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.build.directory}/generated-sources/openapi/src/gen/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
Expand All @@ -201,6 +278,7 @@ SPDX-License-Identifier: Apache-2.0
</systemPropertyVariables>
</configuration>
</plugin>

</plugins>
</build>

Expand Down Expand Up @@ -242,7 +320,6 @@ SPDX-License-Identifier: Apache-2.0

<profile>
<id>native-image</id>

<properties>
<!-- Make a Docker Image, so the integration tests will be executed against the container -->
<quarkus.container-image.build>true</quarkus.container-image.build>
Expand All @@ -267,7 +344,6 @@ SPDX-License-Identifier: Apache-2.0

<profile>
<id>sonar</id>

<properties>
<sonar.coverage.jacoco.xmlReportPaths>
target/jacoco-report/jacoco.xml,
Expand All @@ -278,7 +354,6 @@ SPDX-License-Identifier: Apache-2.0

<profile>
<id>release</id>

<properties>
<!-- Make a Docker Image from the component -->
<quarkus.container-image.build>true</quarkus.container-image.build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.lfenergy.compas.scl.data.config;

import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.config.inject.ConfigProperty;

@ApplicationScoped
public class FeatureFlagService {

@ConfigProperty(name = "scl-data-service.features.is-history-enabled", defaultValue = "true")
boolean isHistoryEnabled;
@ConfigProperty(name = "scl-data-service.features.keep-deleted-files", defaultValue = "true")
boolean keepDeletedFiles;

public boolean isHistoryEnabled() {
return isHistoryEnabled;
}

public boolean keepDeletedFiles() {
return keepDeletedFiles;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package org.lfenergy.compas.scl.data.rest.api.archive;

import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.infrastructure.Infrastructure;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.lfenergy.compas.scl.data.model.*;
import org.lfenergy.compas.scl.data.rest.UserInfoProperties;
import org.lfenergy.compas.scl.data.rest.api.archive.model.ArchivedResourceVersion;
import org.lfenergy.compas.scl.data.rest.api.archive.model.*;
import org.lfenergy.compas.scl.data.service.CompasSclDataService;

import java.io.File;
import java.time.OffsetDateTime;
import java.util.UUID;

@RequestScoped
public class ArchiveResource implements ArchivingApi {

private static final Logger LOGGER = LogManager.getLogger(ArchiveResource.class);
private final CompasSclDataService compasSclDataService;
private final JsonWebToken jsonWebToken;
private final UserInfoProperties userInfoProperties;

@Inject
public ArchiveResource(CompasSclDataService compasSclDataService, JsonWebToken jsonWebToken, UserInfoProperties userInfoProperties) {
this.compasSclDataService = compasSclDataService;
this.jsonWebToken = jsonWebToken;
this.userInfoProperties = userInfoProperties;
}

@Override
public Uni<ArchivedResource> archiveResource(UUID id, String version, String xAuthor, String xApprover, String contentType, String xFilename, File body) {
LOGGER.info("Archiving resource '{}' for scl resource with id '{}' and version '{}'", xFilename, id, version);
return compasSclDataService.archiveResource(id, version, xAuthor, xApprover, contentType, xFilename, body)
.runSubscriptionOn(Infrastructure.getDefaultExecutor())
.onItem()
.transform(this::mapToArchivedResource);
}

@Override
public Uni<ArchivedResource> archiveSclResource(UUID id, String version) {
LOGGER.info("Archiving scl resource with id '{}' and version '{}'", id, version);
String approver = jsonWebToken.getClaim(userInfoProperties.name());
return compasSclDataService.archiveSclResource(id, new Version(version), approver)
.runSubscriptionOn(Infrastructure.getDefaultExecutor())
.onItem()
.transform(this::mapToArchivedResource);
}

@Override
public Uni<ArchivedResourcesHistory> retrieveArchivedResourceHistory(UUID id) {
LOGGER.info("Retrieving archived resource history for id '{}'", id);
return Uni.createFrom()
.item(() -> compasSclDataService.getArchivedResourceHistory(id))
.runSubscriptionOn(Infrastructure.getDefaultExecutor())
.onItem()
.transform(this::mapToArchivedResourcesHistory);
}

@Override
public Uni<ArchivedResources> searchArchivedResources(ArchivedResourcesSearch archivedResourcesSearch) {
LOGGER.info("Retrieving archived resources with filter: {}", archivedResourcesSearch);
return Uni.createFrom()
.item(() -> getArchivedResourcesMetaItem(archivedResourcesSearch))
.runSubscriptionOn(Infrastructure.getDefaultExecutor())
.onItem()
.transform(this::mapToArchivedResources);
}

private IArchivedResourcesMetaItem getArchivedResourcesMetaItem(ArchivedResourcesSearch archivedResourcesSearch) {
String uuid = archivedResourcesSearch.getUuid();
if (uuid != null && !uuid.isBlank()) {
return compasSclDataService.searchArchivedResources(UUID.fromString(uuid));
}
String location = archivedResourcesSearch.getLocation();
String name = archivedResourcesSearch.getName();
String approver = archivedResourcesSearch.getApprover();
String contentType = archivedResourcesSearch.getContentType();
String type = archivedResourcesSearch.getType();
String voltage = archivedResourcesSearch.getVoltage();
OffsetDateTime from = archivedResourcesSearch.getFrom();
OffsetDateTime to = archivedResourcesSearch.getTo();
return compasSclDataService.searchArchivedResources(location, name, approver, contentType, type, voltage, from, to);
}

private ArchivedResource mapToArchivedResource(IAbstractArchivedResourceMetaItem archivedResource) {
return new ArchivedResource()
.uuid(archivedResource.getId())
.location(archivedResource.getLocationId())
.name(archivedResource.getName())
.note(archivedResource.getNote())
.author(archivedResource.getAuthor())
.approver(archivedResource.getApprover())
.type(archivedResource.getType())
.contentType(archivedResource.getContentType())
.voltage(archivedResource.getVoltage())
.version(archivedResource.getVersion())
.modifiedAt(archivedResource.getModifiedAt())
.archivedAt(archivedResource.getArchivedAt())
.fields(
archivedResource.getFields()
.stream()
.map(item -> new ResourceTag().key(item.getKey()).value(item.getValue())).toList()
);
}

private ArchivedResources mapToArchivedResources(IArchivedResourcesMetaItem archivedResources) {
return new ArchivedResources()
.resources(
archivedResources.getResources()
.stream()
.map(this::mapToArchivedResource)
.toList()
);
}

private ArchivedResourcesHistory mapToArchivedResourcesHistory(IArchivedResourcesHistoryMetaItem archivedResourcesHistoryMetaItem) {
return new ArchivedResourcesHistory()
.versions(
archivedResourcesHistoryMetaItem.getVersions()
.stream()
.map(this::mapToArchivedResourceVersion)
.toList()
);
}

private ArchivedResourceVersion mapToArchivedResourceVersion(IArchivedResourceVersion resourceVersion) {
return new ArchivedResourceVersion()
.uuid(resourceVersion.getId())
.location(resourceVersion.getLocation())
.name(resourceVersion.getName())
.note(resourceVersion.getNote())
.author(resourceVersion.getAuthor())
.approver(resourceVersion.getApprover())
.type(resourceVersion.getType())
.contentType(resourceVersion.getContentType())
.voltage(resourceVersion.getVoltage())
.version(resourceVersion.getVersion())
.modifiedAt(resourceVersion.getModifiedAt())
.archivedAt(resourceVersion.getArchivedAt())
.fields(resourceVersion.getFields()
.stream()
.map(field ->
new ResourceTag()
.key(field.getKey())
.value(field.getValue())
)
.toList()
)
.comment(resourceVersion.getComment())
.archived(resourceVersion.isArchived());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.lfenergy.compas.scl.data.rest.api.archive;

import io.smallrye.common.annotation.Blocking;
import io.smallrye.mutiny.Uni;
import jakarta.validation.Valid;
import jakarta.ws.rs.*;
import org.lfenergy.compas.scl.data.rest.api.archive.model.ArchivedResource;
import org.lfenergy.compas.scl.data.rest.api.archive.model.ArchivedResources;
import org.lfenergy.compas.scl.data.rest.api.archive.model.ArchivedResourcesHistory;
import org.lfenergy.compas.scl.data.rest.api.archive.model.ArchivedResourcesSearch;

import java.io.File;
import java.util.UUID;


@Path("/api/archive")
@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaJAXRSSpecServerCodegen", date = "2024-12-06T09:13:22.882514600+01:00[Europe/Vienna]", comments = "Generator version: 7.8.0")
public interface ArchivingApi {

@POST
@Path("/referenced-resource/{id}/versions/{version}")
@Blocking
@Produces({ "application/json" })
Uni<ArchivedResource> archiveResource(@PathParam("id") UUID id, @PathParam("version") String version, @HeaderParam("X-author") String xAuthor, @HeaderParam("X-approver") String xApprover, @HeaderParam("Content-Type") String contentType, @HeaderParam("X-filename") String xFilename, @Valid File body);

@POST
@Path("/scl/{id}/versions/{version}")
@Blocking
@Produces({ "application/json" })
Uni<ArchivedResource> archiveSclResource(@PathParam("id") UUID id, @PathParam("version") String version);

@GET
@Path("/resources/{id}/versions")
@Produces({ "application/json" })
Uni<ArchivedResourcesHistory> retrieveArchivedResourceHistory(@PathParam("id") UUID id);

@POST
@Path("/resources/search")
@Consumes({ "application/json" })
@Produces({ "application/json" })
Uni<ArchivedResources> searchArchivedResources(@Valid ArchivedResourcesSearch archivedResourcesSearch);
}
Loading
Loading