diff --git a/.dockerignore b/.dockerignore index 1dff951bc9ce1517c835779410a3c26e758d09ff..5ae5188a01e2725fe79a442a0065293c12ff2877 100755 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,9 @@ +.github .idea -src +LICENSE +README.ms +docs target/** !target/fdp-spring-boot.jar !target/classes/application-production.yml +nb-configuration.xml diff --git a/.gitignore b/.gitignore index 871d9d423cda8effd646523ef1802859c728f355..cf4b4672801ff63a1ef34d32c284e97358b6924c 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Java - +/target # Netbeans nb-configuration\.xml /nbproject/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6ae5d4ed2d4b2a31468314472de021fce3075f21..4a534690ea567dcb7552d97f94319f93a1cfde7c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,7 +6,7 @@ stages: build: stage: build - image: maven:3.6.3-jdk-11 + image: maven:3.6.3-openjdk-16-slim only: - master script: diff --git a/Dockerfile b/Dockerfile index 5d383e84e7808e2fc84d24500ed859cb13005cbc..1d9128d769ff5af7627ad4472a6d339cb7899dd7 100755 --- a/Dockerfile +++ b/Dockerfile @@ -21,12 +21,23 @@ # THE SOFTWARE. # -FROM openjdk:11-jdk-slim +# BUILD STAGE +FROM maven:3-openjdk-16 as builder + +WORKDIR /builder + +ADD . /builder + +RUN mvn --quiet -B -U --fail-fast -DskipTests package + +################################################################################ +# RUN STAGE +FROM openjdk:16-jdk-slim WORKDIR /fdp -ADD target/fdp-spring-boot.jar /fdp/app.jar -ADD target/classes/application-production.yml /fdp/application.yml +COPY --from=builder /builder/target/fdp-spring-boot.jar /fdp/app.jar +COPY --from=builder /builder/target/classes/application-production.yml /fdp/application.yml COPY ./start.sh /start.sh diff --git a/pom.xml b/pom.xml index a72678daba0fa379907ab07ceb509950281f9cfc..f2453326aba555365c1e21156decfbab7d40ec03 100755 --- a/pom.xml +++ b/pom.xml @@ -5,12 +5,12 @@ <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> - <version>2.1.10.RELEASE</version> + <version>2.5.3</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>nl.dtls</groupId> <artifactId>fairdatapoint</artifactId> - <version>1.3.0</version> + <version>1.12.0</version> <packaging>jar</packaging> <name>FairDataPoint</name> @@ -25,20 +25,20 @@ <developers> <developer> - <name>Rajaram Kaliyaperumal</name> - <email>rr.kaliyaperumal@gmail.com</email> - <organization>LUMC</organization> - <organizationUrl>https://www.lumc.nl/</organizationUrl> + <name>Vojtech Knaisl</name> + <email>vknaisl@gmail.com</email> + <url>https://github.com/vknaisl</url> + </developer> + <developer> + <name>Marek Suchánek</name> + <url>https://github.com/MarekSuchanek</url> </developer> <developer> <name>Kees Burger</name> <email>kees.burger@dtls.nl</email> <organization>DTLS</organization> <organizationUrl>http://www.dtls.nl/</organizationUrl> - </developer> - <developer> - <name>Vojtech Knaisl</name> - <email>vknaisl@gmail.com</email> + <url>https://github.com/kburger</url> </developer> </developers> @@ -47,41 +47,31 @@ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- Maven --> - <maven.compiler.source>11</maven.compiler.source> - <maven.compiler.target>11</maven.compiler.target> + <maven.compiler.source>16</maven.compiler.source> + <maven.compiler.target>16</maven.compiler.target> <!-- Project related --> - <spring.rdf.migration.version>1.0.0.RELEASE</spring.rdf.migration.version> - <spring.security.acl.mongo.version>5.1.5.RELEASE</spring.security.acl.mongo.version> - - <!-- Spring --> - <spring.boot.handlebars.version>0.3.0</spring.boot.handlebars.version> + <spring.rdf.migration.version>1.1.0.RELEASE</spring.rdf.migration.version> + <spring.security.acl.mongo.version>5.2.4.RELEASE</spring.security.acl.mongo.version> <!-- Core --> - <mongobee.version>0.13</mongobee.version> - <springfox.swagger.version>2.9.1</springfox.swagger.version> - <logback.version>1.2.3</logback.version> - <jackson.version>2.10.3</jackson.version> - <rdf4j.version>3.0.0</rdf4j.version> - <velocity.version>1.7</velocity.version> + <springdoc.version>1.5.2</springdoc.version> + <mongock.version>4.3.8</mongock.version> + <mongodb.driver-sync.version>4.2.3</mongodb.driver-sync.version> + <mongodb.spring-data.v3.version>3.2.3</mongodb.spring-data.v3.version> + <rdf4j.version>3.7.2</rdf4j.version> <unirest.version>1.4.9</unirest.version> - <sass.version>5.3.0</sass.version> - <jwt.version>0.10.5</jwt.version> - <lombok.version>1.18.10</lombok.version> - - <!-- Test --> - <junit-jupiter.version>5.3.2</junit-jupiter.version> - <mockito.version>2.23.0</mockito.version> + <jwt.version>0.11.2</jwt.version> + <lombok.version>1.18.20</lombok.version> + <rdf-resolver.version>0.1.2-SNAPSHOT</rdf-resolver.version> <!-- Plugins --> - <plugin.license.version>3.0</plugin.license.version> + <plugin.license.version>4.1</plugin.license.version> <plugin.jacoco.version>0.7.6.201602180812</plugin.jacoco.version> <plugin.coveralls.version>4.3.0</plugin.coveralls.version> <plugin.javax_xml_bind.version>2.3.1</plugin.javax_xml_bind.version> - <plugin.git_commit_id.version>2.2.4</plugin.git_commit_id.version> + <plugin.git_commit_id.version>4.9.10</plugin.git_commit_id.version> <plugin.rdf4j_generator.version>0.2.0</plugin.rdf4j_generator.version> - - </properties> <repositories> @@ -90,16 +80,39 @@ <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2</url> <layout>default</layout> - <releases><enabled>true</enabled><updatePolicy>always</updatePolicy></releases> - <snapshots><enabled>true</enabled><updatePolicy>always</updatePolicy></snapshots> + <releases> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + </releases> + <snapshots> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + </snapshots> </repository> <repository> <id>nexus-releases</id> <name>Nexus Releases</name> <url>https://nexus.internal.fairdatapoint.org/repository/maven-releases/</url> </repository> + <repository> + <id>nexus-snapshots</id> + <name>Nexus Snapshots</name> + <url>https://nexus.internal.fairdatapoint.org/repository/maven-snapshots/</url> + </repository> </repositories> + <dependencyManagement> + <dependencies> + <dependency> + <groupId>com.github.cloudyrock.mongock</groupId> + <artifactId>mongock-bom</artifactId> + <version>${mongock.version}</version> + <type>pom</type> + <scope>import</scope> + </dependency> + </dependencies> + </dependencyManagement> + <dependencies> <!-- ////////////////// --> @@ -148,6 +161,14 @@ <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-aop</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-acl-mongodb</artifactId> @@ -155,27 +176,40 @@ </dependency> <!-- ////////////////// --> - <!-- Core --> + <!-- Mongock --> <!-- ////////////////// --> <dependency> - <groupId>com.github.mongobee</groupId> - <artifactId>mongobee</artifactId> - <version>${mongobee.version}</version> + <groupId>com.github.cloudyrock.mongock</groupId> + <artifactId>mongock-spring-v5</artifactId> </dependency> <dependency> - <groupId>io.springfox</groupId> - <artifactId>springfox-swagger2</artifactId> - <version>${springfox.swagger.version}</version> + <groupId>com.github.cloudyrock.mongock</groupId> + <artifactId>mongodb-springdata-v3-driver</artifactId> </dependency> <dependency> - <groupId>io.springfox</groupId> - <artifactId>springfox-swagger-ui</artifactId> - <version>${springfox.swagger.version}</version> + <groupId>org.mongodb</groupId> + <artifactId>mongodb-driver-sync</artifactId> + <version>${mongodb.driver-sync.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-mongodb</artifactId> + <version>${mongodb.spring-data.v3.version}</version> + </dependency> + + <!-- ////////////////// --> + <!-- Core --> + <!-- ////////////////// --> + <dependency> + <groupId>org.springdoc</groupId> + <artifactId>springdoc-openapi-ui</artifactId> + <version>${springdoc.version}</version> </dependency> <dependency> <groupId>org.eclipse.rdf4j</groupId> <artifactId>rdf4j-runtime</artifactId> <version>${rdf4j.version}</version> + <type>pom</type> <exclusions> <exclusion> <groupId>ch.qos.logback</groupId> @@ -193,16 +227,6 @@ <artifactId>rdf4j-sail-nativerdf</artifactId> <version>${rdf4j.version}</version> </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-annotations</artifactId> - <version>${jackson.version}</version> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - <version>${jackson.version}</version> - </dependency> <dependency> <groupId>com.mashape.unirest</groupId> <artifactId>unirest-java</artifactId> @@ -230,6 +254,16 @@ <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> + <dependency> + <groupId>com.github.fairdevkit</groupId> + <artifactId>rdf-resource-resolver-core</artifactId> + <version>${rdf-resolver.version}</version> + </dependency> + <dependency> + <groupId>com.github.fairdevkit</groupId> + <artifactId>rdf-resource-resolver-api</artifactId> + <version>${rdf-resolver.version}</version> + </dependency> <!-- ////////////////// --> <!-- Test --> @@ -243,10 +277,6 @@ <groupId>com.vaadin.external.google</groupId> <artifactId>android-json</artifactId> </exclusion> - <exclusion> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - </exclusion> </exclusions> </dependency> <dependency> @@ -254,30 +284,6 @@ <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-engine</artifactId> - <version>${junit-jupiter.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.junit.jupiter</groupId> - <artifactId>junit-jupiter-params</artifactId> - <version>${junit-jupiter.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-core</artifactId> - <version>${mockito.version}</version> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.mockito</groupId> - <artifactId>mockito-junit-jupiter</artifactId> - <version>${mockito.version}</version> - <scope>test</scope> - </dependency> </dependencies> <build> @@ -292,6 +298,9 @@ <properties> <owner>DTL</owner> </properties> + <mapping> + <java>JAVADOC_STYLE</java> + </mapping> <excludes> <exclude>pom.xml</exclude> <exclude>**/maven.config</exclude> @@ -301,8 +310,10 @@ <exclude>**/*.properties</exclude> <exclude>**/*.xml</exclude> <exclude>**/*.json</exclude> + <exclude>**/*.json</exclude> <exclude>LICENSE</exclude> <exclude>.dockerignore</exclude> + <exclude>Dockerfile.build</exclude> </excludes> </configuration> <executions> @@ -367,6 +378,21 @@ <verbose>false</verbose> </configuration> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <includes> + <include>**/*.java</include> + </includes> + <excludes> + <exclude>**/*Fixtures.java</exclude> + <exclude>**/*Config.java</exclude> + <exclude>**/Common.java</exclude> + <exclude>**/common/*.java</exclude> + </excludes> + </configuration> + </plugin> <plugin> <groupId>com.github.kburger</groupId> <artifactId>rdf4j-generator-maven-plugin</artifactId> @@ -395,7 +421,7 @@ <prefix>fdp</prefix> </vocabulary> <vocabulary> - <url>https://raw.githubusercontent.com/schemaorg/schemaorg/master/data/releases/3.4/schema.ttl</url> + <url>https://raw.githubusercontent.com/schemaorg/schemaorg/main/data/releases/3.4/schema.ttl</url> <namespace>http://schema.org/</namespace> <prefix>schemaOrg</prefix> </vocabulary> diff --git a/src/main/java/nl/dtls/fairdatapoint/Application.java b/src/main/java/nl/dtls/fairdatapoint/Application.java index 7c82908e6da1ba1e493c094554273c8b2341d732..c57a3c75266950c38a9b11aded6540e8df74974f 100755 --- a/src/main/java/nl/dtls/fairdatapoint/Application.java +++ b/src/main/java/nl/dtls/fairdatapoint/Application.java @@ -24,6 +24,7 @@ package nl.dtls.fairdatapoint; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.ConfigurationPropertiesScan; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -32,6 +33,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; @EnableWebMvc @EnableAsync @ComponentScan(basePackages = "nl.dtls.fairdatapoint.*") +@ConfigurationPropertiesScan("nl.dtls.fairdatapoint.config.*") public class Application { public static void main(String[] args) { diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/apikey/ApiKeyController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/apikey/ApiKeyController.java new file mode 100644 index 0000000000000000000000000000000000000000..1f1fadc3bd3a52df7bf1b87cafb638ab166dd605 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/apikey/ApiKeyController.java @@ -0,0 +1,71 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.apikey; + + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.apikey.ApiKeyDTO; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.service.apikey.ApiKeyService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static java.lang.String.format; + +@Tag(name = "Authentication and Authorization") +@RestController +@RequestMapping("/api-keys") +public class ApiKeyController { + + @Autowired + private ApiKeyService apiKeyService; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ApiKeyDTO>> getApiKeys() { + List<ApiKeyDTO> dto = apiKeyService.getAll(); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ApiKeyDTO> createApiKey() { + ApiKeyDTO dto = apiKeyService.create(); + return new ResponseEntity<>(dto, HttpStatus.CREATED); + } + + @DeleteMapping("/{uuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity<Void> deleteShape(@PathVariable final String uuid) throws ResourceNotFoundException { + boolean result = apiKeyService.delete(uuid); + if (result) { + return ResponseEntity.noContent().build(); + } else { + throw new ResourceNotFoundException(format("Api Key '%s' doesn't exist", uuid)); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/config/ConfigController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/config/ConfigController.java index 716cb3ba7468ca68419da0f20cba3b5ed6d821e9..e36cde873ee143f646f07a660a0387766810a956 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/config/ConfigController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/config/ConfigController.java @@ -22,15 +22,19 @@ */ package nl.dtls.fairdatapoint.api.controller.config; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.config.BootstrapConfigDTO; import nl.dtls.fairdatapoint.service.config.ConfigService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "Client") @RestController @RequestMapping("/configs") public class ConfigController { @@ -38,7 +42,7 @@ public class ConfigController { @Autowired private ConfigService configService; - @RequestMapping(value = "/bootstrap", method = RequestMethod.GET) + @GetMapping(path = "/bootstrap", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<BootstrapConfigDTO> getBootstrapConfig() { BootstrapConfigDTO dto = configService.getBootstrapConfig(); return new ResponseEntity<>(dto, HttpStatus.OK); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/dashboard/DashboardController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/dashboard/DashboardController.java index 59c479176b940341735fcdc3f69184c8305b4c23..3eaa1a36162018c6da223f4c775a56385e10297a 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/dashboard/DashboardController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/dashboard/DashboardController.java @@ -22,6 +22,7 @@ */ package nl.dtls.fairdatapoint.api.controller.dashboard; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.dashboard.DashboardItemDTO; import nl.dtls.fairdatapoint.service.dashboard.DashboardService; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; @@ -29,9 +30,10 @@ import org.eclipse.rdf4j.model.IRI; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @@ -41,6 +43,7 @@ import static nl.dtls.fairdatapoint.util.HttpUtil.getRequestURL; import static nl.dtls.fairdatapoint.util.RdfUtil.removeLastPartOfIRI; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +@Tag(name = "Client") @RestController @RequestMapping("/dashboard") public class DashboardController { @@ -52,7 +55,7 @@ public class DashboardController { @Autowired private DashboardService dashboardService; - @RequestMapping(method = RequestMethod.GET) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<DashboardItemDTO>> getDashboard(HttpServletRequest request) throws MetadataServiceException { IRI uri = i(getRequestURL(request, persistentUrl)); IRI repositoryUri = removeLastPartOfIRI(uri); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/exception/ExceptionControllerAdvice.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/exception/ExceptionControllerAdvice.java index fdc2886a533b5c3f2e5ed8511644068ccf633a67..c07683efc8ce22d7cfcb3acbb93598ed6594cde0 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/exception/ExceptionControllerAdvice.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/exception/ExceptionControllerAdvice.java @@ -27,15 +27,21 @@ */ package nl.dtls.fairdatapoint.api.controller.exception; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; import lombok.extern.slf4j.Slf4j; import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; import nl.dtls.fairdatapoint.entity.exception.*; +import nl.dtls.fairdatapoint.entity.index.exception.IndexException; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; import org.eclipse.rdf4j.rio.Rio; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.web.bind.annotation.ControllerAdvice; @@ -55,7 +61,15 @@ public class ExceptionControllerAdvice { @ExceptionHandler({ValidationException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST) - @ResponseBody + @ResponseBody() + @ApiResponse( + responseCode = "400", + description = "Bad request", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public ErrorDTO handleBadRequest(Exception e) { log.warn(e.getMessage()); return new ErrorDTO(HttpStatus.BAD_REQUEST, e.getMessage()); @@ -64,6 +78,14 @@ public class ExceptionControllerAdvice { @ExceptionHandler({RdfValidationException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody + @ApiResponse( + responseCode = "400", + description = "Bad request", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public Model handleBadRequest(RdfValidationException e) { Model validationReportModel = e.getModel(); @@ -83,6 +105,14 @@ public class ExceptionControllerAdvice { @ExceptionHandler({BadCredentialsException.class, UnauthorizedException.class}) @ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseBody + @ApiResponse( + responseCode = "401", + description = "Unauthorized", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public ErrorDTO handleUnauthorized(Exception e) { log.error(e.getMessage()); return new ErrorDTO(HttpStatus.UNAUTHORIZED, e.getMessage()); @@ -91,6 +121,14 @@ public class ExceptionControllerAdvice { @ExceptionHandler({ForbiddenException.class, AccessDeniedException.class}) @ResponseStatus(HttpStatus.FORBIDDEN) @ResponseBody + @ApiResponse( + responseCode = "403", + description = "Forbidden", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public ErrorDTO handleForbidden(Exception e) { log.error(e.getMessage()); return new ErrorDTO(HttpStatus.FORBIDDEN, e.getMessage()); @@ -99,6 +137,14 @@ public class ExceptionControllerAdvice { @ExceptionHandler(ResourceNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) @ResponseBody + @ApiResponse( + responseCode = "404", + description = "Resource Not Found", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public ErrorDTO handleResourceNotFound(ResourceNotFoundException e) { log.error(e.getMessage()); return new ErrorDTO(HttpStatus.NOT_FOUND, e.getMessage()); @@ -107,9 +153,22 @@ public class ExceptionControllerAdvice { @ExceptionHandler({MetadataServiceException.class}) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ResponseBody + @ApiResponse( + responseCode = "500", + description = "Internal Server Error", + content = @Content( + mediaType = MediaType.APPLICATION_JSON_VALUE, + schema = @Schema(implementation = ErrorDTO.class) + ) + ) public ErrorDTO handleInternalServerError(Exception e) { log.error(e.getMessage()); return new ErrorDTO(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); } + @ExceptionHandler(IndexException.class) + public ResponseEntity<ErrorDTO> handleIndexException(IndexException exception) { + return new ResponseEntity<>(exception.getErrorDTO(), exception.getStatus()); + } + } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexAdminController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexAdminController.java new file mode 100644 index 0000000000000000000000000000000000000000..a49e248a3f4b3ec5f1d5de8eade0d70ec6e58efd --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexAdminController.java @@ -0,0 +1,88 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.index; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.service.UtilityService; +import nl.dtls.fairdatapoint.service.index.event.EventService; +import nl.dtls.fairdatapoint.service.index.webhook.WebhookService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.UUID; + +@Tag(name = "Index") +@Log4j2 +@RestController +@RequestMapping("/index/admin") +public class IndexAdminController { + + @Autowired + private UtilityService utilityService; + + @Autowired + private EventService eventService; + + @Autowired + private WebhookService webhookService; + + @Operation(hidden = true) + @PostMapping("/trigger") + @PreAuthorize("hasRole('ADMIN')") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void triggerMetadataRetrieve(@RequestBody @Valid PingDTO reqDto, HttpServletRequest request) { + log.info("Received ping from {}", utilityService.getRemoteAddr(request)); + final Event event = eventService.acceptAdminTrigger(request, reqDto); + webhookService.triggerWebhooks(event); + eventService.triggerMetadataRetrieval(event); + } + + @Operation(hidden = true) + @PostMapping("/trigger-all") + @PreAuthorize("hasRole('ADMIN')") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void triggerMetadataRetrieveAll(HttpServletRequest request) { + log.info("Received ping from {}", utilityService.getRemoteAddr(request)); + final Event event = eventService.acceptAdminTriggerAll(request); + webhookService.triggerWebhooks(event); + eventService.triggerMetadataRetrieval(event); + } + + @Operation(hidden = true) + @PostMapping("/ping-webhook") + @PreAuthorize("hasRole('ADMIN')") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void webhookPing(@RequestParam(required = true) UUID webhook, HttpServletRequest request) { + log.info("Received webhook {} ping trigger from {}", webhook, utilityService.getRemoteAddr(request)); + final Event event = webhookService.handleWebhookPing(request, webhook); + webhookService.triggerWebhooks(event); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexEntryController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexEntryController.java new file mode 100644 index 0000000000000000000000000000000000000000..56743fbda7ba16f2884134d5567b16ac98ed48fb --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexEntryController.java @@ -0,0 +1,74 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.index; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDetailDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryInfoDTO; +import nl.dtls.fairdatapoint.service.index.entry.IndexEntryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Optional; + +@Tag(name = "Index") +@RestController +@RequestMapping("/index/entries") +public class IndexEntryController { + + @Autowired + private IndexEntryService service; + + @GetMapping(path = "", produces = MediaType.APPLICATION_JSON_VALUE) + public Page<IndexEntryDTO> getEntriesPage(Pageable pageable, + @RequestParam(required = false, defaultValue = "") String state) { + return service.getEntriesPageDTOs(pageable, state); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public Optional<IndexEntryDetailDTO> getEntry(@PathVariable final String uuid) { + return service.getEntryDetailDTO(uuid); + } + + @DeleteMapping("/{uuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteEntry(@PathVariable final String uuid) { + service.deleteEntry(uuid); + } + + @GetMapping(path = "/all", produces = MediaType.APPLICATION_JSON_VALUE) + public List<IndexEntryDTO> getEntriesAll() { + return service.getAllEntriesAsDTOs(); + } + + @GetMapping(path = "/info", produces = MediaType.APPLICATION_JSON_VALUE) + public IndexEntryInfoDTO getEntriesInfo() { + return service.getEntriesInfo(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexPingController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexPingController.java new file mode 100644 index 0000000000000000000000000000000000000000..368b64da683a30f8a573baae55136b80b4150e21 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexPingController.java @@ -0,0 +1,101 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.index; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.service.UtilityService; +import nl.dtls.fairdatapoint.service.index.event.EventService; +import nl.dtls.fairdatapoint.service.index.harvester.HarvesterService; +import nl.dtls.fairdatapoint.service.index.webhook.WebhookService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +@Tag(name = "Index") +@RestController +@RequestMapping("/") +public class IndexPingController { + private static final Logger logger = LoggerFactory.getLogger(IndexPingController.class); + + @Autowired + private EventService eventService; + + @Autowired + private WebhookService webhookService; + + @Autowired + private HarvesterService harvesterService; + + @Autowired + private UtilityService utilityService; + + @Operation( + description = "Inform about running FAIR Data Point. It is expected to send pings regularly (at least weekly). There is a rate limit set both per single IP within a period of time and per URL in message.", + requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody( + description = "Ping payload with FAIR Data Point info", + required = true, + content = @Content( + mediaType = "application/json", + examples = { + @ExampleObject(value = "{\"clientUrl\": \"https://example.com\"}") + }, + schema = @Schema( + type = "object", + title = "Ping", + implementation = PingDTO.class + ) + ) + ), + responses = { + @ApiResponse(responseCode = "204", description = "Ping accepted (no content)"), + @ApiResponse(responseCode = "400", description = "Invalid ping format"), + @ApiResponse(responseCode = "429", description = "Rate limit exceeded") + } + ) + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity<Void> receivePing(@RequestBody @Valid PingDTO reqDto, HttpServletRequest request) throws MetadataRepositoryException { + logger.info("Received ping from {}", utilityService.getRemoteAddr(request)); + final Event event = eventService.acceptIncomingPing(reqDto, request); + logger.info("Triggering metadata retrieval for {}", event.getRelatedTo().getClientUrl()); + eventService.triggerMetadataRetrieval(event); + harvesterService.harvest(reqDto.getClientUrl()); + webhookService.triggerWebhooks(event); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexSettingsController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexSettingsController.java new file mode 100644 index 0000000000000000000000000000000000000000..0ad99c37c1f703de6cdc35ac5e60f6721c8fc4f4 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/index/IndexSettingsController.java @@ -0,0 +1,61 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.index; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsUpdateDTO; +import nl.dtls.fairdatapoint.service.index.settings.IndexSettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@Tag(name = "Index") +@RestController +@RequestMapping("/index/settings") +public class IndexSettingsController { + + @Autowired + private IndexSettingsService indexSettingsService; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public IndexSettingsDTO getIndexSettings() { + return indexSettingsService.getCurrentSettings(); + } + + @PutMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public IndexSettingsDTO updateIndexSettings(@RequestBody @Valid IndexSettingsUpdateDTO reqDto) { + return indexSettingsService.updateSettings(reqDto); + } + + @DeleteMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public IndexSettingsDTO resetIndexSettings() { + return indexSettingsService.resetSettings(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/label/LabelController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/label/LabelController.java new file mode 100644 index 0000000000000000000000000000000000000000..401c6a29fc7383d397b45f49422e747692f8de1f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/label/LabelController.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.label; + +import nl.dtls.fairdatapoint.api.dto.label.LabelDTO; +import nl.dtls.fairdatapoint.service.label.LabelService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/label") +public class LabelController { + @Autowired + private LabelService labelService; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<LabelDTO> getLabel(@RequestParam String iri, + @RequestParam(required = false, defaultValue = "en") String lang) { + var label = labelService.getLabel(iri, lang); + + if (label.isPresent()) { + return new ResponseEntity<>(label.get(), HttpStatus.OK); + } else { + return new ResponseEntity<>(HttpStatus.NOT_FOUND); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/membership/MembershipController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/membership/MembershipController.java index aff73fbff9fc1c9a8eb0ea7f5d6c54b5ec343a40..2880173b37bd543617d5b47ad6ad23d098461c56 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/membership/MembershipController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/membership/MembershipController.java @@ -22,17 +22,21 @@ */ package nl.dtls.fairdatapoint.api.controller.membership; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.membership.MembershipDTO; import nl.dtls.fairdatapoint.service.membership.MembershipService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "Authentication and Authorization") @RestController @RequestMapping("/memberships") public class MembershipController { @@ -40,7 +44,7 @@ public class MembershipController { @Autowired private MembershipService membershipService; - @RequestMapping(method = RequestMethod.GET) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<MembershipDTO>> getUsers() { List<MembershipDTO> dto = membershipService.getMemberships(); return new ResponseEntity<>(dto, HttpStatus.OK); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java index feacd11b760ea4f81983fb0b0fbeff3537b76987..b54fd654201997c79666876c6b81dca8a4d652a8 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java @@ -22,32 +22,52 @@ */ package nl.dtls.fairdatapoint.api.controller.metadata; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; +import nl.dtls.fairdatapoint.entity.exception.ForbiddenException; import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import nl.dtls.fairdatapoint.entity.user.User; import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; +import nl.dtls.fairdatapoint.service.metadata.enhance.MetadataEnhancer; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; import nl.dtls.fairdatapoint.service.metadata.factory.MetadataServiceFactory; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; +import nl.dtls.fairdatapoint.service.openapi.OpenApiService; import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; import nl.dtls.fairdatapoint.service.shape.ShapeService; +import nl.dtls.fairdatapoint.service.user.CurrentUserService; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; import org.eclipse.rdf4j.rio.RDFFormat; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.net.URI; +import java.util.LinkedList; +import java.util.Optional; +import static java.util.stream.Collectors.toList; import static nl.dtls.fairdatapoint.util.HttpUtil.*; import static nl.dtls.fairdatapoint.util.RdfIOUtil.changeBaseUri; import static nl.dtls.fairdatapoint.util.RdfIOUtil.read; import static nl.dtls.fairdatapoint.util.RdfUtil.*; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +@Tag(name = "Metadata") @RestController @RequestMapping("/") public class GenericController { @@ -65,42 +85,50 @@ public class GenericController { @Autowired private ShapeService shapeService; - @RequestMapping( - value = "**/spec", - method = RequestMethod.GET, - produces = {"!application/json"}) + @Autowired + private MetadataStateService metadataStateService; + + @Autowired + private MetadataEnhancer metadataEnhancer; + + @Autowired + private CurrentUserService currentUserService; + + @Autowired + private GenericMetadataRepository metadataRepository; + + @Operation(hidden = true) + @GetMapping(path = "**/spec", produces = {"!application/json"}) public Model getFormMetadata() { return shapeService.getShaclFromShapes(); } - @RequestMapping( - value = "**/expanded", - method = RequestMethod.GET, - produces = {"!application/json"}) + @Operation(hidden = true, deprecated = true) + @GetMapping(path = "**/expanded", produces = {"!application/json"}) public Model getMetaDataExpanded(HttpServletRequest request) throws MetadataServiceException { // 1. Init String uri = getRequestURL(request, persistentUrl); Model resultRdf = new LinkedHashModel(); String urlPrefix = getResourceNameForDetail(uri); MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); - // 2. Get resource definition - ResourceDefinition rd = resourceDefinitionService.getByUriPrefix(urlPrefix); - - // 3. Get entity + // 2. Get entity IRI entityUri = i(getRequestURL(request, persistentUrl)); Model entity = metadataService.retrieve(entityUri); resultRdf.addAll(entity); - // 3. Get children - if (rd.getChild() != null) { - for (org.eclipse.rdf4j.model.Value datasetUri : getObjectsBy(entity, entityUri, i(rd.getChild()))) { - Model dataset = metadataService.retrieve(i(datasetUri.stringValue())); - resultRdf.addAll(dataset); - } + // 3. Check if it is draft + Metadata state = metadataStateService.get(entityUri); + Optional<User> oCurrentUser = currentUserService.getCurrentUser(); + if (state.getState().equals(MetadataState.DRAFT) && oCurrentUser.isEmpty()) { + throw new ForbiddenException("You are not allow to view this record in state DRAFT"); } - // 4. Get parent + // 4. Enhance + metadataEnhancer.enhanceWithResourceDefinition(entityUri, rd, resultRdf); + + // 5. Get parent while (true) { IRI parentUri = i(getStringObjectBy(entity, entityUri, DCTERMS.IS_PART_OF)); if (parentUri == null) { @@ -116,10 +144,8 @@ public class GenericController { return resultRdf; } - @RequestMapping( - value = "**", - method = RequestMethod.GET, - produces = {"!application/json"}) + @Operation(hidden = true) + @GetMapping(path = "**", produces = {"!application/json"}) public Model getMetaData(HttpServletRequest request) throws MetadataServiceException { // 1. Init String uri = getRequestURL(request, persistentUrl); @@ -127,53 +153,80 @@ public class GenericController { String urlPrefix = getResourceNameForDetail(uri); MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); - // 2. Get entity + // 2. Get resource definition + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); + + // 3. Get entity IRI entityUri = i(getRequestURL(request, persistentUrl)); Model entity = metadataService.retrieve(entityUri); resultRdf.addAll(entity); - // 3. Create response + // 4. Check if it is DRAFT + Metadata state = metadataStateService.get(entityUri); + Optional<User> oCurrentUser = currentUserService.getCurrentUser(); + if (state.getState().equals(MetadataState.DRAFT) && oCurrentUser.isEmpty()) { + throw new ForbiddenException("You are not allow to view this record in state DRAFT"); + } + + // 5. Filter children + for (ResourceDefinitionChild rdChild : rd.getChildren()) { + IRI relationUri = i(rdChild.getRelationUri()); + for (org.eclipse.rdf4j.model.Value childUri : getObjectsBy(entity, entityUri, relationUri)) { + Metadata childState = metadataStateService.get(i(childUri.stringValue())); + if (!(childState.getState().equals(MetadataState.PUBLISHED) || oCurrentUser.isPresent())) { + resultRdf.remove(entityUri, relationUri, childUri); + } + } + } + + // 6. Add links + metadataEnhancer.enhanceWithLinks(entityUri, entity, rd, persistentUrl, resultRdf); + metadataEnhancer.enhanceWithResourceDefinition(entityUri, rd, resultRdf); + + // 7. Create response return resultRdf; } - @RequestMapping( - value = "**", - method = RequestMethod.POST, - produces = {"!application/json"}) + @Operation(hidden = true) + @PostMapping(path = "**", produces = {"!application/json"}) public ResponseEntity<Model> storeMetaData(HttpServletRequest request, @RequestBody String reqBody, @RequestHeader(value = "Content-Type", required = false) String contentType) throws MetadataServiceException { - // 1. Init + // 1. Check if user is authenticated + // - it can't be in SecurityConfig because the authentication is done based on content-type + Optional<User> oUser = currentUserService.getCurrentUser(); + if (oUser.isEmpty()) { + throw new ForbiddenException("You have to be login at first"); + } + + // 2. Init String urlPrefix = getResourceNameForList(getRequestURL(request, persistentUrl)); MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); - ResourceDefinition rd = resourceDefinitionService.getByUriPrefix(urlPrefix); + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); - // 2. Generate URI + // 3. Generate URI IRI uri = generateNewIRI(request, persistentUrl); - // 3. Parse reqDto + // 4. Parse reqDto RDFFormat rdfContentType = getRdfContentType(contentType); Model oldDto = read(reqBody, uri.stringValue(), rdfContentType); - Model reqDto = changeBaseUri(oldDto, uri.stringValue(), rd.getShaclTargetClasses()); - String child = rd.getChild(); - if (child != null) { - reqDto.remove(null, i(child), null); + Model reqDto = changeBaseUri(oldDto, uri.stringValue(), resourceDefinitionService.getTargetClassUris(rd)); + for (ResourceDefinitionChild rdChild : rd.getChildren()) { + reqDto.remove(null, i(rdChild.getRelationUri()), null); } - // 4. Store metadata + // 5. Store metadata Model metadata = metadataService.store(reqDto, uri, rd); - // 5. Create response + // 6. Create response return ResponseEntity .created(URI.create(uri.stringValue())) .body(metadata); } - @RequestMapping( - value = "**", - method = RequestMethod.PUT, - produces = {"!application/json"}) + @Operation(hidden = true) + @PutMapping(path = "**", produces = {"!application/json"}) public ResponseEntity<Model> updateMetaData(HttpServletRequest request, @RequestBody String reqBody, @RequestHeader(value = "Content-Type", required = false) String contentType) @@ -181,7 +234,7 @@ public class GenericController { // 1. Init String urlPrefix = getResourceNameForDetail(getRequestURL(request, persistentUrl)); MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); - ResourceDefinition rd = resourceDefinitionService.getByUriPrefix(urlPrefix); + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); // 2. Extract URI IRI uri = i(getRequestURL(request, persistentUrl)); @@ -189,9 +242,8 @@ public class GenericController { // 3. Parse reqDto RDFFormat rdfContentType = getRdfContentType(contentType); Model reqDto = read(reqBody, uri.stringValue(), rdfContentType); - String child = rd.getChild(); - if (child != null) { - org.eclipse.rdf4j.model.Value childEntity = getObjectBy(reqDto, null, i(child)); + for (ResourceDefinitionChild child : rd.getChildren()) { + org.eclipse.rdf4j.model.Value childEntity = getObjectBy(reqDto, null, i(child.getRelationUri())); if (childEntity != null) { reqDto.remove(i(childEntity.stringValue()), null, null); } @@ -205,12 +257,14 @@ public class GenericController { .ok(metadata); } - @RequestMapping(value = "**", method = RequestMethod.DELETE) + @Operation(hidden = true) + @DeleteMapping(path = "**") + @ResponseStatus(HttpStatus.NO_CONTENT) public ResponseEntity<Void> deleteMetadata(HttpServletRequest request) throws MetadataServiceException { // 1. Init String urlPrefix = getResourceNameForDetail(getRequestURL(request, persistentUrl)); MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); - ResourceDefinition rd = resourceDefinitionService.getByUriPrefix(urlPrefix); + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); // 2. Skip if Repository (we don't support delete for repository) if (rd.getName().equals("Repository")) { @@ -227,6 +281,77 @@ public class GenericController { return ResponseEntity.noContent().build(); } + @Operation(hidden = true) + @GetMapping(path = "**/page/{childPrefix}", produces = {"!application/json"}) + public ResponseEntity<Model> getMetaDataChildren( + @PathVariable final String childPrefix, + @RequestParam(defaultValue = "0") final int page, + @RequestParam(defaultValue = "10") final int size, + HttpServletRequest request + ) throws MetadataServiceException, MetadataRepositoryException { + // 1. Init + String requestUrl = getRequestURL(request, persistentUrl); + Model resultRdf = new LinkedHashModel(); + String urlPrefix = getResourceNameForChild(requestUrl); + MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); + + // 2. Get entity + IRI entityUri = getEntityIriForPagination(requestUrl); + Model entity = metadataService.retrieve(entityUri); + + // 3. Check if it is draft + Metadata state = metadataStateService.get(entityUri); + Optional<User> oCurrentUser = currentUserService.getCurrentUser(); + if (state.getState().equals(MetadataState.DRAFT) && oCurrentUser.isEmpty()) { + throw new ForbiddenException("You are not allow to view this record in state DRAFT"); + } + + // 4. Get Children + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); + ResourceDefinition currentChildRd = resourceDefinitionService.getByUrlPrefix(childPrefix); + MetadataService childMetadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(childPrefix); + + for (ResourceDefinitionChild rdChild : rd.getChildren()) { + if (rdChild.getResourceDefinitionUuid().equals(currentChildRd.getUuid())) { + IRI relationUri = i(rdChild.getRelationUri()); + + // 4.1 Get all titles for sort + var titles = metadataRepository.findChildTitles(entityUri, relationUri); + + // 4.2 Get all children sorted + var children = getObjectsBy(entity, entityUri, relationUri) + .stream() + .filter((childUri) -> getResourceNameForChild(childUri.toString()).equals(childPrefix)) + .filter((childUri) -> { + if (oCurrentUser.isPresent()) return true; + Metadata childState = metadataStateService.get(i(childUri.stringValue())); + return childState.getState().equals(MetadataState.PUBLISHED); + }) + .sorted((v1, v2) -> { + var title1 = titles.get(v1.toString()); + var title2 = titles.get(v2.toString()); + return title1.compareTo(title2); + }) + .collect(toList()); + + // 4.3 Retrieve children metadata only for requested page + var childrenCount = children.size(); + children.stream().skip(page * size).limit(size) + .map((childUri) -> retrieveChildModel(childMetadataService, childUri)) + .flatMap(Optional::stream) + .forEach(resultRdf::addAll); + + // 4.4 Set Link headers and send response + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.set("Link", createLinkHeader(requestUrl, childrenCount, page, size)); + return ResponseEntity.ok().headers(responseHeaders).body(resultRdf); + } + } + + // Send empty response in case nothing was found + return ResponseEntity.ok(resultRdf); + } + private String getResourceNameForList(String url) { url = url.replace(persistentUrl, ""); @@ -252,4 +377,61 @@ public class GenericController { return parts[1]; } + private String getResourceNameForChild(String url) { + url = url.replace(persistentUrl, ""); + String[] parts = url.split("/"); + + if (parts.length < 2) { + throw new ValidationException("Unsupported URL"); + } + + // If URL is a repository -> return empty string + if (parts[1].equals("page")) { + return ""; + } + + return parts[1]; + } + + private IRI getEntityIriForPagination(String url) { + String[] parts = url.split("/"); + + StringBuilder sb = new StringBuilder(parts[0]); + for (int i = 1; i < parts.length - 2; i++) { + sb.append("/"); + sb.append(parts[i]); + } + return i(sb.toString()); + } + + private String createLinkHeader(String requestUrl, int childrenCount, int page, int size) { + var links = new LinkedList<String>(); + var lastPage = (int) Math.ceil((float) childrenCount / size) - 1; + + links.add(createLink(requestUrl, 0, size, "first")); + links.add(createLink(requestUrl, lastPage, size, "last")); + + if (page > 0 && page <= lastPage) { + links.add(createLink(requestUrl, page - 1, size, "prev")); + } + + if (page < lastPage && page >= 0) { + links.add(createLink(requestUrl, page + 1, size, "next")); + } + + return String.join(", ", links); + } + + private Optional<Model> retrieveChildModel(MetadataService childMetadataService, Value childUri) { + try { + Model childModel = childMetadataService.retrieve(i(childUri.stringValue())); + return Optional.of(childModel); + } catch (MetadataServiceException e) { + return Optional.empty(); + } + } + + private String createLink(String requestUrl, int page, int size, String rel) { + return "<" + requestUrl + "/?page=" + page + "&size=" + size + ">; rel=\"" + rel + "\""; + } } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMemberController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMemberController.java index 4d3895d34d2f6585159f425327407281ecee8d0d..0d6edb2893c6557ee1abbd39c5fa1dc2715af5b2 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMemberController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMemberController.java @@ -22,6 +22,8 @@ */ package nl.dtls.fairdatapoint.api.controller.metadata; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.member.MemberCreateDTO; import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; @@ -35,19 +37,20 @@ import org.eclipse.rdf4j.model.Model; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.List; -import java.util.Optional; import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getMetadataIdentifier; import static nl.dtls.fairdatapoint.util.HttpUtil.getRequestURL; import static nl.dtls.fairdatapoint.util.RdfUtil.removeLastPartOfIRI; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +@Tag(name = "Authentication and Authorization") @RestController public class GenericMemberController { @@ -61,24 +64,8 @@ public class GenericMemberController { @Autowired private MetadataServiceFactory metadataServiceFactory; - @RequestMapping(value = "**/member", method = RequestMethod.GET) - public MemberDTO getMember(HttpServletRequest request) throws MetadataServiceException { - // 1. Init - String urlPrefix = getResourceNameForList(getRequestURL(request, persistentUrl)); - MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); - - // 2. Get and check existence entity - IRI uri = i(getRequestURL(request, persistentUrl)); - IRI entityUri = removeLastPartOfIRI(uri); - Model metadata = metadataService.retrieve(entityUri); - - // 3. Get member - String entityId = getMetadataIdentifier(metadata).getIdentifier().getLabel(); - Optional<MemberDTO> oMember = memberService.getMemberForCurrentUser(entityId, Metadata.class); - return oMember.orElse(new MemberDTO(null, null)); - } - - @RequestMapping(value = "**/members", method = RequestMethod.GET) + @Operation(hidden = true) + @GetMapping(path = "**/members", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<MemberDTO>> getMembers(HttpServletRequest request) throws ResourceNotFoundException, MetadataServiceException { // 1. Init @@ -96,7 +83,8 @@ public class GenericMemberController { return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(value = "**/members/{userUuid}", method = RequestMethod.PUT) + @Operation(hidden = true) + @PutMapping(path = "**/members/{userUuid}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<MemberDTO> putMember(@PathVariable final String userUuid, HttpServletRequest request, @RequestBody @Valid MemberCreateDTO reqBody) @@ -117,7 +105,9 @@ public class GenericMemberController { return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(value = "**/members/{userUuid}", method = RequestMethod.DELETE) + @Operation(hidden = true) + @DeleteMapping(path = "**/members/{userUuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) public ResponseEntity<Void> deleteMember(@PathVariable final String userUuid, HttpServletRequest request) throws ResourceNotFoundException, MetadataServiceException { // 1. Init diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMetaController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMetaController.java new file mode 100644 index 0000000000000000000000000000000000000000..64ffa7cf6cc65385165685cf248c00a86f1249fa --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericMetaController.java @@ -0,0 +1,159 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.metadata; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaPathDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.member.MemberService; +import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; +import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; +import nl.dtls.fairdatapoint.service.metadata.factory.MetadataServiceFactory; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Optional; + +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getMetadataIdentifier; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getTitle; +import static nl.dtls.fairdatapoint.util.HttpUtil.getRequestURL; +import static nl.dtls.fairdatapoint.util.RdfUtil.getStringObjectBy; +import static nl.dtls.fairdatapoint.util.RdfUtil.removeLastPartOfIRI; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +@Tag(name = "Metadata") +@RestController +public class GenericMetaController { + + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + + @Autowired + private MemberService memberService; + + @Autowired + private MetadataServiceFactory metadataServiceFactory; + + @Autowired + private MetadataStateService metadataStateService; + + @Autowired + private ResourceDefinitionService resourceDefinitionService; + + @Operation(hidden = true) + @RequestMapping(path = "**/meta", method = RequestMethod.GET) + public MetaDTO getMeta(HttpServletRequest request) throws MetadataServiceException { + // 1. Init + String urlPrefix = getResourceNameForList(getRequestURL(request, persistentUrl)); + MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); + + // 2. Get resource definition + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); + + // 3. Get and check existence entity + IRI uri = i(getRequestURL(request, persistentUrl)); + IRI entityUri = removeLastPartOfIRI(uri); + Model entity = metadataService.retrieve(entityUri); + + // 4. Get member + String entityId = getMetadataIdentifier(entity).getIdentifier().getLabel(); + Optional<MemberDTO> oMember = memberService.getMemberForCurrentUser(entityId, Metadata.class); + MemberDTO member = oMember.orElse(new MemberDTO(null, null)); + + // 5. Get state + MetaStateDTO state = metadataStateService.getState(entityUri, entity, rd); + + // 6. Make path map + HashMap<String, MetaPathDTO> pathMap = new HashMap<>(); + while (true) { + MetaPathDTO entry = new MetaPathDTO(); + entry.setResourceDefinitionUuid(rd.getUuid()); + entry.setTitle(getTitle(entity).stringValue()); + IRI parentUri = i(getStringObjectBy(entity, entityUri, DCTERMS.IS_PART_OF)); + Optional.ofNullable(parentUri).map(IRI::toString).ifPresent(entry::setParent); + pathMap.put(entityUri.toString(), entry); + if (parentUri == null) { + break; + } + entity = metadataService.retrieve(parentUri); + entityUri = parentUri; + urlPrefix = getResourceNameForList(parentUri.toString()); + rd = resourceDefinitionService.getByUrlPrefix(urlPrefix); + } + + return new MetaDTO(member, state, pathMap); + } + + @Operation(hidden = true) + @RequestMapping(path = "**/meta/state", method = RequestMethod.PUT) + public MetaStateChangeDTO putMetaState(HttpServletRequest request, @RequestBody @Valid MetaStateChangeDTO reqDto) throws MetadataServiceException { + // 1. Init + String urlPrefix = getResourceNameForList(getRequestURL(request, persistentUrl)); + MetadataService metadataService = metadataServiceFactory.getMetadataServiceByUrlPrefix(urlPrefix); + + // 2. Get and check existence entity + IRI uri = i(getRequestURL(request, persistentUrl)); + IRI entityUri = removeLastPartOfIRI(removeLastPartOfIRI(uri)); + Model model = metadataService.retrieve(entityUri); + + // 3. Get state + metadataStateService.modifyState(entityUri, reqDto); + + return reqDto; + } + + private String getResourceNameForList(String url) throws MetadataServiceException { + url = url.replace(persistentUrl, "") + .replace("/meta", "") + .replace("/state", ""); + + String[] parts = url.split("/"); + if (parts.length == 1) { + return ""; + } + + if (parts.length != 3) { + throw new MetadataServiceException("Unsupported URL"); + } + return parts[1]; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/profile/ProfileController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/profile/ProfileController.java new file mode 100644 index 0000000000000000000000000000000000000000..970871a9becb97eec067b8b27724698ee74be67f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/profile/ProfileController.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.profile; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.config.ConverterConfig; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.service.profile.ProfileService; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.Optional; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.util.HttpUtil.getRequestURL; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +@Tag(name = "Client") +@RestController +@RequestMapping("/profile") +public class ProfileController { + + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + + @Autowired + private ProfileService profileService; + + @GetMapping(path = "/{uuid}", produces = { + "text/turtle", + "application/x-turtle", + "text/n3", + "text/rdf+n3", + "application/ld+json", + "application/rdf+xml", + "application/xml", + "text/xml", + }) + public ResponseEntity<Model> getShapeContent(HttpServletRequest request, @PathVariable final String uuid) + throws ResourceNotFoundException { + IRI uri = i(getRequestURL(request, persistentUrl)); + Optional<Model> oDto = profileService.getProfileByUuid(uuid, uri); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ResourceNotFoundException(format("Profile '%s' doesn't exist", uuid)); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/reset/ResetController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/reset/ResetController.java new file mode 100644 index 0000000000000000000000000000000000000000..e92e226d6eb4bdc36b5f81fd20695e2298380097 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/reset/ResetController.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.reset; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.reset.ResetDTO; +import nl.dtls.fairdatapoint.service.reset.ResetService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + +@Tag(name = "Client") +@RestController +public class ResetController { + + @Autowired + private ResetService resetService; + + @PostMapping("/reset") + @PreAuthorize("hasRole('ADMIN')") + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity<Void> postResetFactoryDefaults(@RequestBody @Valid ResetDTO reqDto) throws Exception { + resetService.resetToFactoryDefaults(reqDto); + return ResponseEntity.noContent().build(); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/resource/ResourceDefinitionController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/resource/ResourceDefinitionController.java new file mode 100644 index 0000000000000000000000000000000000000000..74748d4a529d469e914067cc39165bc743f370ae --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/resource/ResourceDefinitionController.java @@ -0,0 +1,97 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.resource; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionChangeDTO; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionDTO; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; +import java.util.Optional; + +import static java.lang.String.format; + +@Tag(name = "Metadata Model") +@RestController +@RequestMapping("/resource-definitions") +public class ResourceDefinitionController { + + @Autowired + private ResourceDefinitionService resourceDefinitionService; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ResourceDefinitionDTO>> getResourceDefinitions() { + List<ResourceDefinitionDTO> dto = resourceDefinitionService.getAll(); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ResourceDefinitionDTO> createResourceDefinitions(@RequestBody @Valid ResourceDefinitionChangeDTO reqDto) throws BindException { + ResourceDefinitionDTO dto = resourceDefinitionService.create(reqDto); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ResourceDefinitionDTO> getResourceDefinition(@PathVariable final String uuid) + throws ResourceNotFoundException { + Optional<ResourceDefinitionDTO> oDto = resourceDefinitionService.getDTOByUuid(uuid); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ResourceNotFoundException(format("Resource Definition '%s' doesn't exist", uuid)); + } + } + + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ResourceDefinitionDTO> putResourceDefinitions(@PathVariable final String uuid, + @RequestBody @Valid ResourceDefinitionChangeDTO reqDto) + throws ResourceNotFoundException, BindException { + Optional<ResourceDefinitionDTO> oDto = resourceDefinitionService.update(uuid, reqDto); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ResourceNotFoundException(format("Resource Definition '%s' doesn't exist", uuid)); + } + } + + @DeleteMapping(path = "/{uuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity<Void> deleteResourceDefinitions(@PathVariable final String uuid) + throws ResourceNotFoundException { + boolean result = resourceDefinitionService.deleteByUuid(uuid); + if (result) { + return ResponseEntity.noContent().build(); + } else { + throw new ResourceNotFoundException(format("Resource Definition '%s' doesn't exist", uuid)); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/search/SearchController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/search/SearchController.java new file mode 100644 index 0000000000000000000000000000000000000000..78f33f44595a251d6d469a94295edb409174c2ac --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/search/SearchController.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.search; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.search.SearchQueryDTO; +import nl.dtls.fairdatapoint.api.dto.search.SearchResultDTO; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.service.search.SearchService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +@Tag(name = "Metadata") +@RestController +@RequestMapping("/search") +public class SearchController { + + @Autowired + private SearchService searchService; + + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<SearchResultDTO>> search(@RequestBody @Valid SearchQueryDTO reqDto) throws MetadataRepositoryException { + return ResponseEntity.ok(searchService.search(reqDto)); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/settings/SettingsController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/settings/SettingsController.java new file mode 100644 index 0000000000000000000000000000000000000000..a5a93864218a5806c672027623dab05ac8ea7f27 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/settings/SettingsController.java @@ -0,0 +1,61 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.controller.settings; + +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsDTO; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsUpdateDTO; +import nl.dtls.fairdatapoint.service.settings.SettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +@Tag(name = "Client") +@RestController +@RequestMapping("/settings") +public class SettingsController { + + @Autowired + private SettingsService settingsService; + + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public SettingsDTO getSettings() { + return settingsService.getCurrentSettings(); + } + + @PutMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public SettingsDTO updateSettings(@RequestBody @Valid SettingsUpdateDTO reqDto) { + return settingsService.updateSettings(reqDto); + } + + @DeleteMapping(produces = MediaType.APPLICATION_JSON_VALUE) + @PreAuthorize("hasRole('ADMIN')") + public SettingsDTO resetSettings() { + return settingsService.resetSettings(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/shape/ShapeController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/shape/ShapeController.java index 078fbcca6ac5c36513a5a2d494c6f17aaa3bcbbf..bd9a2912c1cd4eb5515d0a6bc4336173a3bd8018 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/shape/ShapeController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/shape/ShapeController.java @@ -22,13 +22,18 @@ */ package nl.dtls.fairdatapoint.api.controller.shape; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.shape.ShapeChangeDTO; import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeRemoteDTO; import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; import nl.dtls.fairdatapoint.service.shape.ShapeService; +import org.eclipse.rdf4j.model.Model; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; @@ -37,6 +42,7 @@ import java.util.Optional; import static java.lang.String.format; +@Tag(name = "Metadata Model") @RestController @RequestMapping("/shapes") public class ShapeController { @@ -44,19 +50,40 @@ public class ShapeController { @Autowired private ShapeService shapeService; - @RequestMapping(method = RequestMethod.GET) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<ShapeDTO>> getShapes() { List<ShapeDTO> dto = shapeService.getShapes(); return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(method = RequestMethod.POST) + @GetMapping(path = "/public", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ShapeDTO>> getPublishedShapes() { + List<ShapeDTO> dto = shapeService.getPublishedShapes(); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @PreAuthorize("hasRole('ADMIN')") + @GetMapping(path = "/import", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ShapeRemoteDTO>> getImportableShapes(@RequestParam(name = "from") String fdpUrl) { + List<ShapeRemoteDTO> dto = shapeService.getRemoteShapes(fdpUrl); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @PreAuthorize("hasRole('ADMIN')") + @PostMapping(path = "/import", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ShapeDTO>> importShapes(@RequestBody @Valid List<ShapeRemoteDTO> reqDtos) { + List<ShapeDTO> dto = shapeService.importShapes(reqDtos); + return new ResponseEntity<>(dto, HttpStatus.OK); + } + + @PreAuthorize("hasRole('ADMIN')") + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<ShapeDTO> createShape(@RequestBody @Valid ShapeChangeDTO reqDto) { ShapeDTO dto = shapeService.createShape(reqDto); return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<ShapeDTO> getShape(@PathVariable final String uuid) throws ResourceNotFoundException { Optional<ShapeDTO> oDto = shapeService.getShapeByUuid(uuid); @@ -67,7 +94,28 @@ public class ShapeController { } } - @RequestMapping(value = "/{uuid}", method = RequestMethod.PUT) + @GetMapping(path = "/{uuid}", produces = { + "text/turtle", + "application/x-turtle", + "text/n3", + "text/rdf+n3", + "application/ld+json", + "application/rdf+xml", + "application/xml", + "text/xml", + }) + public ResponseEntity<Model> getShapeContent(@PathVariable final String uuid) + throws ResourceNotFoundException { + Optional<Model> oDto = shapeService.getShapeContentByUuid(uuid); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ResourceNotFoundException(format("Shape '%s' doesn't exist", uuid)); + } + } + + @PreAuthorize("hasRole('ADMIN')") + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<ShapeDTO> putShape(@PathVariable final String uuid, @RequestBody @Valid ShapeChangeDTO reqDto) throws ResourceNotFoundException { Optional<ShapeDTO> oDto = shapeService.updateShape(uuid, reqDto); @@ -78,7 +126,9 @@ public class ShapeController { } } - @RequestMapping(value = "/{uuid}", method = RequestMethod.DELETE) + @PreAuthorize("hasRole('ADMIN')") + @DeleteMapping("/{uuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) public ResponseEntity<Void> deleteShape(@PathVariable final String uuid) throws ResourceNotFoundException { boolean result = shapeService.deleteShape(uuid); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/token/TokenController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/token/TokenController.java index 9d5109015ea6b61a3311e5b00d1f6f247f6bb779..b6344729ad86b368f67d9b17a53617f1821d83bb 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/token/TokenController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/token/TokenController.java @@ -22,22 +22,22 @@ */ package nl.dtls.fairdatapoint.api.controller.token; +import io.swagger.v3.oas.annotations.tags.Tag; import nl.dtls.fairdatapoint.api.dto.auth.AuthDTO; import nl.dtls.fairdatapoint.api.dto.auth.TokenDTO; import nl.dtls.fairdatapoint.service.jwt.JwtService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.AuthenticationException; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +@Tag(name = "Authentication and Authorization") @RestController @RequestMapping("/tokens") public class TokenController { @@ -45,7 +45,7 @@ public class TokenController { @Autowired private JwtService jwtService; - @PostMapping + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<TokenDTO> generateToken(@RequestBody @Valid AuthDTO reqDto) { try { String token = jwtService.createToken(reqDto); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/user/UserController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/user/UserController.java index 56e0615985fb921ee673b2fc877df0e8aaca1489..b84c4c29735f76881694a0d71a8003a41ccc5068 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/user/UserController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/user/UserController.java @@ -22,16 +22,15 @@ */ package nl.dtls.fairdatapoint.api.controller.user; -import nl.dtls.fairdatapoint.api.dto.user.UserChangeDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserCreateDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserPasswordDTO; +import io.swagger.v3.oas.annotations.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.user.*; import nl.dtls.fairdatapoint.entity.exception.ForbiddenException; import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; import nl.dtls.fairdatapoint.service.user.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpEntity; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -41,6 +40,7 @@ import java.util.Optional; import static java.lang.String.format; +@Tag(name = "User Management") @RestController @RequestMapping("/users") public class UserController { @@ -48,21 +48,21 @@ public class UserController { @Autowired private UserService userService; - @RequestMapping(method = RequestMethod.GET) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<List<UserDTO>> getUsers() { List<UserDTO> dto = userService.getUsers(); return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(method = RequestMethod.POST) + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<UserDTO> createUser(@RequestBody @Valid UserCreateDTO reqDto) { UserDTO dto = userService.createUser(reqDto); return new ResponseEntity<>(dto, HttpStatus.OK); } - @RequestMapping(value = "/current", method = RequestMethod.GET) - public ResponseEntity<UserDTO> getUserCurrent() - throws ResourceNotFoundException { + @Tag(name = "Authentication and Authorization") + @GetMapping(path = "/current", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> getUserCurrent() throws ResourceNotFoundException { Optional<UserDTO> oDto = userService.getCurrentUser(); if (oDto.isPresent()) { return new ResponseEntity<>(oDto.get(), HttpStatus.OK); @@ -71,9 +71,8 @@ public class UserController { } } - @RequestMapping(value = "/{uuid}", method = RequestMethod.GET) - public ResponseEntity<UserDTO> getUser(@PathVariable final String uuid) - throws ResourceNotFoundException { + @GetMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> getUser(@PathVariable final String uuid) throws ResourceNotFoundException { Optional<UserDTO> oDto = userService.getUserByUuid(uuid); if (oDto.isPresent()) { return new ResponseEntity<>(oDto.get(), HttpStatus.OK); @@ -82,7 +81,17 @@ public class UserController { } } - @RequestMapping(value = "/{uuid}", method = RequestMethod.PUT) + @PutMapping(path = "/current", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> putUserCurrent(@RequestBody @Valid UserProfileChangeDTO reqDto) throws ResourceNotFoundException { + Optional<UserDTO> oDto = userService.updateCurrentUser(reqDto); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ForbiddenException("You have to be login at first"); + } + } + + @PutMapping(path = "/{uuid}", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<UserDTO> putUser(@PathVariable final String uuid, @RequestBody @Valid UserChangeDTO reqDto) throws ResourceNotFoundException { Optional<UserDTO> oDto = userService.updateUser(uuid, reqDto); @@ -93,7 +102,18 @@ public class UserController { } } - @RequestMapping(value = "/{uuid}/password", method = RequestMethod.PUT) + @PutMapping(path = "/current/password", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> putUserCurrentPassword(@RequestBody @Valid UserPasswordDTO reqDto) + throws ResourceNotFoundException { + Optional<UserDTO> oDto = userService.updatePasswordForCurrentUser(reqDto); + if (oDto.isPresent()) { + return new ResponseEntity<>(oDto.get(), HttpStatus.OK); + } else { + throw new ForbiddenException("You have to be login at first"); + } + } + + @PutMapping(path = "/{uuid}/password", produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<UserDTO> putUserPassword(@PathVariable final String uuid, @RequestBody @Valid UserPasswordDTO reqDto) throws ResourceNotFoundException { Optional<UserDTO> oDto = userService.updatePassword(uuid, reqDto); @@ -104,8 +124,9 @@ public class UserController { } } - @RequestMapping(value = "/{uuid}", method = RequestMethod.DELETE) - public HttpEntity deleteUser(@PathVariable final String uuid) + @DeleteMapping("/{uuid}") + @ResponseStatus(HttpStatus.NO_CONTENT) + public ResponseEntity<Void> deleteUser(@PathVariable final String uuid) throws ResourceNotFoundException { boolean result = userService.deleteUser(uuid); if (result) { diff --git a/src/main/java/nl/dtls/fairdatapoint/api/converter/RdfConverter.java b/src/main/java/nl/dtls/fairdatapoint/api/converter/RdfConverter.java index 9e497d4e834d0ced608ebd0d346fa250741f2fc5..59715f8e1f07b9dd18b71963c96bda520e928df9 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/converter/RdfConverter.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/converter/RdfConverter.java @@ -43,7 +43,7 @@ import java.io.IOException; public class RdfConverter extends AbstractHttpMessageConverter<Model> { - private RDFFormat format; + private final RDFFormat format; public RdfConverter(RDFFormat format) { super(getMediaTypes(format)); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/apikey/ApiKeyDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/apikey/ApiKeyDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..171c09f78146a68420718389bfbfd9698a20b073 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/apikey/ApiKeyDTO.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.apikey; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class ApiKeyDTO { + + private String uuid; + + private String token; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/config/BootstrapConfigDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/config/BootstrapConfigDTO.java index 5e7b264633aceb7710d353ed12d47b85cc3a24d0..1d23539071ff4bdcf8018b50255d62517cc17cf7 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/dto/config/BootstrapConfigDTO.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/config/BootstrapConfigDTO.java @@ -26,6 +26,10 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionDTO; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; + +import java.util.List; @NoArgsConstructor @AllArgsConstructor @@ -35,4 +39,8 @@ public class BootstrapConfigDTO { protected String persistentUrl; + protected List<ResourceDefinitionDTO> resourceDefinitions; + + protected boolean index; + } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/dashboard/DashboardItemDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/dashboard/DashboardItemDTO.java index 08a4812f9e0da75e1af3c8d1938da9ce0333ee6c..d9f5b51cce57d1a75d0279ff92db355346914af3 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/dto/dashboard/DashboardItemDTO.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/dashboard/DashboardItemDTO.java @@ -27,6 +27,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import nl.dtls.fairdatapoint.api.dto.membership.MembershipDTO; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; import java.util.List; import java.util.Optional; @@ -45,4 +46,6 @@ public class DashboardItemDTO { protected Optional<MembershipDTO> membership; + protected MetadataState state; + } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..b891d7d27588ef997870ebe4cea96cff366467c4 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDTO.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.entry; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexEntryDTO { + + @NotNull + private String uuid; + + @NotNull + @URL + private String clientUrl; + + @NotNull + private IndexEntryStateDTO state; + + @NotNull + private String registrationTime; + + @NotNull + private String modificationTime; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDetailDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDetailDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..28583103eef94cf77fa7e7c7c3bf9697aceafc80 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryDetailDTO.java @@ -0,0 +1,67 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.entry; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.api.dto.index.event.EventDTO; +import nl.dtls.fairdatapoint.entity.index.entry.RepositoryMetadata; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexEntryDetailDTO { + + @NotNull + private String uuid; + + @NotNull + @URL + private String clientUrl; + + @NotNull + private IndexEntryStateDTO state; + + @NotNull + private RepositoryMetadata currentMetadata; + + @NotNull + private List<EventDTO> events; + + @NotNull + private String registrationTime; + + @NotNull + private String modificationTime; + + @NotNull + private String lastRetrievalTime; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryInfoDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryInfoDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..0799270ef039c5c6a5bf648eee3e4149ab93c384 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryInfoDTO.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.entry; + +import lombok.*; + +import java.util.Map; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class IndexEntryInfoDTO { + + private Map<String, Long> entriesCount; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryStateDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryStateDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..6890aea466910636ddb29c456993742ad9fa2949 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/entry/IndexEntryStateDTO.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.entry; + +public enum IndexEntryStateDTO { + + UNKNOWN, + + ACTIVE, + + INACTIVE, + + UNREACHABLE, + + INVALID +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/event/EventDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/event/EventDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..0bae018af97d2fddce60efddd94cbf692fa47a41 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/event/EventDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.event; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.entity.index.event.EventType; + +import javax.validation.constraints.NotNull; +import java.util.UUID; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class EventDTO { + + @NotNull + private UUID uuid; + + @NotNull + private EventType type; + + @NotNull + private String created; + + private String finished; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/ping/PingDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/ping/PingDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..c14d82126ec320cb47340a6daffe27b6805a9c65 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/ping/PingDTO.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.ping; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class PingDTO { + + @NotNull + @URL + private String clientUrl; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..448d4969d894b9ce3e7cb08bcc675fa975782629 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsDTO.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexSettingsDTO { + @NotNull + private IndexSettingsRetrievalDTO retrieval; + + @NotNull + private IndexSettingsPingDTO ping; + + @NotNull + private Boolean isDefault; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsPingDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsPingDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..616e6826ccf4fe3570f7cbc9f57149d1feddc7d6 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsPingDTO.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.api.validator.ValidDuration; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexSettingsPingDTO { + @NotNull + @ValidDuration + private String validDuration; + @NotNull + @ValidDuration + private String rateLimitDuration; + @NotNull + private Integer rateLimitHits; + @NotNull + private List<String> denyList; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsRetrievalDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsRetrievalDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..d630da3432a47b8a0a8a3122a296dc8df8277802 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsRetrievalDTO.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.api.validator.ValidDuration; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexSettingsRetrievalDTO { + @NotNull + @ValidDuration + private String rateLimitWait; + + @NotNull + @ValidDuration + private String timeout; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsUpdateDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsUpdateDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..09905c30fb62bc739bded419b1a7865d16f66487 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/settings/IndexSettingsUpdateDTO.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class IndexSettingsUpdateDTO { + @Valid + @NotNull + private IndexSettingsRetrievalDTO retrieval; + + @Valid + @NotNull + private IndexSettingsPingDTO ping; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/index/webhook/WebhookPayloadDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/webhook/WebhookPayloadDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..bd2a682000e8ab288cfa164bf40987415bb469c5 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/index/webhook/WebhookPayloadDTO.java @@ -0,0 +1,37 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.index.webhook; + +import lombok.Data; +import lombok.NoArgsConstructor; +import nl.dtls.fairdatapoint.entity.index.webhook.WebhookEvent; + +@Data +@NoArgsConstructor +public class WebhookPayloadDTO { + private WebhookEvent event; + private String uuid; + private String clientUrl; + private String timestamp; + private String secret; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/label/LabelDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/label/LabelDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..58290dc1a190e0cefffb7618d32dbd2ac2a22b7a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/label/LabelDTO.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.label; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class LabelDTO { + private String label; + private String lang; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/membership/MembershipDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/membership/MembershipDTO.java index c6e293be1eb6c451e60f2cc7c6c62fdb89c99c5a..69798d0d5e7422fcf8d3587c4da494dd834d1aad 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/dto/membership/MembershipDTO.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/membership/MembershipDTO.java @@ -24,7 +24,6 @@ package nl.dtls.fairdatapoint.api.dto.membership; import lombok.AllArgsConstructor; import lombok.Data; -import nl.dtls.fairdatapoint.entity.membership.MembershipEntity; import java.util.List; @@ -38,6 +37,6 @@ public class MembershipDTO { private List<MembershipPermissionDTO> permissions; - private List<MembershipEntity> allowedEntities; + private List<String> allowedEntities; } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..aa6598ccaa550da14b0b53b8c6aa6bbdad4db4cb --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +@Schema(name = "MetaDTO") +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class MetaDTO { + + @JsonInclude + private MemberDTO member; + + @JsonInclude + private MetaStateDTO state; + + @NotNull + private Map<String, MetaPathDTO> path; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaPathDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaPathDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..6362d342690e49026d05978b4a973d0058c06ebe --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaPathDTO.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.metadata; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class MetaPathDTO { + + @NotNull + private String resourceDefinitionUuid; + + @NotNull + private String title; + + @JsonInclude + private String parent = null; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateChangeDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateChangeDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..f2f3a8c71df32b6b6c2bd9816f39ded93bdc1c8f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateChangeDTO.java @@ -0,0 +1,37 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.metadata; + +import lombok.*; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class MetaStateChangeDTO { + + private MetadataState current; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..3c978717b21850b174a99623e486c26cde417fda --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/metadata/MetaStateDTO.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.metadata; + +import lombok.*; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; + +import java.util.Map; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@ToString +public class MetaStateDTO { + + private MetadataState current; + + private Map<String, MetadataState> children; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/reset/ResetDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/reset/ResetDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..136e88342f0d8275fd9aa61060864b602b275c29 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/reset/ResetDTO.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.reset; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ResetDTO { + + private boolean users; + + private boolean metadata; + + private boolean resourceDefinitions; + + private boolean settings; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionChangeDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionChangeDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..c957992ef848d86d6a0afb86c20f08b13c9926f0 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionChangeDTO.java @@ -0,0 +1,60 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.resource; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.api.validator.ValidIri; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionLink; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ResourceDefinitionChangeDTO { + + @NotBlank + protected String name; + + @NotNull + protected String urlPrefix; + + @NotNull + protected List<String> shapeUuids; + + @NotNull + @Valid + protected List<ResourceDefinitionChild> children; + + @NotNull + @Valid + protected List<ResourceDefinitionLink> externalLinks; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..fa2c800ebf4234f1100c6622479b4f3c5dd54dba --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/resource/ResourceDefinitionDTO.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.resource; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionLink; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ResourceDefinitionDTO { + + @NotBlank + private String uuid; + + @NotBlank + protected String name; + + @NotNull + protected String urlPrefix; + + @NotNull + protected List<String> shapeUuids; + + @NotNull + protected List<String> targetClassUris; + + @NotNull + @Valid + protected List<ResourceDefinitionChild> children; + + @NotNull + @Valid + protected List<ResourceDefinitionLink> externalLinks; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchQueryDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchQueryDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..9916c1f13158971e8ad690861d8707f6a57817dc --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchQueryDTO.java @@ -0,0 +1,41 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.search; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SearchQueryDTO { + + @NotNull + private String q; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchResultDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchResultDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..22c4c8ea165abc3ebb321df51ecc10a781977313 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/search/SearchResultDTO.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.search; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.entity.search.SearchResultRelation; + +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SearchResultDTO { + + private String uri; + + private List<String> types; + + private String title; + + private String description; + + private List<SearchResultRelation> relations; + +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsService.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsDTO.java old mode 100755 new mode 100644 similarity index 64% rename from src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsService.java rename to src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsDTO.java index dd39043021e62f901ecb33bd52451212fa142b91..c59e31611372a281cf4817952037d714b94922fc --- a/src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsService.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsDTO.java @@ -20,27 +20,29 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package nl.dtls.fairdatapoint.service.metadatametrics; +package nl.dtls.fairdatapoint.api.dto.settings; -import nl.dtls.fairdatapoint.entity.metadata.Metric; -import org.eclipse.rdf4j.model.IRI; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.entity.settings.SettingsMetricsEntry; -import javax.annotation.Nonnull; import java.util.List; -public interface FairMetadataMetricsService { +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SettingsDTO { + + private String clientUrl; + + private String persistentUrl; + + private List<SettingsMetricsEntry> metadataMetrics; - /** - * This method returns list of fair metrics for the given metadata URI - * - * @param metadataURI metadata URI - * @return List of fair metrics - */ - List<Metric> getMetrics(@Nonnull IRI metadataURI); + private SettingsPingDTO ping; + private SettingsRepositoryDTO repository; } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..ef3ccd313d8e7f13c7b6631e54373c7e94ba9a3a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingDTO.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SettingsPingDTO { + + @NotNull + private Boolean enabled; + + @NotNull + private List<String> endpoints; + + @NotNull + private String interval; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingUpdateDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingUpdateDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..46dadb201725ef05698b3c27c7338c19c6bd764c --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsPingUpdateDTO.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.settings; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class SettingsPingUpdateDTO { + + private boolean enabled; + + @NotNull + private List<String> endpoints; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsRepositoryDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsRepositoryDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..16b1c57ab9847c96b8bcb255e3ccb0a96434f26b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsRepositoryDTO.java @@ -0,0 +1,41 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SettingsRepositoryDTO { + private String type; + private String dir; + private String url; + private String repository; + private String username; + private String password; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsUpdateDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsUpdateDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..abb6f4dab187a66318a50e60abd96fb76aba9dde --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/settings/SettingsUpdateDTO.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.settings; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import nl.dtls.fairdatapoint.entity.settings.SettingsMetricsEntry; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SettingsUpdateDTO { + + @NotNull + private List<SettingsMetricsEntry> metadataMetrics; + + @NotNull + private SettingsPingUpdateDTO ping; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeChangeDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeChangeDTO.java index f992e0832603ee5754b62ff69232dc03a11bd5f7..625c7a8056ddbacf9c660f3472bf38d3a765fca9 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeChangeDTO.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeChangeDTO.java @@ -28,6 +28,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; @NoArgsConstructor @AllArgsConstructor @@ -38,6 +39,8 @@ public class ShapeChangeDTO { @NotBlank private String name; + private boolean published; + private String definition; } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeDTO.java index 5193b904f2c53ab54a4e8efdfd5950a4736a7ff2..a9844dc51f1a56b6c371eab34a1211495dbc57b8 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeDTO.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeDTO.java @@ -28,6 +28,8 @@ import lombok.NoArgsConstructor; import lombok.Setter; import nl.dtls.fairdatapoint.entity.shape.ShapeType; +import java.util.List; + @NoArgsConstructor @AllArgsConstructor @Getter @@ -38,8 +40,11 @@ public class ShapeDTO { private String name; + private boolean published; + private ShapeType type; private String definition; + private List<String> targetClasses; } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeRemoteDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeRemoteDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..8dfde6c8c84ffd82f8e83ff1c168d64cb62e0b5d --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/shape/ShapeRemoteDTO.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.shape; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class ShapeRemoteDTO { + private String from; + + private String uuid; + + private String name; + + private String definition; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/dto/user/UserProfileChangeDTO.java b/src/main/java/nl/dtls/fairdatapoint/api/dto/user/UserProfileChangeDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..307da1ff31cd26a544541aef07673b35cd86c311 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/dto/user/UserProfileChangeDTO.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.dto.user; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class UserProfileChangeDTO { + + @NotBlank + protected String firstName; + + @NotBlank + protected String lastName; + + @NotBlank + protected String email; + + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/filter/CORSFilter.java b/src/main/java/nl/dtls/fairdatapoint/api/filter/CORSFilter.java index 1a07a3eb8acdf962fe0b0fdc584622e5911925e5..187945c64d2c9e2a677993c1182d499e3a46dd52 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/filter/CORSFilter.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/filter/CORSFilter.java @@ -55,7 +55,8 @@ public class CORSFilter extends OncePerRequestFilter { response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, format("%s,%s,%s,%s", HttpHeaders.ORIGIN, HttpHeaders.AUTHORIZATION, HttpHeaders.ACCEPT, HttpHeaders.CONTENT_TYPE)); - response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, format("%s", HttpHeaders.LOCATION)); + response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, format("%s,%s", HttpHeaders.LOCATION, + HttpHeaders.LINK)); response.setHeader(HttpHeaders.ALLOW, allowedMtds); response.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, allowedMtds); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/filter/JwtTokenFilter.java b/src/main/java/nl/dtls/fairdatapoint/api/filter/JwtTokenFilter.java index 3cc1d1b5dcbf18af8f0599e29e33b60bff4244ea..c1c534afaa09a1320de92bdccdb5fc8ba09cb1ab 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/filter/JwtTokenFilter.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/filter/JwtTokenFilter.java @@ -25,6 +25,7 @@ package nl.dtls.fairdatapoint.api.filter; import com.fasterxml.jackson.databind.ObjectMapper; import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; import nl.dtls.fairdatapoint.entity.exception.UnauthorizedException; +import nl.dtls.fairdatapoint.service.apikey.ApiKeyService; import nl.dtls.fairdatapoint.service.jwt.JwtService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -40,12 +41,17 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import static nl.dtls.fairdatapoint.util.HttpUtil.getToken; + @Component public class JwtTokenFilter extends OncePerRequestFilter { @Autowired private JwtService jwtService; + @Autowired + private ApiKeyService apiKeyService; + @Autowired private ObjectMapper objectMapper; @@ -53,18 +59,38 @@ public class JwtTokenFilter extends OncePerRequestFilter { public void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain fc) throws IOException, ServletException { + String token = getToken(request); + if (tryWithUser(token) || tryWithApiKey(token)) { + fc.doFilter(request, response); + } else { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType(MediaType.APPLICATION_JSON.toString()); + ErrorDTO error = new ErrorDTO(HttpStatus.UNAUTHORIZED, "You have to be log in"); + objectMapper.writeValue(response.getWriter(), error); + } + } + + private boolean tryWithUser(String token) { try { - String token = jwtService.resolveToken(request); if (token != null && jwtService.validateToken(token)) { Authentication auth = jwtService.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(auth); } - fc.doFilter(request, response); + return true; } catch (UnauthorizedException e) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - response.setContentType(MediaType.APPLICATION_JSON.toString()); - ErrorDTO error = new ErrorDTO(HttpStatus.UNAUTHORIZED, e.getMessage()); - objectMapper.writeValue(response.getWriter(), error); + return false; + } + } + + private boolean tryWithApiKey(String token) { + try { + if (token != null) { + Authentication auth = apiKeyService.getAuthentication(token); + SecurityContextHolder.getContext().setAuthentication(auth); + } + return true; + } catch (UnauthorizedException e) { + return false; } } diff --git a/src/main/java/nl/dtls/fairdatapoint/api/filter/LoggingFilter.java b/src/main/java/nl/dtls/fairdatapoint/api/filter/LoggingFilter.java index 28801d60caac9399992b79ca729ed6b2d845467c..2840b7109d1fd396a0e8e973248b4008e0438fc0 100755 --- a/src/main/java/nl/dtls/fairdatapoint/api/filter/LoggingFilter.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/filter/LoggingFilter.java @@ -27,7 +27,9 @@ */ package nl.dtls.fairdatapoint.api.filter; +import nl.dtls.fairdatapoint.service.UtilityService; import org.apache.logging.log4j.ThreadContext; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -41,12 +43,15 @@ import java.io.IOException; @Component public class LoggingFilter extends OncePerRequestFilter { + @Autowired + private UtilityService utilityService; + @Override public void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain fc) throws IOException, ServletException { - ThreadContext.put("ipAddress", request.getRemoteAddr()); + ThreadContext.put("ipAddress", utilityService.getRemoteAddr(request)); ThreadContext.put("responseStatus", String.valueOf(response.getStatus())); ThreadContext.put("requestMethod", request.getMethod()); ThreadContext.put("requestURI", request.getRequestURI()); diff --git a/src/main/java/nl/dtls/fairdatapoint/api/validator/DurationValidator.java b/src/main/java/nl/dtls/fairdatapoint/api/validator/DurationValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..618dbd846c83913b1efef9d39822dc9f18de7083 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/validator/DurationValidator.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.validator; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import java.time.Duration; + +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +public class DurationValidator implements ConstraintValidator<ValidDuration, String> { + + @Override + public void initialize(ValidDuration text) { + } + + @Override + public boolean isValid(String text, ConstraintValidatorContext cxt) { + try { + Duration.parse(text); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/validator/IriValidator.java b/src/main/java/nl/dtls/fairdatapoint/api/validator/IriValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..c348cf500872dda5a5ea47003be9388d95594a21 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/validator/IriValidator.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.validator; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +public class IriValidator implements ConstraintValidator<ValidIri, String> { + + @Override + public void initialize(ValidIri text) { + } + + @Override + public boolean isValid(String text, ConstraintValidatorContext cxt) { + try { + i(text); + return true; + } catch (Exception e) { + return false; + } + } + +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidDuration.java b/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidDuration.java new file mode 100644 index 0000000000000000000000000000000000000000..f46b8ac4e7ffc99db16d6b9855c191d9dd78a60b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidDuration.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = DurationValidator.class) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidDuration { + + String message() default "Invalid ISO-8601 duration"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidIri.java b/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidIri.java new file mode 100644 index 0000000000000000000000000000000000000000..25f1c0e3bc32a06cb51f8398b936bb4abb5133ca --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/api/validator/ValidIri.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.api.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = IriValidator.class) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ValidIri { + + String message() default "Invalid IRI"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/config/AclConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/AclConfig.java index bc62eb8e91a9c0d029741f151b395afc4d6a9cd9..2a6c3bcb9a16a46c853e9503a1617a7efb7746d8 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/AclConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/AclConfig.java @@ -43,14 +43,12 @@ import org.springframework.security.acls.mongodb.BasicLookupStrategy; import org.springframework.security.acls.mongodb.MongoDBMutableAclService; import org.springframework.security.core.authority.SimpleGrantedAuthority; -import java.util.List; - import static java.lang.String.format; @Configuration public class AclConfig { - private static final String CACHE_NAME = "ACL_CACHE"; + public static final String ACL_CACHE = "ACL_CACHE"; @Autowired private MongoTemplate mongoTemplate; @@ -60,8 +58,7 @@ public class AclConfig { @Bean public AclCache aclCache(ConcurrentMapCacheManager cacheManager) { - cacheManager.setCacheNames(List.of(CACHE_NAME)); - Cache springCache = cacheManager.getCache(CACHE_NAME); + Cache springCache = cacheManager.getCache(ACL_CACHE); return new SpringCacheBasedAclCache(springCache, permissionGrantingStrategy(), aclAuthorizationStrategy()); } diff --git a/src/main/java/nl/dtls/fairdatapoint/config/AsyncConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/AsyncConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..716504dccff306e0b66beb6a7067795d1e903e22 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/AsyncConfig.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config; + +import nl.dtls.fairdatapoint.Profiles; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.EnableAsync; + +@Configuration +@EnableAsync +@Profile(Profiles.NON_TESTING) +public class AsyncConfig { +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/CacheConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/CacheConfig.java index aa2017a5480da11b850957203779c0f9a86e8c8a..61b5ed1555c0fda860c9827fb1c3e8788f509b17 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/CacheConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/CacheConfig.java @@ -23,12 +23,43 @@ package nl.dtls.fairdatapoint.config; import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.List; + +import static nl.dtls.fairdatapoint.config.AclConfig.ACL_CACHE; + @Configuration @EnableCaching public class CacheConfig { public static final String CATALOG_THEMES_CACHE = "CATALOG_THEMES_CACHE"; + public static final String RESOURCE_DEFINITION_CACHE = "RESOURCE_DEFINITION_CACHE"; + + public static final String RESOURCE_DEFINITION_PARENT_CACHE = "RESOURCE_DEFINITION_PARENT_CACHE"; + + public static final String RESOURCE_DEFINITION_TARGET_CLASSES_CACHE = "RESOURCE_DEFINITION_TARGET_CLASSES_CACHE"; + + public static final String LABEL_CACHE = "LABEL_CACHE"; + + public static final String SETTINGS_CACHE = "SETTINGS_CACHE"; + + @Bean + public ConcurrentMapCacheManager cacheManager() { + ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); + cacheManager.setCacheNames(List.of( + ACL_CACHE, + CATALOG_THEMES_CACHE, + RESOURCE_DEFINITION_CACHE, + RESOURCE_DEFINITION_PARENT_CACHE, + RESOURCE_DEFINITION_TARGET_CLASSES_CACHE, + SETTINGS_CACHE, + LABEL_CACHE + )); + return cacheManager; + } + } diff --git a/src/main/java/nl/dtls/fairdatapoint/config/MetricsValueConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/HttpClientConfig.java old mode 100755 new mode 100644 similarity index 64% rename from src/main/java/nl/dtls/fairdatapoint/config/MetricsValueConfig.java rename to src/main/java/nl/dtls/fairdatapoint/config/HttpClientConfig.java index 397530d6c8f9ef88ab5362a6bce8a5341aef8b26..cfc186cf682a2e8fc0d168b3cc60cbcf9984e1b7 --- a/src/main/java/nl/dtls/fairdatapoint/config/MetricsValueConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/HttpClientConfig.java @@ -20,28 +20,33 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package nl.dtls.fairdatapoint.config; -import org.springframework.beans.factory.config.YamlMapFactoryBean; +import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; +import org.springframework.web.client.RestTemplate; -import java.util.Map; +import java.net.http.HttpClient; +import java.time.Duration; @Configuration -public class MetricsValueConfig { +public class HttpClientConfig { + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) { + return restTemplateBuilder + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(5)) + .build(); + } - @Bean(name = "metadataMetrics") - public Map<String, String> metadataMetrics() { - YamlMapFactoryBean yamlFactory = new YamlMapFactoryBean(); - yamlFactory.setResources(new ClassPathResource("application.yml")); - return (Map<String, String>) yamlFactory.getObject().get("metadataMetrics"); + @Bean + public HttpClient httpClient() { + return HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.ALWAYS) + .build(); } -} +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/config/MetadataConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/MetadataConfig.java index 65b556d902e4864e37a0dd24ca7cbb8840020ad4..64894132905ebbd663bf299d87c0f4732fd5b180 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/MetadataConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/MetadataConfig.java @@ -22,41 +22,25 @@ */ package nl.dtls.fairdatapoint.config; -import nl.dtls.fairdatapoint.entity.metadata.Agent; +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; import org.eclipse.rdf4j.model.IRI; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static nl.dtls.fairdatapoint.util.HttpUtil.removeLastSlash; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; -import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.l; @Configuration public class MetadataConfig { - @Value("${instance.clientUrl}") - private String clientUrl; + @Autowired + private InstanceProperties instanceProperties; @Bean(name = "persistentUrl") - public String persistentUrl(@Value("${instance.persistentUrl:}") String persistentUrl) { - if (persistentUrl == null || persistentUrl.isEmpty()) { - return clientUrl; - } - return removeLastSlash(persistentUrl); - } - - @Bean(name = "publisher") - public Agent publisher(@Value("${metadataProperties.publisherURI:}") String publisherURI, - @Value("${metadataProperties.publisherName:}") String publishername) { - - Agent publisher = null; - if (!publisherURI.isEmpty() && !publishername.isEmpty()) { - publisher = new Agent(); - publisher.setUri(i(publisherURI)); - publisher.setName(l(publishername)); - } - return publisher; + public String persistentUrl() { + return removeLastSlash(instanceProperties.getUrl()); } @Bean(name = "language") @@ -78,5 +62,4 @@ public class MetadataConfig { } return license; } - } diff --git a/src/main/java/nl/dtls/fairdatapoint/config/MongoConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/MongoConfig.java index 1af85374596c350b76188013c0cbb67e1a5e6e1f..934890d77f9c70ea54ef065f7b37e5b7f5da6aec 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/MongoConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/MongoConfig.java @@ -22,34 +22,41 @@ */ package nl.dtls.fairdatapoint.config; -import com.github.mongobee.Mongobee; +import com.github.cloudyrock.mongock.config.LegacyMigration; +import com.github.cloudyrock.mongock.driver.mongodb.springdata.v3.SpringDataMongoV3Driver; +import com.github.cloudyrock.spring.v5.MongockSpring5; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionTargetClassesCache; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.env.Environment; import org.springframework.data.mongodb.config.EnableMongoAuditing; +import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @Configuration @EnableMongoAuditing -@EnableMongoRepositories(basePackages = {"nl.dtls.fairdatapoint", "nl.dtls.rdf.migration", "org.springframework" + - ".security.acls"}) +@EnableMongoRepositories(basePackages = {"nl.dtls.fairdatapoint", "nl.dtls.rdf.migration", "org.springframework.security.acls"}) public class MongoConfig { - @Value("${spring.data.mongodb.uri}") - private String mongoUri; + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; @Autowired - private Environment environment; + private ResourceDefinitionTargetClassesCache targetClassesCache; - @Bean - public Mongobee mongobee() throws Exception { - Mongobee runner = new Mongobee(mongoUri); - runner.setChangeLogsScanPackage("nl.dtls.fairdatapoint"); - runner.setSpringEnvironment(environment); - runner.execute(); - return runner; + @Bean("mongockRunner") + public MongockSpring5.MongockApplicationRunner mongockApplicationRunner( + ApplicationContext springContext, + MongoTemplate mongoTemplate) { + return MongockSpring5.builder() + .setDriver(SpringDataMongoV3Driver.withDefaultLock(mongoTemplate)) + .addChangeLogsScanPackage("nl.dtls.fairdatapoint.database.mongo.migration.production") + .setSpringContext(springContext) + .setLegacyMigration(new LegacyMigration("dbchangelog")) + .addDependency(ResourceDefinitionCache.class, resourceDefinitionCache) + .addDependency(ResourceDefinitionTargetClassesCache.class, targetClassesCache) + .buildApplicationRunner(); } - } \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/config/OpenApiConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/OpenApiConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..52db8d619243a8b0bc0aa22f54f4cdb1ee9740ca --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/OpenApiConfig.java @@ -0,0 +1,93 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.tags.Tag; +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.config.properties.OpenApiProperties; +import nl.dtls.fairdatapoint.service.openapi.OpenApiTagsUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.info.BuildProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@Configuration +public class OpenApiConfig { + + @Bean + public OpenAPI customOpenAPI(InstanceProperties instanceProperties, OpenApiProperties openApiProperties) { + OpenAPI openAPI = new OpenAPI() + .servers(Collections.singletonList(new Server().url(instanceProperties.getUrl()))) + .components(new Components() + .addSecuritySchemes("bearer-jwt", new SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .bearerFormat("JWT") + .in(SecurityScheme.In.HEADER) + .name("Authorization") + ) + ) + .info(new Info() + .title(openApiProperties.getTitle()) + .description(openApiProperties.getDescription()) + .version(openApiProperties.getVersion()) + .license( + new License() + .name("The MIT License") + .url("https://opensource.org/licenses/MIT") + ) + ) + .addSecurityItem(new SecurityRequirement() + .addList("bearer-jwt", Arrays.asList("read", "write")) + ) + .tags(OpenApiTagsUtils.STATIC_TAGS); + if (openApiProperties.getContact().getUrl() != null) { + openAPI.getInfo().contact(new Contact() + .url(openApiProperties.getContact().getUrl()) + .name(openApiProperties.getContact().getName()) + .email(openApiProperties.getContact().getEmail()) + ); + } + openAPI.servers(Collections.singletonList(new Server().url(instanceProperties.getUrl()))); + openAPI.setExtensions(new LinkedHashMap<>()); + openAPI.getExtensions().put("fdpGenericPaths", new Paths()); + openAPI.setPaths(new Paths()); + return openAPI; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/RepositoryConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/RepositoryConfig.java index 7bb749f68f4687c184bee27789ed5b0b393aba0a..32289614875e7121cbb492fdcf1bd872573caf48 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/RepositoryConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/RepositoryConfig.java @@ -23,6 +23,7 @@ package nl.dtls.fairdatapoint.config; import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.config.properties.RepositoryProperties; import org.eclipse.rdf4j.repository.Repository; import org.eclipse.rdf4j.repository.RepositoryException; import org.eclipse.rdf4j.repository.config.RepositoryConfigException; @@ -33,6 +34,7 @@ import org.eclipse.rdf4j.repository.sparql.SPARQLRepository; import org.eclipse.rdf4j.sail.Sail; import org.eclipse.rdf4j.sail.memory.MemoryStore; import org.eclipse.rdf4j.sail.nativerdf.NativeStore; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.context.ApplicationContext; @@ -47,52 +49,21 @@ import static nl.dtls.fairdatapoint.util.HttpUtil.removeLastSlash; @Log4j2 public class RepositoryConfig { - @Value("${repository.agraph.url:}") - private String agraphUrl; - - @Value("${repository.agraph.username:}") - private String agraphUsername; - - @Value("${repository.agraph.password:}") - private String agraphPassword; - - @Value("${repository.graphDb.url:}") - private String graphDbUrl; - - @Value("${repository.graphDb.repository:}") - private String graphDbRepository; - - @Value("${repository.blazegraph.url:}") - private String blazegraphUrl; - - @Value("${repository.blazegraph.repository:}") - private String blazegraphRepository; - - @Value("${repository.native.dir:}") - private String nativeStoreDir; + @Autowired + private RepositoryProperties repositoryProperties; @Bean(initMethod = "initialize", destroyMethod = "shutDown") - public Repository repository(@Value("${repository.type:1}") int storeType, ApplicationContext context) + public Repository repository(ApplicationContext context) throws RepositoryException { - Repository repository = null; - switch (storeType) { - case 1: - repository = getInMemoryStore(); - break; - case 2: - repository = getNativeStore(); - break; - case 3: - repository = getAgraphRepository(); - break; - case 4: - repository = getGraphDBRepository(); - break; - case 5: - repository = getBlazeGraphRepository(); - break; - } + Repository repository = switch (repositoryProperties.getType()) { + case 1 -> getInMemoryStore(); + case 2 -> getNativeStore(); + case 3 -> getAgraphRepository(); + case 4 -> getGraphDBRepository(); + case 5 -> getBlazeGraphRepository(); + default -> null; + }; if (repository == null) { log.error("Failed to configure a RDF repository"); @@ -107,43 +78,47 @@ public class RepositoryConfig { private Repository getInMemoryStore() { log.info("Setting up InMemory Store"); Sail store = new MemoryStore(); - SailRepository repository = new SailRepository(store); - return repository; + return new SailRepository(store); } private Repository getNativeStore() { log.info("Setting up Native Store"); - if (!nativeStoreDir.isEmpty()) { - File dataDir = new File(nativeStoreDir); + if (!repositoryProperties.getNativeRepo().getDir().isEmpty()) { + File dataDir = new File(repositoryProperties.getNativeRepo().getDir()); return new SailRepository(new NativeStore(dataDir)); } - log.warn("'nativeStoreDir' is empty"); + log.warn("'repository.native.dir' is empty"); return null; } private Repository getAgraphRepository() { log.info("Setting up Allegro Graph Store"); - if (!agraphUrl.isEmpty()) { - SPARQLRepository repository = new SPARQLRepository(agraphUrl); - if (!agraphUsername.isEmpty() && !agraphPassword.isEmpty()) { - repository.setUsernameAndPassword(agraphUsername, agraphPassword); + if (!repositoryProperties.getAgraph().getUrl().isEmpty()) { + SPARQLRepository repository = new SPARQLRepository(repositoryProperties.getAgraph().getUrl()); + if (!repositoryProperties.getAgraph().getUsername().isEmpty() && + !repositoryProperties.getAgraph().getPassword().isEmpty()) { + repository.setUsernameAndPassword( + repositoryProperties.getAgraph().getUsername(), + repositoryProperties.getAgraph().getPassword() + ); } return repository; } - log.warn("'agraphUrl' is empty"); + log.warn("'repository.agraph.url' is empty"); return null; } private Repository getBlazeGraphRepository() { log.info("Setting up Blaze Graph Store"); + String blazegraphUrl = repositoryProperties.getBlazegraph().getUrl(); if (!blazegraphUrl.isEmpty()) { blazegraphUrl = removeLastSlash(blazegraphUrl); // Build url for blazegraph (Eg: http://localhost:8079/bigdata/namespace/test1/sparql) StringBuilder sb = new StringBuilder(); sb.append(blazegraphUrl); sb.append("/namespace/"); - if (!blazegraphRepository.isEmpty()) { - sb.append(blazegraphRepository); + if (!repositoryProperties.getBlazegraph().getRepository().isEmpty()) { + sb.append(repositoryProperties.getBlazegraph().getRepository()); } else { sb.append("kb"); } @@ -151,18 +126,34 @@ public class RepositoryConfig { String url = sb.toString(); return new SPARQLRepository(url); } - log.warn("'blazegraphUrl' is empty"); + log.warn("'repository.blazegraph.url' is empty"); return null; } private Repository getGraphDBRepository() { log.info("Setting up GraphDB Store"); try { - if (!graphDbUrl.isEmpty() && !graphDbRepository.isEmpty()) { - RepositoryManager repositoryManager = new RemoteRepositoryManager(graphDbUrl); - repositoryManager.initialize(); - return repositoryManager.getRepository(graphDbRepository); + if (!repositoryProperties.getGraphDb().getUrl().isEmpty() && + !repositoryProperties.getGraphDb().getRepository().isEmpty()) { + final RepositoryManager repositoryManager; + if (!repositoryProperties.getGraphDb().getUsername().isEmpty() && + !repositoryProperties.getGraphDb().getPassword().isEmpty()) { + repositoryManager = RemoteRepositoryManager.getInstance( + repositoryProperties.getGraphDb().getUrl(), + repositoryProperties.getGraphDb().getUsername(), + repositoryProperties.getGraphDb().getPassword() + ); + } else { + repositoryManager = RemoteRepositoryManager.getInstance( + repositoryProperties.getGraphDb().getUrl() + ); + } + + return repositoryManager.getRepository( + repositoryProperties.getGraphDb().getRepository() + ); } + log.warn("'repository.graphDb.url' or 'repository.graphDb.repository' is empty"); } catch (RepositoryConfigException | RepositoryException e) { log.error("Failed to connect to GraphDB"); } diff --git a/src/main/java/nl/dtls/fairdatapoint/config/RepositoryMigrationConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/RepositoryMigrationConfig.java index df7b4aed92a7ed33cb9210c6e7479a467504b505..c37735fe281e3a0023add32b67465df1282366fc 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/RepositoryMigrationConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/RepositoryMigrationConfig.java @@ -35,7 +35,7 @@ import org.springframework.context.annotation.Profile; public class RepositoryMigrationConfig { @Bean - @DependsOn("mongobee") + @DependsOn("mongockRunner") @Profile(Profiles.PRODUCTION) public RdfProductionMigrationRunner rdfProductionMigrationRunner(RdfMigrationRepository rdfMigrationRepository, ApplicationContext appContext) { diff --git a/src/main/java/nl/dtls/fairdatapoint/config/SecurityConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/SecurityConfig.java index cb6fe05b6743ca02728ab10a813b80e7d5e9fbe3..c78f034c8937a11a164bb5bf98804d77f6a11f5c 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/SecurityConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/SecurityConfig.java @@ -55,11 +55,14 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers("/dashboard").authenticated() .antMatchers("/users**").authenticated() + .antMatchers("/api-keys**").authenticated() .antMatchers("/users/**").authenticated() .antMatchers("/memberships**").authenticated() .antMatchers("/tokens").permitAll() + .antMatchers("/search**").permitAll() + .antMatchers("/index/admin**").authenticated() + .antMatchers("/index**").permitAll() .antMatchers(HttpMethod.PUT, "/**").authenticated() - .antMatchers(HttpMethod.POST, "/**").authenticated() .anyRequest().permitAll() .and() .apply(filterConfigurer); diff --git a/src/main/java/nl/dtls/fairdatapoint/config/SwaggerConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/SwaggerConfig.java deleted file mode 100755 index 80ea0aad14ad4566cbba25a488b3e92a69ffd2a9..0000000000000000000000000000000000000000 --- a/src/main/java/nl/dtls/fairdatapoint/config/SwaggerConfig.java +++ /dev/null @@ -1,101 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package nl.dtls.fairdatapoint.config; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import springfox.documentation.builders.PathSelectors; -import springfox.documentation.builders.RequestHandlerSelectors; -import springfox.documentation.service.*; -import springfox.documentation.spi.DocumentationType; -import springfox.documentation.spi.service.contexts.SecurityContext; -import springfox.documentation.spring.web.plugins.Docket; -import springfox.documentation.swagger2.annotations.EnableSwagger2; - -import java.util.Collections; -import java.util.List; - -import static nl.dtls.fairdatapoint.util.HttpUtil.removeProtocol; - -@Configuration -@EnableSwagger2 -public class SwaggerConfig { - - @Value("${instance.clientUrl}") - private String clientUrl; - - @Bean - public Docket api() { - return new Docket(DocumentationType.SWAGGER_2) - .select() - .apis(RequestHandlerSelectors.any()) - .paths(PathSelectors.any()) - .build() - .apiInfo(apiInfo()) - .host(removeProtocol(clientUrl)) - .securitySchemes(List.of(apiKey())) - .securityContexts(List.of(securityContext())); - } - - private ApiInfo apiInfo() { - return new ApiInfo( - "FAIR Data Point API", - "<a target='_blank' " + - " href='https://github.com/FAIRDataTeam/FAIRDataPoint/wiki/FAIR-Data-Point-Specification'>" + - " FAIR Data Point Specification" + - " </a>" + - " <br/>", - "1.3.0", - "ATO", - new Contact("Luiz Bonino", - "https://github.com/FAIRDataTeam/FAIRDataPoint", - "luiz.bonino@go-fair.org"), - "The MIT License", - "https://opensource.org/licenses/MIT", - Collections.emptyList() - ); - } - - private ApiKey apiKey() { - return new ApiKey("apiKey", "Authorization", "header"); - } - - private SecurityContext securityContext() { - return SecurityContext.builder() - .securityReferences(defaultAuth()) - .forPaths(PathSelectors.any()) - .build(); - } - - private List<SecurityReference> defaultAuth() { - AuthorizationScope[] authorizationScopes = {new AuthorizationScope("global", "global description")}; - return List.of(new SecurityReference("apiKey", authorizationScopes)); - } - -} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/WebConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/WebConfig.java index bba4dae3c1df0540347dccda8ff992a063e98959..3a985c09b6f2b849058e8cfbc7b3223f5418c865 100755 --- a/src/main/java/nl/dtls/fairdatapoint/config/WebConfig.java +++ b/src/main/java/nl/dtls/fairdatapoint/config/WebConfig.java @@ -22,6 +22,7 @@ */ package nl.dtls.fairdatapoint.config; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import nl.dtls.fairdatapoint.api.converter.ErrorConverter; import nl.dtls.fairdatapoint.api.converter.RdfConverter; @@ -35,11 +36,13 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.resource.WebJarsResourceResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; import java.util.List; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY; +import static org.springdoc.core.Constants.CLASSPATH_RESOURCE_LOCATION; @Configuration public class WebConfig implements WebMvcConfigurer { @@ -52,10 +55,10 @@ public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { + converters.add(new StringHttpMessageConverter()); converters.addAll(errorConverters); converters.addAll(rdfConverters); - converters.add(new MappingJackson2HttpMessageConverter()); - converters.add(new StringHttpMessageConverter()); + converters.add(new MappingJackson2HttpMessageConverter(objectMapper())); } @Override @@ -66,17 +69,16 @@ public class WebConfig implements WebMvcConfigurer { for (RdfConverter converter : rdfConverters) { converter.configureContentNegotiation(configurer); } - configurer.favorPathExtension(false); configurer.favorParameter(true); } @Override public void addResourceHandlers(final ResourceHandlerRegistry registry) { // Swagger - registry.setOrder(Integer.MIN_VALUE + 1).addResourceHandler("/swagger-ui.html") - .addResourceLocations("classpath:/META-INF/resources/"); - registry.setOrder(Integer.MIN_VALUE + 2).addResourceHandler("/webjars/**") - .addResourceLocations("classpath:/META-INF/resources/webjars/"); + registry.setOrder(Integer.MIN_VALUE + 1).addResourceHandler("/webjars/**") + .addResourceLocations(CLASSPATH_RESOURCE_LOCATION+"/webjars/") + .resourceChain(true) + .addResolver(new WebJarsResourceResolver()); } @Bean @@ -85,8 +87,12 @@ public class WebConfig implements WebMvcConfigurer { final ObjectMapper mapper = new ObjectMapper(); mapper.findAndRegisterModules(); mapper.setSerializationInclusion(NON_NULL); - mapper.enable(SORT_PROPERTIES_ALPHABETICALLY); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); return mapper; } + @Bean + public InternalResourceViewResolver defaultViewResolver() { + return new InternalResourceViewResolver(); + } } diff --git a/src/main/java/nl/dtls/fairdatapoint/config/WorkerConfig.java b/src/main/java/nl/dtls/fairdatapoint/config/WorkerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..982d72d18012aed2bfa85cd2cd1e597fd6a5109b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/WorkerConfig.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class WorkerConfig { + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/InstanceProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/InstanceProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..2e8fe4bebb83d1e5542de6e19866fd0cd7c566ea --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/InstanceProperties.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ConfigurationProperties(prefix = "instance") +public class InstanceProperties { + private String clientUrl = "http://localhost:8080"; + private String persistentUrl = null; + private boolean behindProxy = true; + private boolean index = false; + + public String getUrl() { + if (persistentUrl == null || persistentUrl.isBlank()) { + return clientUrl; + } + return persistentUrl; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiContactProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiContactProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..f289ddab6aaa0cf959a1789294bf3b9717e84975 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiContactProperties.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class OpenApiContactProperties { + private String name; + private String email; + private String url; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..1cc5d10cec2cf168a16018cbf4b9f8e6ebb761d9 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/OpenApiProperties.java @@ -0,0 +1,41 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ConfigurationProperties(prefix = "openapi") +public class OpenApiProperties { + private String title; + private String version; + private String description; + private OpenApiContactProperties contact; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/PingProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/PingProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..b5737fb61e28365dd8d721bf79d948c1079e3e95 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/PingProperties.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.time.Duration; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ConfigurationProperties(prefix = "ping") +public class PingProperties { + private boolean enabled = true; + private String initDelay = "10000"; + private Duration interval = Duration.ofDays(7); +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryBasicProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryBasicProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..15481d3aef7b3306aab7852bb65fcc3c276950cd --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryBasicProperties.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class RepositoryBasicProperties { + private String url = ""; + private String repository = ""; + private String username = ""; + private String password = ""; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryNativeProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryNativeProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..c825379bdc4593b511da4805987127ca35f85a2b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryNativeProperties.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class RepositoryNativeProperties { + private String dir = ""; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryProperties.java b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..b26d71429fa95ffc03c3b987003a0b114e7d3bb8 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/config/properties/RepositoryProperties.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.config.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@ConfigurationProperties(prefix = "repository") +public class RepositoryProperties { + private int type; + private RepositoryNativeProperties nativeRepo = null; + private RepositoryBasicProperties agraph = null; + private RepositoryBasicProperties graphDb = null; + private RepositoryBasicProperties blazegraph = null; + + public void setNative(RepositoryNativeProperties nativeRepo) { + this.nativeRepo = nativeRepo; + } + + public String getStringType() { + return switch (type) { + case 1 -> "InMemory"; + case 2 -> "Native"; + case 3 -> "AllegroGraph"; + case 4 -> "GraphDB"; + case 5 -> "Blazegraph"; + default -> "Invalid"; + }; + } + + public String getDir() { + if (type == 2) { + return nativeRepo.getDir(); + } + return null; + } + + public String getUrl() { + return switch (type) { + case 3 -> agraph.getUrl(); + case 4 -> graphDb.getUrl(); + case 5 -> blazegraph.getUrl(); + default -> null; + }; + } + + public String getRepository() { + return switch (type) { + case 3 -> agraph.getRepository(); + case 4 -> graphDb.getRepository(); + case 5 -> blazegraph.getRepository(); + default -> null; + }; + } + + public String getUsername() { + return switch (type) { + case 3 -> agraph.getUsername(); + case 4 -> graphDb.getUsername(); + default -> null; + }; + } + + public String getPassword() { + return switch (type) { + case 3 -> agraph.getPassword(); + case 4 -> graphDb.getPassword(); + default -> null; + }; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/MigrationRunner.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/MigrationRunner.java index dd6ae9da5ff5afa84c8d3260bbbf52891223963f..e816fea38900b3fdad41b2d21b0585a58a96cd53 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/MigrationRunner.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/MigrationRunner.java @@ -24,7 +24,11 @@ package nl.dtls.fairdatapoint.database.mongo.migration.development; import nl.dtls.fairdatapoint.Profiles; import nl.dtls.fairdatapoint.database.mongo.migration.development.acl.AclMigration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.ApiKeyMigration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.index.entry.IndexEntryMigration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.index.event.EventMigration; import nl.dtls.fairdatapoint.database.mongo.migration.development.membership.MembershipMigration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.MetadataMigration; import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.ResourceDefinitionMigration; import nl.dtls.fairdatapoint.database.mongo.migration.development.shape.ShapeMigration; import nl.dtls.fairdatapoint.database.mongo.migration.development.user.UserMigration; @@ -53,6 +57,18 @@ public class MigrationRunner { @Autowired private ShapeMigration shapeMigration; + @Autowired + private ApiKeyMigration apiKeyMigration; + + @Autowired + private MetadataMigration metadataMigration; + + @Autowired + private IndexEntryMigration indexEntryMigration; + + @Autowired + private EventMigration eventMigration; + @PostConstruct public void run() { userMigration.runMigration(); @@ -60,6 +76,10 @@ public class MigrationRunner { aclMigration.runMigration(); resourceDefinitionMigration.runMigration(); shapeMigration.runMigration(); + apiKeyMigration.runMigration(); + metadataMigration.runMigration(); + indexEntryMigration.runMigration(); + eventMigration.runMigration(); } } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/ApiKeyMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/ApiKeyMigration.java new file mode 100644 index 0000000000000000000000000000000000000000..81ed7f163f57b10ad2ac328a73f972ad7c2d21f9 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/ApiKeyMigration.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.apikey; + +import nl.dtls.fairdatapoint.database.common.migration.Migration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.data.ApiKeyFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ApiKeyRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ApiKeyMigration implements Migration { + + @Autowired + private ApiKeyFixtures apiKeyFixtures; + + @Autowired + private ApiKeyRepository apiKeyRepository; + + public void runMigration() { + apiKeyRepository.deleteAll(); + apiKeyRepository.save(apiKeyFixtures.albertApiKey()); + apiKeyRepository.save(apiKeyFixtures.nikolaApiKey()); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/data/ApiKeyFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/data/ApiKeyFixtures.java new file mode 100644 index 0000000000000000000000000000000000000000..16fe31cc8e6ba044fb7d2b1a7aa6170006a30cec --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/apikey/data/ApiKeyFixtures.java @@ -0,0 +1,58 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.data; + +import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; +import nl.dtls.fairdatapoint.entity.apikey.ApiKey; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class ApiKeyFixtures { + + @Autowired + private UserFixtures userFixtures; + + public final String ALBERT_API_KEY = "a274793046e34a219fd0ea6362fcca61a001500b71724f4c973a017031653c20"; + + public final String NIKOLA_API_KEY = "dd5dc3b53b6145cfa9f6c58b72ebad21cd2f860ace62451ba4e3c74a0e63540a"; + + public ApiKey albertApiKey() { + return new ApiKey( + null, + "a1c00673-24c5-4e0a-bdbe-22e961ee7548", + userFixtures.albert().getUuid(), + ALBERT_API_KEY + ); + } + + public ApiKey nikolaApiKey() { + return new ApiKey( + null, + "62657760-21fe-488c-a0ea-f612a70493da", + userFixtures.nikola().getUuid(), + NIKOLA_API_KEY + ); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/IndexEntryMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/IndexEntryMigration.java new file mode 100644 index 0000000000000000000000000000000000000000..587336676b936ee3880f7fa238986c96d8f537f2 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/IndexEntryMigration.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.index.entry; + +import nl.dtls.fairdatapoint.database.common.migration.Migration; +import nl.dtls.fairdatapoint.database.mongo.migration.development.index.entry.data.IndexEntryFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class IndexEntryMigration implements Migration { + + @Autowired + private IndexEntryFixtures indexEntryFixtures; + + @Autowired + private IndexEntryRepository indexEntryRepository; + + public void runMigration() { + indexEntryRepository.deleteAll(); + + indexEntryRepository.save(indexEntryFixtures.entryActive()); + indexEntryRepository.save(indexEntryFixtures.entryActive2()); + indexEntryRepository.save(indexEntryFixtures.entryInactive()); + indexEntryRepository.save(indexEntryFixtures.entryUnreachable()); + indexEntryRepository.save(indexEntryFixtures.entryInvalid()); + indexEntryRepository.save(indexEntryFixtures.entryUnknown()); + } + +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/data/IndexEntryFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/data/IndexEntryFixtures.java new file mode 100644 index 0000000000000000000000000000000000000000..a7e91361c1d00f878a01a7f78a6fc5404ac8008d --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/entry/data/IndexEntryFixtures.java @@ -0,0 +1,105 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.index.entry.data; + +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.RepositoryMetadata; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.HashMap; + +import static nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState.*; + +@Service +public class IndexEntryFixtures { + + public IndexEntry entryActive() { + String clientUri = "https://example.com/my-valid-fairdatapoint"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + return new IndexEntry("8987abc1-15a4-4752-903c-8f8a5882cca6", clientUri, Valid, Instant.now(), Instant.now(), + Instant.now(), repositoryData); + } + + public IndexEntry entryActive2() { + String clientUri = "https://app.fairdatapoint.org"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + Instant date = Instant.parse("2020-05-30T23:38:23.085Z"); + return new IndexEntry("c912331f-4a77-4300-a469-dbaf5fc0b4e2", clientUri, Valid, date, date, date, + repositoryData); + } + + public IndexEntry entryInactive() { + String clientUri = "https://example.com/my-valid-fairdatapoint"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + Instant date = Instant.parse("2020-05-30T23:38:23.085Z"); + return new IndexEntry("b5851ebe-aacf-4de9-bf0a-3686e9256e73", clientUri, Valid, date, date, date, + repositoryData); + } + + public IndexEntry entryUnreachable() { + String clientUri = "https://example.com/my-unreachable-fairdatapoint"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + return new IndexEntry("dae46b47-87fb-4fdf-995c-8aa3739a27fc", clientUri, Unreachable, Instant.now(), + Instant.now(), Instant.now(), repositoryData); + } + + public IndexEntry entryInvalid() { + String clientUri = "https://example.com/my-invalid-fairdatapoint"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + return new IndexEntry("b37e8c1f-ac0e-49f8-8e07-35571c4f8235", clientUri, Invalid, Instant.now(), + Instant.now(), Instant.now(), repositoryData); + } + + public IndexEntry entryUnknown() { + String clientUri = "https://example.com/my-unknown-fairdatapoint"; + RepositoryMetadata repositoryData = new RepositoryMetadata( + RepositoryMetadata.CURRENT_VERSION, + clientUri, + new HashMap<>() + ); + return new IndexEntry("4471d7c5-8c5b-4581-a9bc-d175456492c4", clientUri, Unknown, Instant.now(), + Instant.now(), Instant.now(), repositoryData); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/event/EventMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/event/EventMigration.java new file mode 100644 index 0000000000000000000000000000000000000000..5e7768c0a1a1861b077df705724723c7f08d312e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/index/event/EventMigration.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.index.event; + +import nl.dtls.fairdatapoint.database.mongo.repository.EventRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class EventMigration { + + @Autowired + private EventRepository eventRepository; + + public void runMigration() { + eventRepository.deleteAll(); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/membership/data/MembershipFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/membership/data/MembershipFixtures.java index 5b4544b5c107c3b8ae63deabe8b0e1b1c4ddc23f..726dfc0043db15148d032baaec43fc6807d58e85 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/membership/data/MembershipFixtures.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/membership/data/MembershipFixtures.java @@ -22,14 +22,13 @@ */ package nl.dtls.fairdatapoint.database.mongo.migration.development.membership.data; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; import nl.dtls.fairdatapoint.entity.membership.Membership; import nl.dtls.fairdatapoint.entity.membership.MembershipPermission; import org.springframework.stereotype.Service; import java.util.ArrayList; -import static nl.dtls.fairdatapoint.entity.membership.MembershipEntity.*; - @Service public class MembershipFixtures { @@ -50,9 +49,9 @@ public class MembershipFixtures { add(ADMINISTRATION); }}, new ArrayList<>() {{ - add(CATALOG); - add(DATASET); - add(DISTRIBUTION); + add(ResourceDefinitionFixtures.CATALOG_DEFINITION_UUID); + add(ResourceDefinitionFixtures.DATASET_DEFINITION_UUID); + add(ResourceDefinitionFixtures.DISTRIBUTION_DEFINITION_UUID); }} ); } @@ -65,7 +64,7 @@ public class MembershipFixtures { add(CREATE); }}, new ArrayList<>() {{ - add(CATALOG); + add(ResourceDefinitionFixtures.CATALOG_DEFINITION_UUID); }} ); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/MetadataMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/MetadataMigration.java new file mode 100644 index 0000000000000000000000000000000000000000..695fca295a624ed967982b3f5eb7d8e833f34192 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/MetadataMigration.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.metadata; + +import nl.dtls.fairdatapoint.database.common.migration.Migration; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MetadataMigration implements Migration { + + @Autowired + private MetadataRepository metadataRepository; + + public void runMigration() { + metadataRepository.deleteAll(); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/data/MetadataFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/data/MetadataFixtures.java new file mode 100644 index 0000000000000000000000000000000000000000..823318d2085b8d1375159c338e33ba5782293b0e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/metadata/data/MetadataFixtures.java @@ -0,0 +1,101 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data; + +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +@Service +public class MetadataFixtures { + + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + + public Metadata repositoryMetadata() { + return + new Metadata( + null, + persistentUrl, + MetadataState.PUBLISHED + ); + } + + public Metadata catalog1() { + return + new Metadata( + null, + persistentUrl + "/catalog/catalog-1", + MetadataState.PUBLISHED + ); + } + + public Metadata catalog2() { + return + new Metadata( + null, + persistentUrl + "/catalog/catalog-2", + MetadataState.DRAFT + ); + } + + public Metadata dataset1() { + return + new Metadata( + null, + persistentUrl + "/dataset/dataset-1", + MetadataState.PUBLISHED + ); + } + + public Metadata dataset2() { + return + new Metadata( + null, + persistentUrl + "/dataset/dataset-2", + MetadataState.DRAFT + ); + } + + public Metadata distribution1() { + return + new Metadata( + null, + persistentUrl + "/distribution/distribution-1", + MetadataState.PUBLISHED + ); + } + + public Metadata distribution2() { + return + new Metadata( + null, + persistentUrl + "/distribution/distribution-2", + MetadataState.DRAFT + ); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/ResourceDefinitionMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/ResourceDefinitionMigration.java index 447437d1ece756257a9fc9f79b4e7dafe347867e..3ed4b6f8973ba1949bab79cedde782c847fcd152 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/ResourceDefinitionMigration.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/ResourceDefinitionMigration.java @@ -26,6 +26,7 @@ import nl.dtls.fairdatapoint.database.common.migration.Migration; import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -38,6 +39,9 @@ public class ResourceDefinitionMigration implements Migration { @Autowired private ResourceDefinitionRepository resourceDefinitionRepository; + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + public void runMigration() { resourceDefinitionRepository.deleteAll(); @@ -52,6 +56,8 @@ public class ResourceDefinitionMigration implements Migration { ResourceDefinition distributionDef = resourceDefinitionFixtures.distributionDefinition(); resourceDefinitionRepository.save(distributionDef); + + resourceDefinitionCache.computeCache(); } } \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/data/ResourceDefinitionFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/data/ResourceDefinitionFixtures.java index fa39cf178734a2fd4269a7df452a3740217527b8..b0644ba0ea03f07400ef77f1b0218d6b8e5b633b 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/data/ResourceDefinitionFixtures.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/resource/data/ResourceDefinitionFixtures.java @@ -22,7 +22,8 @@ */ package nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data; -import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.database.mongo.migration.development.shape.data.ShapeFixtures; +import nl.dtls.fairdatapoint.entity.resource.*; import nl.dtls.fairdatapoint.vocabulary.R3D; import org.eclipse.rdf4j.model.vocabulary.DCAT; import org.springframework.stereotype.Service; @@ -40,31 +41,43 @@ public class ResourceDefinitionFixtures { public static String DISTRIBUTION_DEFINITION_UUID = "02c649de-c579-43bb-b470-306abdc808c7"; + public static String ONTOLOGY_DEFINITION_UUID = "4bc19f45-845d-48d6-ade7-ac2664563f60"; + public ResourceDefinition repositoryDefinition() { return new ResourceDefinition( REPOSITORY_DEFINITION_UUID, "Repository", "", - "http://www.re3data.org/schema/3-0#Repository", - "https://www.purl.org/fairtools/fdp/schema/0.1/fdpMetadata", - List.of("http://www.w3.org/ns/dcat#Resource", "http://www.re3data.org/schema/3-0#Repository"), - R3D.DATACATALOG.stringValue(), - null, - CATALOG_DEFINITION_UUID + List.of(ShapeFixtures.RESOURCE_SHAPE_UUID, ShapeFixtures.REPOSITORY_SHAPE_UUID), + List.of(new ResourceDefinitionChild( + CATALOG_DEFINITION_UUID, + R3D.DATACATALOG.stringValue(), + new ResourceDefinitionChildListView( + "Catalogs", + "http://www.w3.org/ns/dcat#themeTaxonomy", + List.of() + ) + )), + List.of() ); } public ResourceDefinition catalogDefinition() { return new ResourceDefinition( - "a0949e72-4466-4d53-8900-9436d1049a4b", + CATALOG_DEFINITION_UUID, "Catalog", "catalog", - "http://www.w3.org/ns/dcat#Catalog", - "https://www.purl.org/fairtools/fdp/schema/0.1/catalogMetadata", - List.of("http://www.w3.org/ns/dcat#Resource", "http://www.w3.org/ns/dcat#Catalog"), - DCAT.HAS_DATASET.stringValue(), - REPOSITORY_DEFINITION_UUID, - DATASET_DEFINITION_UUID + List.of(ShapeFixtures.RESOURCE_SHAPE_UUID, ShapeFixtures.CATALOG_SHAPE_UUID), + List.of(new ResourceDefinitionChild( + DATASET_DEFINITION_UUID, + DCAT.HAS_DATASET.stringValue(), + new ResourceDefinitionChildListView( + "Datasets", + "http://www.w3.org/ns/dcat#theme", + List.of() + ) + )), + List.of() ); } @@ -73,12 +86,18 @@ public class ResourceDefinitionFixtures { DATASET_DEFINITION_UUID, "Dataset", "dataset", - "http://www.w3.org/ns/dcat#Dataset", - "https://www.purl.org/fairtools/fdp/schema/0.1/datasetMetadata", - List.of("http://www.w3.org/ns/dcat#Resource", "http://www.w3.org/ns/dcat#Dataset"), - DCAT.HAS_DISTRIBUTION.stringValue(), - CATALOG_DEFINITION_UUID, - DISTRIBUTION_DEFINITION_UUID + List.of(ShapeFixtures.RESOURCE_SHAPE_UUID, ShapeFixtures.DATASET_SHAPE_UUID), + List.of(new ResourceDefinitionChild( + DISTRIBUTION_DEFINITION_UUID, + DCAT.HAS_DISTRIBUTION.stringValue(), + new ResourceDefinitionChildListView("Distributions", null, List.of( + new ResourceDefinitionChildListViewMetadata( + "Media Type", + "http://www.w3.org/ns/dcat#mediaType" + ) + )) + )), + List.of() ); } @@ -87,12 +106,23 @@ public class ResourceDefinitionFixtures { DISTRIBUTION_DEFINITION_UUID, "Distribution", "distribution", - "http://www.w3.org/ns/dcat#Distribution", - "https://www.purl.org/fairtools/fdp/schema/0.1/distributionMetadata", - List.of("http://www.w3.org/ns/dcat#Resource", "http://www.w3.org/ns/dcat#Distribution"), - null, - DATASET_DEFINITION_UUID, - null + List.of(ShapeFixtures.RESOURCE_SHAPE_UUID, ShapeFixtures.DISTRIBUTION_SHAPE_UUID), + List.of(), + List.of( + new ResourceDefinitionLink("Access online", "http://www.w3.org/ns/dcat#accessURL"), + new ResourceDefinitionLink("Download", "http://www.w3.org/ns/dcat#downloadURL") + ) + ); + } + + public ResourceDefinition ontologyDefinition() { + return new ResourceDefinition( + ONTOLOGY_DEFINITION_UUID, + "Ontology", + "ontology", + List.of(ShapeFixtures.RESOURCE_SHAPE_UUID), + List.of(), + List.of() ); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/shape/data/ShapeFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/shape/data/ShapeFixtures.java index 039b0be28b9107ee69209bee98fe551f40a44fa9..04a9d3b557717cab1a51fde25193c4bb2e6c8e71 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/shape/data/ShapeFixtures.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/development/shape/data/ShapeFixtures.java @@ -26,21 +26,35 @@ import nl.dtls.fairdatapoint.entity.shape.Shape; import nl.dtls.fairdatapoint.entity.shape.ShapeType; import org.springframework.stereotype.Service; +import java.util.Set; + @Service public class ShapeFixtures { + public static final String RESOURCE_SHAPE_UUID = "6a668323-3936-4b53-8380-a4fd2ed082ee"; + + public static final String REPOSITORY_SHAPE_UUID = "a92958ab-a414-47e6-8e17-68ba96ba3a2b"; + + public static final String CATALOG_SHAPE_UUID = "2aa7ba63-d27a-4c0e-bfa6-3a4e250f4660"; + + public static final String DATASET_SHAPE_UUID = "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3"; + + public static final String DISTRIBUTION_SHAPE_UUID = "ebacbf83-cd4f-4113-8738-d73c0735b0ab"; + public Shape resourceShape() { return new Shape( null, "6a668323-3936-4b53-8380-a4fd2ed082ee", "Resource", + false, ShapeType.INTERNAL, "@prefix : <http://fairdatapoint.org/> .\n" + - "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix foaf: <http://xmlns.com/foaf/0.1/>.\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" + - "@prefix dash: <http://datashapes.org/dash#> .\n" + "\n" + ":ResourceShape a sh:NodeShape ;\n" + " sh:targetClass dcat:Resource ;\n" + @@ -56,6 +70,12 @@ public class ShapeFixtures { " sh:maxCount 1 ;\n" + " dash:editor dash:TextAreaEditor ;\n" + " ], [\n" + + " sh:path dct:publisher ;\n" + + " sh:node :AgentShape ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:BlankNodeEditor ;\n" + + " ], [\n" + " sh:path dct:hasVersion ;\n" + " sh:name \"version\" ;\n" + " sh:nodeKind sh:Literal ;\n" + @@ -64,19 +84,13 @@ public class ShapeFixtures { " dash:editor dash:TextFieldEditor ;\n" + " dash:viewer dash:LiteralViewer ;\n" + " ], [\n" + - " sh:path dct:license ;\n" + + " sh:path dct:language ;\n" + " sh:nodeKind sh:IRI ;\n" + " sh:maxCount 1 ;\n" + " dash:editor dash:URIEditor ;\n" + " dash:viewer dash:LabelViewer ;\n" + " ], [\n" + - " sh:path dct:conformsTo ;\n" + - " sh:name \"specification\" ;\n" + - " sh:maxCount 1 ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " dash:viewer dash:LabelViewer ;\n" + - " ], [\n" + - " sh:path dct:language ;\n" + + " sh:path dct:license ;\n" + " sh:nodeKind sh:IRI ;\n" + " sh:maxCount 1 ;\n" + " dash:editor dash:URIEditor ;\n" + @@ -85,15 +99,20 @@ public class ShapeFixtures { " sh:path dct:rights ;\n" + " sh:nodeKind sh:IRI ;\n" + " sh:maxCount 1 ;\n" + - " ], [\n" + - " sh:path dct:issued ;\n" + - " sh:datatype xsd:dateTime ;\n" + - " sh:maxCount 1 ;\n" + - " ], [\n" + - " sh:path dct:modified ;\n" + - " sh:datatype xsd:dateTime ;\n" + - " sh:maxCount 1 ;\n" + - " ] ." + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n" + + "\n" + + ":AgentShape a sh:NodeShape ;\n" + + " sh:targetClass foaf:Agent ;\n" + + " sh:property [\n" + + " sh:path foaf:name;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " ] .", + Set.of("http://www.w3.org/ns/dcat#Resource") ); } @@ -102,34 +121,49 @@ public class ShapeFixtures { null, "a92958ab-a414-47e6-8e17-68ba96ba3a2b", "Repository", + false, ShapeType.INTERNAL, "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix r3d: <http://www.re3data.org/schema/3-0#> .\n" + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" + - "@prefix r3d: <http://www.re3data.org/schema/3-0#> .\n" + "\n" + ":RepositoryShape a sh:NodeShape ;\n" + " sh:targetClass r3d:Repository ;\n" + " sh:property [\n" + - " sh:path r3d:startDate ;\n" + - " sh:datatype xsd:date ;\n" + - " sh:maxCount 1 ;\n" + - " ] ,\n" + - " [\n" + - " sh:path r3d:lastUpdate ;\n" + - " sh:datatype xsd:date ;\n" + - " sh:maxCount 1 ;\n" + - " ] ,\n" + - " [\n" + - " sh:path r3d:institution ;\n" + - " sh:class r3d:Institution ;\n" + - " sh:maxCount 1 ;\n" + - " ] ,\n" + - " [\n" + - " sh:path r3d:institutionCountry ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:maxCount 1 ;\n" + - " ] ." + " sh:path dct:references ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path r3d:institution ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path r3d:startDate ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path r3d:lastUpdate ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path r3d:institutionCountry ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n", + Set.of("http://www.w3.org/ns/dcat#Repository") ); } @@ -138,31 +172,39 @@ public class ShapeFixtures { null, "2aa7ba63-d27a-4c0e-bfa6-3a4e250f4660", "Catalog", + false, ShapeType.INTERNAL, "@prefix : <http://fairdatapoint.org/> .\n" + - "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + "@prefix dct: <http://purl.org/dc/terms/> .\n" + "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n" + - "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + "\n" + ":CatalogShape a sh:NodeShape ;\n" + " sh:targetClass dcat:Catalog ;\n" + " sh:property [\n" + - " sh:path dct:isPartOf ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:minCount 1 ;\n" + - " sh:maxCount 1 ;\n" + - " ],\n" + - " [\n" + - " sh:path foaf:homePage ;\n" + - " sh:maxCount 1 ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:themeTaxonomy ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " dash:viewer dash:LabelViewer ;\n" + - " ] ." + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path foaf:homePage ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:themeTaxonomy ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n", + Set.of("http://www.w3.org/ns/dcat#Catalog") ); } @@ -171,43 +213,53 @@ public class ShapeFixtures { null, "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3", "Dataset", - ShapeType.INTERNAL, + false, + ShapeType.CUSTOM, "@prefix : <http://fairdatapoint.org/> .\n" + - "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + "@prefix dct: <http://purl.org/dc/terms/> .\n" + - "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + "\n" + ":DatasetShape a sh:NodeShape ;\n" + " sh:targetClass dcat:Dataset ;\n" + " sh:property [\n" + - " sh:path dct:isPartOf ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:minCount 1 ;\n" + - " sh:maxCount 1 ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:landingPage ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:maxCount 1 ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:theme ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " dash:editor dash:URIEditor ;\n" + - " dash:viewer dash:LabelViewer ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:keyword ;\n" + - " sh:nodeKind sh:Literal ;\n" + - " dash:editor dash:TextFieldEditor ;\n" + - " dash:viewer dash:LiteralViewer ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:contactPoint ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:maxCount 1 ;\n" + - " ] ." + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:theme ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:minCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:contactPoint ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:keyword ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:landingPage ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n", + Set.of("http://www.w3.org/ns/dcat#Dataset") ); } @@ -216,52 +268,59 @@ public class ShapeFixtures { null, "ebacbf83-cd4f-4113-8738-d73c0735b0ab", "Distribution", - ShapeType.INTERNAL, + false, + ShapeType.CUSTOM, "@prefix : <http://fairdatapoint.org/> .\n" + - "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + "@prefix dct: <http://purl.org/dc/terms/> .\n" + - "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + "\n" + ":DistributionShape a sh:NodeShape ;\n" + " sh:targetClass dcat:Distribution ;\n" + " sh:property [\n" + - " sh:path dct:isPartOf ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:minCount 1 ;\n" + - " sh:maxCount 1 ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:accessURL ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:maxCount 1 ;\n" + - " dash:editor dash:URIEditor ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:downloadURL ;\n" + - " sh:nodeKind sh:IRI ;\n" + - " sh:maxCount 1 ;\n" + - " dash:editor dash:URIEditor ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:mediaType ;\n" + - " sh:nodeKind sh:Literal ;\n" + - " sh:minCount 1 ;\n" + - " sh:maxCount 1 ;\n" + - " dash:editor dash:TextFieldEditor ;\n" + - " dash:viewer dash:LiteralViewer ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:format ;\n" + - " sh:nodeKind sh:Literal ;\n" + - " sh:maxCount 1 ;\n" + - " dash:editor dash:TextFieldEditor ;\n" + - " ],\n" + - " [\n" + - " sh:path dcat:byteSize ;\n" + - " sh:nodeKind sh:Literal ;\n" + - " sh:maxCount 1 ;\n" + - " ] ." + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:accessURL ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " ], [\n" + + " sh:path dcat:downloadURL ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " ], [\n" + + " sh:path dcat:mediaType ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:format ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:byteSize ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ] .", + Set.of("http://www.w3.org/ns/dcat#Distribution") ); } @@ -270,6 +329,7 @@ public class ShapeFixtures { null, "ceba9984-9838-4be2-a2a7-12213016fd96", "Custom Shape", + false, ShapeType.CUSTOM, "@prefix : <http://fairdatapoint.org/> .\n" + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + @@ -283,7 +343,8 @@ public class ShapeFixtures { " sh:nodeKind sh:IRI ;\n" + " dash:editor dash:URIEditor ;\n" + " dash:viewer dash:LabelViewer ;\n" + - " ] ." + " ] .", + Set.of("http://example.org/Dog") ); } @@ -292,6 +353,7 @@ public class ShapeFixtures { null, customShape().getUuid(), customShape().getName(), + false, customShape().getType(), "@prefix : <http://fairdatapoint.org/> .\n" + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + @@ -311,7 +373,8 @@ public class ShapeFixtures { " sh:nodeKind sh:Literal ;\n" + " dash:editor dash:TextFieldEditor ;\n" + " dash:viewer dash:LiteralViewer ;\n" + - " ] ." + " ] .", + Set.of("http://example.org/Dog") ); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0001_Init.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0001_Init.java index 00d797bc779c44f2bfa9e1cffb404a060d237c7a..af2742c35d10c9d437f3c61619feba9721f5f55d 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0001_Init.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0001_Init.java @@ -22,8 +22,8 @@ */ package nl.dtls.fairdatapoint.database.mongo.migration.production; -import com.github.mongobee.changeset.ChangeLog; -import com.github.mongobee.changeset.ChangeSet; +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import nl.dtls.fairdatapoint.Profiles; diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_Custom_metamodel.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_CustomMetamodel.java old mode 100755 new mode 100644 similarity index 97% rename from src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_Custom_metamodel.java rename to src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_CustomMetamodel.java index b4dea022bd83e5c2e6af5043a2722fa930c41247..e63858962f98d1fe06555c5b912280119aed1cdf --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_Custom_metamodel.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0002_CustomMetamodel.java @@ -22,8 +22,8 @@ */ package nl.dtls.fairdatapoint.database.mongo.migration.production; -import com.github.mongobee.changeset.ChangeLog; -import com.github.mongobee.changeset.ChangeSet; +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import nl.dtls.fairdatapoint.Profiles; @@ -37,7 +37,7 @@ import static com.mongodb.client.model.Updates.set; @ChangeLog(order = "0002") @Profile(Profiles.PRODUCTION) -public class Migration_0002_Custom_metamodel { +public class Migration_0002_CustomMetamodel { @ChangeSet(order = "0002", id = "0002_Custom_metamodel", author = "migrationBot") public void run(MongoDatabase db) { diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0003_ShapeDefinition.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0003_ShapeDefinition.java index 0eb865c4445248a13afecab7635cca3532688ad8..e23af882cd03f68f2ecdcd033a3ad8ad2eb94f12 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0003_ShapeDefinition.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0003_ShapeDefinition.java @@ -22,8 +22,8 @@ */ package nl.dtls.fairdatapoint.database.mongo.migration.production; -import com.github.mongobee.changeset.ChangeLog; -import com.github.mongobee.changeset.ChangeSet; +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; import nl.dtls.fairdatapoint.Profiles; diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0004_ResourceDefinition.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0004_ResourceDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..7db10fd43012884846e88be8eaa7755d92393582 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0004_ResourceDefinition.java @@ -0,0 +1,202 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import nl.dtls.fairdatapoint.Profiles; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import org.bson.BasicBSONObject; +import org.bson.Document; +import org.bson.types.BasicBSONList; +import org.springframework.context.annotation.Profile; + +import java.util.List; + +@ChangeLog(order = "0004") +@Profile(Profiles.PRODUCTION) +public class Migration_0004_ResourceDefinition { + + @ChangeSet(order = "0004", id = "Migration_0004_ResourceDefinition", author = "migrationBot") + public void run(MongoDatabase db, ResourceDefinitionCache resourceDefinitionCache) { + migrateResourceDefinitions(db); + resourceDefinitionCache.computeCache(); + } + + private void migrateResourceDefinitions(MongoDatabase db) { + MongoCollection<Document> rdCol = db.getCollection("resourceDefinition"); + rdCol.deleteMany(new Document()); + rdCol.insertOne(repositoryDefinition()); + rdCol.insertOne(catalogDefinition()); + rdCol.insertOne(datasetDefinition()); + rdCol.insertOne(distributionDefinition()); + + MongoCollection<Document> membershipCol = db.getCollection("membership"); + membershipCol.deleteMany(new Document()); + membershipCol.insertOne(membershipOwner()); + membershipCol.insertOne(membershipDataProvider()); + } + + private Document repositoryDefinition() { + Document definition = new Document(); + definition.append("uuid", "77aaad6a-0136-4c6e-88b9-07ffccd0ee4c"); + definition.append("name", "Repository"); + definition.append("urlPrefix", ""); + definition.append("targetClassUris", List.of("http://www.w3.org/ns/dcat#Resource", + "http://www.re3data.org/schema/3-0#Repository")); + + // Child + Document child = new Document(); + child.append("resourceDefinitionUuid", "a0949e72-4466-4d53-8900-9436d1049a4b"); + child.append("relationUri", "http://www.re3data.org/schema/3-0#dataCatalog"); + Document listView = new Document(); + listView.append("title", "Catalogs"); + listView.append("tagsUri", "http://www.w3.org/ns/dcat#themeTaxonomy"); + listView.append("metadata", List.of()); + child.append("listView", listView); + definition.append("children", List.of(child)); + + // External Links + definition.append("externalLinks", List.of()); + + definition.append("_class", "nl.dtls.fairdatapoint.entity.resource.ResourceDefinition"); + return definition; + } + + private Document catalogDefinition() { + Document definition = new Document(); + definition.append("uuid", "a0949e72-4466-4d53-8900-9436d1049a4b"); + definition.append("name", "Catalog"); + definition.append("urlPrefix", "catalog"); + definition.append("targetClassUris", List.of("http://www.w3.org/ns/dcat#Resource", + "http://www.w3.org/ns/dcat#Catalog")); + + // Child + Document child = new Document(); + child.append("resourceDefinitionUuid", "2f08228e-1789-40f8-84cd-28e3288c3604"); + child.append("relationUri", "http://www.w3.org/ns/dcat#dataset"); + Document listView = new Document(); + listView.append("title", "Datasets"); + listView.append("tagsUri", "http://www.w3.org/ns/dcat#theme"); + listView.append("metadata", List.of()); + child.append("listView", listView); + definition.append("children", List.of(child)); + + // External Links + definition.append("externalLinks", List.of()); + + definition.append("_class", "nl.dtls.fairdatapoint.entity.resource.ResourceDefinition"); + return definition; + } + + private Document datasetDefinition() { + Document definition = new Document(); + definition.append("uuid", "2f08228e-1789-40f8-84cd-28e3288c3604"); + definition.append("name", "Dataset"); + definition.append("urlPrefix", "dataset"); + definition.append("targetClassUris", List.of("http://www.w3.org/ns/dcat#Resource", + "http://www.w3.org/ns/dcat#Dataset")); + + // Child + Document child = new Document(); + child.append("resourceDefinitionUuid", "02c649de-c579-43bb-b470-306abdc808c7"); + child.append("relationUri", "http://www.w3.org/ns/dcat#distribution"); + // - list View + Document listView = new Document(); + listView.append("title", "Distributions"); + listView.append("tagsUri", null); + // - metadata + Document metadata = new Document(); + metadata.append("title", "Media Type"); + metadata.append("propertyUri", "http://www.w3.org/ns/dcat#mediaType"); + listView.append("metadata", List.of(metadata)); + child.append("listView", listView); + definition.append("children", List.of(child)); + + // External Links + definition.append("externalLinks", List.of()); + + definition.append("_class", "nl.dtls.fairdatapoint.entity.resource.ResourceDefinition"); + return definition; + } + + private Document distributionDefinition() { + Document definition = new Document(); + definition.append("uuid", "02c649de-c579-43bb-b470-306abdc808c7"); + definition.append("name", "Distribution"); + definition.append("urlPrefix", "distribution"); + definition.append("targetClassUris", List.of("http://www.w3.org/ns/dcat#Resource", + "http://www.w3.org/ns/dcat#Distribution")); + + // Child + definition.append("children", List.of()); + + // External Links + Document accessLink = new Document(); + accessLink.append("title", "Access online"); + accessLink.append("propertyUri", "http://www.w3.org/ns/dcat#accessURL"); + Document downloadLink = new Document(); + downloadLink.append("title", "Download"); + downloadLink.append("propertyUri", "http://www.w3.org/ns/dcat#downloadURL"); + definition.append("externalLinks", List.of(accessLink, downloadLink)); + + definition.append("_class", "nl.dtls.fairdatapoint.entity.resource.ResourceDefinition"); + return definition; + } + + private Document membershipOwner() { + Document user = new Document(); + user.append("uuid", "49f2bcfd-ef0a-4a3a-a1a3-0fc72a6892a8"); + user.append("name", "Owner"); + BasicBSONList permissions = new BasicBSONList(); + permissions.add(new BasicBSONObject().append("mask", 2).append("code", "W")); + permissions.add(new BasicBSONObject().append("mask", 4).append("code", "C")); + permissions.add(new BasicBSONObject().append("mask", 8).append("code", "D")); + permissions.add(new BasicBSONObject().append("mask", 16).append("code", "A")); + user.append("permissions", permissions); + BasicBSONList allowedEntities = new BasicBSONList(); + allowedEntities.add("a0949e72-4466-4d53-8900-9436d1049a4b"); + allowedEntities.add("2f08228e-1789-40f8-84cd-28e3288c3604"); + allowedEntities.add("02c649de-c579-43bb-b470-306abdc808c7"); + user.append("allowedEntities", allowedEntities); + user.append("_class", "nl.dtls.fairdatapoint.entity.membership.Membership"); + return user; + } + + private Document membershipDataProvider() { + Document user = new Document(); + user.append("uuid", "87a2d984-7db2-43f6-805c-6b0040afead5"); + user.append("name", "Data Provider"); + BasicBSONList permissions = new BasicBSONList(); + permissions.add(new BasicBSONObject().append("mask", 4).append("code", "C")); + user.append("permissions", permissions); + BasicBSONList allowedEntities = new BasicBSONList(); + allowedEntities.add("a0949e72-4466-4d53-8900-9436d1049a4b"); + user.append("allowedEntities", allowedEntities); + user.append("_class", "nl.dtls.fairdatapoint.entity.membership.Membership"); + return user; + } + +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0005_UpdateShapeDefinition.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0005_UpdateShapeDefinition.java new file mode 100644 index 0000000000000000000000000000000000000000..16655564b28b629d761f8addc24f7ce6ad98e355 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0005_UpdateShapeDefinition.java @@ -0,0 +1,332 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import nl.dtls.fairdatapoint.Profiles; +import org.bson.Document; +import org.springframework.context.annotation.Profile; + +@ChangeLog(order = "0005") +@Profile(Profiles.PRODUCTION) +public class Migration_0005_UpdateShapeDefinition { + + @ChangeSet(order = "0005", id = "Migration_0005_UpdateShapeDefinition", author = "migrationBot") + public void run(MongoDatabase db) { + addShapeDefinitions(db); + } + + private void addShapeDefinitions(MongoDatabase db) { + MongoCollection<Document> shapeCol = db.getCollection("shape"); + + shapeCol.deleteOne(new Document("uuid", "6a668323-3936-4b53-8380-a4fd2ed082ee")); + shapeCol.deleteOne(new Document("uuid", "a92958ab-a414-47e6-8e17-68ba96ba3a2b")); + shapeCol.deleteOne(new Document("uuid", "2aa7ba63-d27a-4c0e-bfa6-3a4e250f4660")); + shapeCol.deleteOne(new Document("uuid", "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3")); + shapeCol.deleteOne(new Document("uuid", "ebacbf83-cd4f-4113-8738-d73c0735b0ab")); + + shapeCol.insertOne(resourceDefinition()); + shapeCol.insertOne(repositoryDefinition()); + shapeCol.insertOne(catalogDefinition()); + shapeCol.insertOne(datasetDefinition()); + shapeCol.insertOne(distributionDefinition()); + } + + private Document resourceDefinition() { + Document definition = new Document(); + definition.append("uuid", "6a668323-3936-4b53-8380-a4fd2ed082ee"); + definition.append("name", "Resource"); + definition.append("type", "INTERNAL"); + definition.append("definition", "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix foaf: <http://xmlns.com/foaf/0.1/>.\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" + + "\n" + + ":ResourceShape a sh:NodeShape ;\n" + + " sh:targetClass dcat:Resource ;\n" + + " sh:property [\n" + + " sh:path dct:title ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " ], [\n" + + " sh:path dct:description ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextAreaEditor ;\n" + + " ], [\n" + + " sh:path dct:publisher ;\n" + + " sh:node :AgentShape ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:BlankNodeEditor ;\n" + + " ], [\n" + + " sh:path dct:hasVersion ;\n" + + " sh:name \"version\" ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:language ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dct:license ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dct:rights ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n" + + "\n" + + ":AgentShape a sh:NodeShape ;\n" + + " sh:targetClass foaf:Agent ;\n" + + " sh:property [\n" + + " sh:path foaf:name;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " ] ."); + definition.append("_class", "nl.dtls.fairdatapoint.entity.shape.Shape"); + return definition; + } + + + private Document repositoryDefinition() { + Document definition = new Document(); + definition.append("uuid", "a92958ab-a414-47e6-8e17-68ba96ba3a2b"); + definition.append("name", "Repository"); + definition.append("type", "INTERNAL"); + definition.append("definition", "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix r3d: <http://www.re3data.org/schema/3-0#> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n" + + "\n" + + ":RepositoryShape a sh:NodeShape ;\n" + + " sh:targetClass r3d:Repository ;\n" + + " sh:property [\n" + + " sh:path dct:references ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path r3d:institution ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path r3d:startDate ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path r3d:lastUpdate ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path r3d:institutionCountry ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n"); + definition.append("_class", "nl.dtls.fairdatapoint.entity.shape.Shape"); + return definition; + } + + private Document catalogDefinition() { + Document definition = new Document(); + definition.append("uuid", "2aa7ba63-d27a-4c0e-bfa6-3a4e250f4660"); + definition.append("name", "Catalog"); + definition.append("type", "INTERNAL"); + definition.append("definition", "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "\n" + + ":CatalogShape a sh:NodeShape ;\n" + + " sh:targetClass dcat:Catalog ;\n" + + " sh:property [\n" + + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path foaf:homePage ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:themeTaxonomy ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n"); + definition.append("_class", "nl.dtls.fairdatapoint.entity.shape.Shape"); + return definition; + } + + private Document datasetDefinition() { + Document definition = new Document(); + definition.append("uuid", "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3"); + definition.append("name", "Dataset"); + definition.append("type", "INTERNAL"); + definition.append("definition", "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "\n" + + ":DatasetShape a sh:NodeShape ;\n" + + " sh:targetClass dcat:Dataset ;\n" + + " sh:property [\n" + + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:theme ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:minCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:contactPoint ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ], [\n" + + " sh:path dcat:keyword ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:landingPage ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " dash:viewer dash:LabelViewer ;\n" + + " ] .\n"); + definition.append("_class", "nl.dtls.fairdatapoint.entity.shape.Shape"); + return definition; + } + + private Document distributionDefinition() { + Document definition = new Document(); + definition.append("uuid", "ebacbf83-cd4f-4113-8738-d73c0735b0ab"); + definition.append("name", "Distribution"); + definition.append("type", "INTERNAL"); + definition.append("definition", "@prefix : <http://fairdatapoint.org/> .\n" + + "@prefix dash: <http://datashapes.org/dash#> .\n" + + "@prefix dcat: <http://www.w3.org/ns/dcat#> .\n" + + "@prefix dct: <http://purl.org/dc/terms/> .\n" + + "@prefix sh: <http://www.w3.org/ns/shacl#> .\n" + + "\n" + + ":DistributionShape a sh:NodeShape ;\n" + + " sh:targetClass dcat:Distribution ;\n" + + " sh:property [\n" + + " sh:path dct:issued ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dct:modified ;\n" + + " sh:datatype xsd:dateTime ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:DatePickerEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:accessURL ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " ], [\n" + + " sh:path dcat:downloadURL ;\n" + + " sh:nodeKind sh:IRI ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:URIEditor ;\n" + + " ], [\n" + + " sh:path dcat:mediaType ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:minCount 1 ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:format ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ], [\n" + + " sh:path dcat:byteSize ;\n" + + " sh:nodeKind sh:Literal ;\n" + + " sh:maxCount 1 ;\n" + + " dash:editor dash:TextFieldEditor ;\n" + + " dash:viewer dash:LiteralViewer ;\n" + + " ] ."); + definition.append("_class", "nl.dtls.fairdatapoint.entity.shape.Shape"); + return definition; + } + +} \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0006_ShapesSharing.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0006_ShapesSharing.java new file mode 100644 index 0000000000000000000000000000000000000000..45deffc5afb9c5b7304cb7801e3bc459904728db --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0006_ShapesSharing.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import nl.dtls.fairdatapoint.Profiles; +import org.bson.Document; +import org.springframework.context.annotation.Profile; + +@ChangeLog(order = "0006") +@Profile(Profiles.PRODUCTION) +public class Migration_0006_ShapesSharing { + + @ChangeSet(order = "0006", id = "Migration_0006_ShapesSharing", author = "migrationBot") + public void run(MongoDatabase db) { + addShapeDefinitions(db); + } + + private void addShapeDefinitions(MongoDatabase db) { + MongoCollection<Document> shapeCol = db.getCollection("shape"); + shapeCol.updateMany( + Filters.exists("published", false), + Updates.set("published", false) + ); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0007_RemoveMongobee.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0007_RemoveMongobee.java new file mode 100644 index 0000000000000000000000000000000000000000..687bae7c32cbcca456c363247ce855ff752db147 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0007_RemoveMongobee.java @@ -0,0 +1,40 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoDatabase; +import nl.dtls.fairdatapoint.Profiles; +import org.springframework.context.annotation.Profile; + +@ChangeLog(order = "0007") +@Profile(Profiles.PRODUCTION) +public class Migration_0007_RemoveMongobee { + + @ChangeSet(order = "0007", id = "Migration_0007_RemoveMongobee", author = "migrationBot") + public void run(MongoDatabase db) { + db.getCollection("dbchangelog").drop(); + db.getCollection("mongobeelock").drop(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0008_ShapesInternalChange.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0008_ShapesInternalChange.java new file mode 100644 index 0000000000000000000000000000000000000000..d0bb2f0832669ea7cd33f0ca42bf595d7b38528b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0008_ShapesInternalChange.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import nl.dtls.fairdatapoint.Profiles; +import org.bson.Document; +import org.springframework.context.annotation.Profile; + +@ChangeLog(order = "0008") +@Profile(Profiles.PRODUCTION) +public class Migration_0008_ShapesInternalChange { + + @ChangeSet(order = "0008", id = "Migration_0008_ShapesInternalChange", author = "migrationBot") + public void run(MongoDatabase db) { + updateInternalShapesType(db); + } + + private void updateInternalShapesType(MongoDatabase db) { + MongoCollection<Document> shapeCol = db.getCollection("shape"); + // DATASET + shapeCol.updateOne( + Filters.eq("uuid", "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3"), + Updates.set("type", "CUSTOM") + ); + // DISTRIBUTION + shapeCol.updateOne( + Filters.eq("uuid", "ebacbf83-cd4f-4113-8738-d73c0735b0ab"), + Updates.set("type", "CUSTOM") + ); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0009_ShapeTargetClasses.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0009_ShapeTargetClasses.java new file mode 100644 index 0000000000000000000000000000000000000000..847ee523b26baaa035e4326f54a426aa84a93893 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/migration/production/Migration_0009_ShapeTargetClasses.java @@ -0,0 +1,87 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.migration.production; + +import com.github.cloudyrock.mongock.ChangeLog; +import com.github.cloudyrock.mongock.ChangeSet; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; +import nl.dtls.fairdatapoint.Profiles; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionTargetClassesCache; +import nl.dtls.fairdatapoint.service.shape.ShapeShaclUtils; +import org.bson.Document; +import org.springframework.context.annotation.Profile; + +import java.util.*; + +@ChangeLog(order = "0009") +@Profile(Profiles.PRODUCTION) +public class Migration_0009_ShapeTargetClasses { + + @ChangeSet(order = "0009", id = "Migration_0009_ShapeTargetClasses", author = "migrationBot") + public void run(MongoDatabase db, ResourceDefinitionCache resourceDefinitionCache, ResourceDefinitionTargetClassesCache targetClassesCache) { + updateShapesAndResources(db); + resourceDefinitionCache.computeCache(); + targetClassesCache.computeCache(); + } + + private void updateShapesAndResources(MongoDatabase db) { + Map<String, Set<String>> targetClassesMap = new HashMap<>(); + // Update shapes + MongoCollection<Document> shapeCol = db.getCollection("shape"); + for (Document document : shapeCol.find()) { + String definition = (String) document.get("definition"); + String uuid = (String) document.get("uuid"); + Set<String> targetClasses = ShapeShaclUtils.extractTargetClasses(definition); + targetClassesMap.put(uuid, targetClasses); + shapeCol.updateOne( + Filters.eq("uuid", uuid), + Updates.set("targetClasses", targetClasses) + ); + } + // Update resource definitions + MongoCollection<Document> rdCol = db.getCollection("resourceDefinition"); + for (Document document : rdCol.find()) { + List<String> targetClassUris = (List<String>) document.get("targetClassUris"); + Set<String> shapeUuids = new HashSet<>(); + targetClassUris.forEach(uri -> { + targetClassesMap.forEach((shapeUuid, targetClasses) -> { + if (targetClasses.contains(uri)) { + shapeUuids.add(shapeUuid); + } + }); + }); + rdCol.updateOne( + Filters.eq("uuid", document.get("uuid")), + Updates.unset("targetClassUris") + ); + rdCol.updateOne( + Filters.eq("uuid", document.get("uuid")), + Updates.set("shapeUuids", shapeUuids) + ); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ApiKeyRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ApiKeyRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..eef8275d64aae704408258a6b56b3c8dbc3b9859 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ApiKeyRepository.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.apikey.ApiKey; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.List; +import java.util.Optional; + +public interface ApiKeyRepository extends MongoRepository<ApiKey, String> { + + List<ApiKey> findByUserUuid(String userUuid); + + Optional<ApiKey> findByUuid(String uuid); + + Optional<ApiKey> findByToken(String token); + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/EventRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/EventRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..4d3b807a4a8a06d58c63bbb7d0f75884d0cb630b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/EventRepository.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.EventType; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.time.Instant; +import java.util.List; + +public interface EventRepository extends MongoRepository<Event, String> { + + List<Event> getAllByType(EventType type); + + List<Event> getAllByFinishedIsNull(); + + Page<Event> getAllByRelatedTo(IndexEntry indexEntry, Pageable pageable); + + List<Event> findAllByIncomingPingExchangeRemoteAddrAndCreatedAfter(String remoteAddr, Instant after); +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexEntryRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexEntryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..3866e4ab0b0b38651653411ebc63176cfbe83a1c --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexEntryRepository.java @@ -0,0 +1,54 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.time.Instant; +import java.util.Optional; + +public interface IndexEntryRepository extends MongoRepository<IndexEntry, String> { + + Optional<IndexEntry> findByUuid(String uuid); + + Optional<IndexEntry> findByClientUrl(String clientUrl); + + Page<IndexEntry> findAllByStateEquals(Pageable pageable, IndexEntryState state); + + Page<IndexEntry> findAllByStateEqualsAndLastRetrievalTimeBefore(Pageable pageable, IndexEntryState state, + Instant when); + + Page<IndexEntry> findAllByStateEqualsAndLastRetrievalTimeAfter(Pageable pageable, IndexEntryState state, + Instant when); + + long countAllByStateEquals(IndexEntryState state); + + long countAllByStateEqualsAndLastRetrievalTimeAfter(IndexEntryState state, Instant when); + + long countAllByStateEqualsAndLastRetrievalTimeBefore(IndexEntryState state, Instant when); + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexSettingsRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexSettingsRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..01b672fb374b8b8e981f70a35dda1dd51297afaf --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/IndexSettingsRepository.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.stereotype.Component; + +import java.util.Optional; + +public interface IndexSettingsRepository extends MongoRepository<IndexSettings, String> { + Optional<IndexSettings> findFirstBy(); +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/MetadataRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/MetadataRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..effc67963b4b8a4722adf06fc2c8ab49f47bf840 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/MetadataRepository.java @@ -0,0 +1,37 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.List; +import java.util.Optional; + +public interface MetadataRepository extends MongoRepository<Metadata, String> { + + Optional<Metadata> findByUri(String uri); + + List<Metadata> findByUriIn(List<String> uris); + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ResourceDefinitionRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ResourceDefinitionRepository.java index b003fbca0bbc987e9600b78e6c78f87bbb2dac57..3336cf1a35dd8c588b348b05ce0435ec2180d584 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ResourceDefinitionRepository.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ResourceDefinitionRepository.java @@ -25,6 +25,7 @@ package nl.dtls.fairdatapoint.database.mongo.repository; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import org.springframework.data.mongodb.repository.MongoRepository; +import java.util.List; import java.util.Optional; public interface ResourceDefinitionRepository extends MongoRepository<ResourceDefinition, String> { @@ -33,6 +34,8 @@ public interface ResourceDefinitionRepository extends MongoRepository<ResourceDe Optional<ResourceDefinition> findByName(String name); - Optional<ResourceDefinition> findByUriPrefix(String uriPrefix); + Optional<ResourceDefinition> findByUrlPrefix(String urlPrefix); + + List<ResourceDefinition> findByShapeUuidsIsContaining(String shapeUuid); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/SettingsRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/SettingsRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..b0bbb6576f5556585150b34499173fcadf73b888 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/SettingsRepository.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.settings.Settings; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.Optional; + +public interface SettingsRepository extends MongoRepository<Settings, String> { + Optional<Settings> findFirstBy(); +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ShapeRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ShapeRepository.java index ad4bb006dcc7709dec9f1d50493bb883e0fd1f40..3bf428f92d7e66fd1ca745041bfb8e170b23cb7c 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ShapeRepository.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/ShapeRepository.java @@ -25,10 +25,13 @@ package nl.dtls.fairdatapoint.database.mongo.repository; import nl.dtls.fairdatapoint.entity.shape.Shape; import org.springframework.data.mongodb.repository.MongoRepository; +import java.util.List; import java.util.Optional; public interface ShapeRepository extends MongoRepository<Shape, String> { Optional<Shape> findByUuid(String uuid); + List<Shape> findAllByPublishedIsTrue(); + } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/WebhookRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/WebhookRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..c8331374ac98a1fe5df5985d9fbe812955651300 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/mongo/repository/WebhookRepository.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.mongo.repository; + +import nl.dtls.fairdatapoint.entity.index.webhook.Webhook; +import org.springframework.data.mongodb.repository.MongoRepository; + +import java.util.Optional; +import java.util.UUID; + +public interface WebhookRepository extends MongoRepository<Webhook, String> { + Optional<Webhook> findByUuid(UUID uuid); +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/RdfDevelopmentMigrationRunner.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/RdfDevelopmentMigrationRunner.java index 86b35da7d6fb185e976935e97767c89694d5f156..f168e4476dc93f8c4d3e9adf2bacce172463260a 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/RdfDevelopmentMigrationRunner.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/RdfDevelopmentMigrationRunner.java @@ -23,7 +23,7 @@ package nl.dtls.fairdatapoint.database.rdf.migration.development; import nl.dtls.fairdatapoint.Profiles; -import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.MetadataMigration; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.RdfMetadataMigration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Profile; @@ -32,16 +32,16 @@ import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; @Service -@DependsOn("mongobee") +@DependsOn("mongockRunner") @Profile(Profiles.NON_PRODUCTION) public class RdfDevelopmentMigrationRunner { @Autowired - private MetadataMigration metadataMigration; + private RdfMetadataMigration rdfMetadataMigration; @PostConstruct public void run() { - metadataMigration.runMigration(); + rdfMetadataMigration.runMigration(); } } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/MetadataMigration.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/RdfMetadataMigration.java old mode 100755 new mode 100644 similarity index 69% rename from src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/MetadataMigration.java rename to src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/RdfMetadataMigration.java index fe3f5f294683314e29550feac451e4928433b000..8b9befe40699c25eaae8fa9fdeceeb4e4acc0a74 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/MetadataMigration.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/RdfMetadataMigration.java @@ -22,13 +22,18 @@ */ package nl.dtls.fairdatapoint.database.rdf.migration.development.metadata; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; import nl.dtls.fairdatapoint.database.common.migration.Migration; import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; -import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.data.RdfMetadataFixtures; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; import nl.dtls.fairdatapoint.service.security.MongoAuthenticationService; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; @@ -42,10 +47,13 @@ import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; @Service -public class MetadataMigration implements Migration { +public class RdfMetadataMigration implements Migration { @Autowired - protected MetadataFixtures metadataFixtures; + private GenericMetadataRepository metadataRepository; + + @Autowired + protected RdfMetadataFixtures rdfMetadataFixtures; @Autowired @Qualifier("catalogMetadataService") @@ -64,20 +72,26 @@ public class MetadataMigration implements Migration { @Autowired private MongoAuthenticationService mongoAuthenticationService; + @Autowired + private MetadataStateService metadataStateService; + @Autowired @Qualifier("persistentUrl") private String persistentUrl; public void runMigration() { try { - // 1. Auth user - String albertUuid = userFixtures.albert().getUuid(); - Authentication auth = mongoAuthenticationService.getAuthentication(albertUuid); + // 1. Remove all previous metadata + metadataRepository.removeAll(); + + // 2. Auth user + String adminUuid = userFixtures.admin().getUuid(); + Authentication auth = mongoAuthenticationService.getAuthentication(adminUuid); SecurityContextHolder.getContext().setAuthentication(auth); - // 2. Load metadata fixtures + // 3. Load metadata fixtures importDefaultFixtures(persistentUrl); - } catch (MetadataServiceException e) { + } catch (MetadataServiceException | MetadataRepositoryException e) { e.printStackTrace(); } } @@ -88,31 +102,35 @@ public class MetadataMigration implements Migration { ResourceDefinition datasetRd = resourceDefinitionFixtures.datasetDefinition(); ResourceDefinition distributionRd = resourceDefinitionFixtures.distributionDefinition(); - Model repositoryM = metadataFixtures.repositoryMetadata(repositoryUrl); + Model repositoryM = rdfMetadataFixtures.repositoryMetadata(repositoryUrl); IRI repositoryUri = getUri(repositoryM); genericMetadataService.store(repositoryM, i(repositoryUrl), repositoryRd); + metadataStateService.modifyState(repositoryUri, new MetaStateChangeDTO(MetadataState.PUBLISHED)); - Model catalog1 = metadataFixtures.catalog1(repositoryUrl, i(repositoryUrl)); + Model catalog1 = rdfMetadataFixtures.catalog1(repositoryUrl, i(repositoryUrl)); IRI catalog1Uri = getUri(catalog1); catalogMetadataService.store(catalog1, catalog1Uri, catalogRd); + metadataStateService.modifyState(catalog1Uri, new MetaStateChangeDTO(MetadataState.PUBLISHED)); - Model catalog2 = metadataFixtures.catalog2(repositoryUrl, repositoryUri); + Model catalog2 = rdfMetadataFixtures.catalog2(repositoryUrl, repositoryUri); IRI catalog2Uri = getUri(catalog2); catalogMetadataService.store(catalog2, catalog2Uri, catalogRd); - Model dataset1 = metadataFixtures.dataset1(repositoryUrl, catalog1Uri); + Model dataset1 = rdfMetadataFixtures.dataset1(repositoryUrl, catalog1Uri); IRI dataset1Uri = getUri(dataset1); genericMetadataService.store(dataset1, dataset1Uri, datasetRd); + metadataStateService.modifyState(dataset1Uri, new MetaStateChangeDTO(MetadataState.PUBLISHED)); - Model dataset2 = metadataFixtures.dataset2(repositoryUrl, catalog1Uri); + Model dataset2 = rdfMetadataFixtures.dataset2(repositoryUrl, catalog1Uri); IRI dataset2Uri = getUri(dataset2); genericMetadataService.store(dataset2, dataset2Uri, datasetRd); - Model distribution1 = metadataFixtures.distribution1(repositoryUrl, dataset1Uri); + Model distribution1 = rdfMetadataFixtures.distribution1(repositoryUrl, dataset1Uri); IRI distribution1Uri = getUri(distribution1); genericMetadataService.store(distribution1, distribution1Uri, distributionRd); + metadataStateService.modifyState(distribution1Uri, new MetaStateChangeDTO(MetadataState.PUBLISHED)); - Model distribution2 = metadataFixtures.distribution2(repositoryUrl, dataset1Uri); + Model distribution2 = rdfMetadataFixtures.distribution2(repositoryUrl, dataset1Uri); IRI distribution2Uri = getUri(distribution2); genericMetadataService.store(distribution2, distribution2Uri, distributionRd); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/MetadataFixtures.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/RdfMetadataFixtures.java old mode 100755 new mode 100644 similarity index 90% rename from src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/MetadataFixtures.java rename to src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/RdfMetadataFixtures.java index b238aaac0c5ad19544f0faeb808b2d96ac467768..d842acaeccd9d0c2813fefb22052ce39583cd480 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/MetadataFixtures.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/data/RdfMetadataFixtures.java @@ -31,16 +31,27 @@ import org.springframework.stereotype.Service; import java.util.Arrays; @Service -public class MetadataFixtures { +public class RdfMetadataFixtures { - @Autowired protected MetadataFactory metadataFactory; + @Autowired + public RdfMetadataFixtures(MetadataFactory metadataFactory) { + this.metadataFactory = metadataFactory; + } + public Model repositoryMetadata(String repositoryUrl) { return metadataFactory.createFDPMetadata( - "EOSC-Pillar FAIR Data Point", - "FAIRDataPoint is a REST API and Web Client for creating, storing, and serving FAIR metadata." + - "Here you can store catalogs, datasets, and distributions.", + "My FAIR Data Point", + "Duis pellentesque, nunc a fringilla varius, magna dui porta quam, nec ultricies augue turpis sed " + + "velit. Donec id consectetur ligula. Suspendisse pharetra egestas massa, vel varius leo " + + "viverra at. Donec scelerisque id ipsum id semper. Maecenas facilisis augue vel justo " + + "molestie aliquet. Maecenas sed mattis lacus, sed viverra risus. Donec iaculis quis lacus " + + "vitae scelerisque. Nullam fermentum lectus nisi, id vulputate nisi congue nec. Morbi " + + "fermentum justo at justo bibendum, at tempus ipsum tempor. Donec facilisis nibh sed lectus " + + "blandit venenatis. Cras ullamcorper, justo vitae feugiat commodo, orci metus suscipit purus," + + " quis sagittis turpis ante eget ex. Pellentesque malesuada a metus eu pulvinar. Morbi rutrum" + + " euismod eros at varius. Duis finibus dapibus ex, a hendrerit mauris efficitur at.", repositoryUrl ); } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/factory/MetadataFactoryImpl.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/factory/MetadataFactoryImpl.java index 6bc103abce468f0d958f611d588eaf74ab26173d..30e4885bbe5764f25e66e740aabb2b8395a24739 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/factory/MetadataFactoryImpl.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/development/metadata/factory/MetadataFactoryImpl.java @@ -22,10 +22,12 @@ */ package nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.factory; +import nl.dtls.fairdatapoint.entity.metadata.Agent; import nl.dtls.fairdatapoint.util.ValueFactoryHelper; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.vocabulary.FOAF; import org.springframework.stereotype.Service; import java.util.List; @@ -89,6 +91,11 @@ public class MetadataFactoryImpl implements MetadataFactory { setTitle(metadata, uri, l(title)); setDescription(metadata, uri, l(description)); setVersion(metadata, uri, l(1.0f)); + setPublisher(metadata, uri, new Agent( + i("http://example.com/publisher"), + i("http://example.com/publisher/mbox"), + i(FOAF.AGENT), + l("Publisher"))); if (parent != null) { setParent(metadata, uri, parent); diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0001_Init.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0001_Init.java index 7208aeec9f2c55f2e313835222921fd52bff5c5f..b463aaa283d32a3c8f29529258d69cd00ea12705 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0001_Init.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0001_Init.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.database.rdf.migration.production; import com.mongodb.client.MongoCollection; import lombok.extern.slf4j.Slf4j; -import nl.dtls.fairdatapoint.entity.metadata.Agent; +import nl.dtls.fairdatapoint.service.reset.FactoryDefaults; import nl.dtls.fairdatapoint.vocabulary.DATACITE; import nl.dtls.fairdatapoint.vocabulary.FDP; import nl.dtls.fairdatapoint.vocabulary.R3D; @@ -50,7 +50,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -82,13 +82,6 @@ public class Rdf_Migration_0001_Init implements RdfProductionMigration { @Autowired private IRI language; - @Autowired - private Agent publisher; - - @Autowired - @Qualifier("metadataMetrics") - private Map<String, String> metadataMetrics; - @Autowired private MongoTemplate mongoTemplate; @@ -99,39 +92,12 @@ public class Rdf_Migration_0001_Init implements RdfProductionMigration { private void createRepositoryInTripleStore() { try (RepositoryConnection conn = repository.getConnection()) { - List<Statement> s = new ArrayList<>(); - add(s, RDF.TYPE, R3D.REPOSITORY); - add(s, DCTERMS.TITLE, l("EOSC-Pillar FAIR Data Point")); - add(s, RDFS.LABEL, l("EOSC-Pillar FAIR Data Point")); - add(s, DCTERMS.HAS_VERSION, l(1.0f)); - add(s, FDP.METADATAISSUED, l(LocalDateTime.now())); - add(s, FDP.METADATAMODIFIED, l(LocalDateTime.now())); - add(s, DCTERMS.LICENSE, license); - add(s, DCTERMS.DESCRIPTION, l("FAIRDataPoint is a REST API and Web Client for creating, storing, and serving FAIR metadata." + - "Here you can store catalogs, datasets, and distributions." )); - add(s, DCTERMS.CONFORMS_TO, i("https://www.purl.org/fairtools/fdp/schema/0.1/fdpMetadata")); - add(s, DCTERMS.LANGUAGE, language); - // Identifier - IRI identifierIri = i(persistentUrl + "/#identifier"); - add(s, DATACITE.HASIDENTIFIER, identifierIri); - add(s, identifierIri, RDF.TYPE, DATACITE.IDENTIFIER); - add(s, identifierIri, DCTERMS.IDENTIFIER, l(persistentUrl)); - // Access Rights - IRI arIri = i(persistentUrl + "/#accessRights"); - add(s, DCTERMS.ACCESS_RIGHTS, arIri); - add(s, arIri, RDF.TYPE, DCTERMS.RIGHTS_STATEMENT); - add(s, arIri, DCTERMS.DESCRIPTION, l(accessRightsDescription)); - // Publisher - add(s, DCTERMS.PUBLISHER, publisher.getUri()); - add(s, publisher.getUri(), RDF.TYPE, publisher.getType()); - add(s, publisher.getUri(), FOAF.NAME, publisher.getName()); - // Metrics - metadataMetrics.forEach((metric, metricValue) -> { - IRI metUri = i(format("%s/metrics/%s", persistentUrl, DigestUtils.md5Hex(metric))); - add(s, Sio.REFERS_TO, metUri); - add(s, metUri, Sio.IS_ABOUT, i(metric)); - add(s, metUri, Sio.REFERS_TO, i(metricValue)); - }); + List<Statement> s = FactoryDefaults.repositoryStatements( + persistentUrl, + license, + language, + accessRightsDescription + ); conn.add(s); } catch (RepositoryException e) { log.error(e.getMessage(), e); @@ -144,53 +110,7 @@ public class Rdf_Migration_0001_Init implements RdfProductionMigration { } private Document repositoryPermission() { - String albertUuid = "7e64818d-6276-46fb-8bb1-732e6e09f7e9"; - BasicBSONObject owner = new BasicBSONObject().append("name", albertUuid).append("isPrincipal", true); - Document acl = new Document(); - acl.append("className", "nl.dtls.fairdatapoint.entity.metadata.FDPMetadata"); - acl.append("instanceId", persistentUrl); - acl.append("owner", owner); - acl.append("inheritPermissions", true); - BasicBSONList permissions = new BasicBSONList(); - permissions.add( - new Document() - .append("sid", owner) - .append("permission", 2) - .append("granting", true) - .append("auditFailure", false) - .append("auditSuccess", false)); - permissions.add( - new Document() - .append("sid", owner) - .append("permission", 4) - .append("granting", true) - .append("auditFailure", false) - .append("auditSuccess", false)); - permissions.add( - new Document() - .append("sid", owner) - .append("permission", 8) - .append("granting", true) - .append("auditFailure", false) - .append("auditSuccess", false)); - permissions.add( - new Document() - .append("sid", owner) - .append("permission", 16) - .append("granting", true) - .append("auditFailure", false) - .append("auditSuccess", false)); - acl.append("permissions", permissions); - acl.append("_class", "org.springframework.security.acls.domain.MongoAcl"); - return acl; - } - - private void add(List<Statement> statements, IRI predicate, org.eclipse.rdf4j.model.Value object) { - statements.add(s(i(persistentUrl), predicate, object, i(persistentUrl))); - } - - private void add(List<Statement> statements, IRI subject, IRI predicate, org.eclipse.rdf4j.model.Value object) { - statements.add(s(subject, predicate, object, i(persistentUrl))); + return FactoryDefaults.aclRepository(persistentUrl); } } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0002_Metadata_Draft.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0002_Metadata_Draft.java new file mode 100644 index 0000000000000000000000000000000000000000..97aac5a81ae16ad7c0820c406ea35ef903778555 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/migration/production/Rdf_Migration_0002_Metadata_Draft.java @@ -0,0 +1,67 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.database.rdf.migration.production; + +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import nl.dtls.rdf.migration.entity.RdfMigrationAnnotation; +import nl.dtls.rdf.migration.runner.RdfProductionMigration; +import org.eclipse.rdf4j.common.iteration.Iterations; +import org.eclipse.rdf4j.repository.Repository; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.RepositoryException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@RdfMigrationAnnotation( + number = 2, + name = "Metadata Draft", + description = "Support metadata in DRAFT state") +@Slf4j +@Service +public class Rdf_Migration_0002_Metadata_Draft implements RdfProductionMigration { + + @Autowired + protected Repository repository; + + @Autowired + private MetadataRepository metadataRepository; + + public void runMigration() { + createRepositoryInTripleStore(); + } + + private void createRepositoryInTripleStore() { + try (RepositoryConnection conn = repository.getConnection()) { + Iterations.asList(conn.getContextIDs()) + .forEach(iri -> + metadataRepository.save(new Metadata(null, iri.stringValue(), MetadataState.PUBLISHED)) + ); + } catch (RepositoryException e) { + log.error(e.getMessage(), e); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/AbstractMetadataRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/AbstractMetadataRepository.java index 41d06a167786b830de8709d60aaaed43f3977081..e5fad355f8bd8dce3efa36005bd96a7d8744abbb 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/AbstractMetadataRepository.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/AbstractMetadataRepository.java @@ -23,86 +23,131 @@ package nl.dtls.fairdatapoint.database.rdf.repository.common; import com.google.common.base.Charsets; -import com.google.common.base.Preconditions; import com.google.common.io.Resources; import lombok.extern.slf4j.Slf4j; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.entity.search.SearchResult; +import nl.dtls.fairdatapoint.entity.search.SearchResultRelation; import org.eclipse.rdf4j.common.iteration.Iterations; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.query.BindingSet; import org.eclipse.rdf4j.query.QueryResults; import org.eclipse.rdf4j.query.TupleQuery; import org.eclipse.rdf4j.repository.Repository; import org.eclipse.rdf4j.repository.RepositoryConnection; import org.eclipse.rdf4j.repository.RepositoryException; -import org.eclipse.rdf4j.repository.RepositoryResult; import org.springframework.beans.factory.annotation.Autowired; -import javax.annotation.Nonnull; import java.io.IOException; import java.net.URL; +import java.util.HashMap; import java.util.List; import java.util.Map; import static java.lang.String.format; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; @Slf4j public abstract class AbstractMetadataRepository { + private static final String FIND_ENTITY_BY_LITERAL = "findEntityByLiteral.sparql"; + private static final String FIND_CHILD_TITLES = "findChildTitles.sparql"; + @Autowired protected Repository repository; - public List<Statement> retrieveResource(@Nonnull IRI uri) throws MetadataRepositoryException { - Preconditions.checkNotNull(uri, "URI must not be null."); - log.info("Get statements for the URI {}", uri.toString()); + public List<Resource> findResources() throws MetadataRepositoryException { + try (RepositoryConnection conn = repository.getConnection()) { + + return Iterations.asList( + conn.getContextIDs() + ); + } catch (RepositoryException e) { + throw new MetadataRepositoryException("Error retrieve resource :" + e.getMessage()); + } + } + public List<Statement> find(IRI context) throws MetadataRepositoryException { try (RepositoryConnection conn = repository.getConnection()) { - log.info("Connexion to repository hé", conn); - RepositoryResult<Statement> queryResult = conn.getStatements(null, null, null, uri); - log.info("Query result 2", queryResult); - return Iterations.asList(queryResult); + return Iterations.asList( + conn.getStatements(null, null, null, context) + ); } catch (RepositoryException e) { throw new MetadataRepositoryException("Error retrieve resource :" + e.getMessage()); } } - public boolean isStatementExist(Resource rsrc, IRI pred, Value value) throws MetadataRepositoryException { + public List<SearchResult> findByLiteral(Literal query) throws MetadataRepositoryException { + return runSparqlQuery(FIND_ENTITY_BY_LITERAL, AbstractMetadataRepository.class, Map.of( + "query", query)) + .stream() + .map(s -> new SearchResult( + s.getValue("entity").stringValue(), + s.getValue("rdfType").stringValue(), + s.getValue("title").stringValue(), + ofNullable(s.getValue("description")).map(Value::stringValue).orElse(""), + new SearchResultRelation( + s.getValue("relationPredicate").stringValue(), + s.getValue("relationObject").stringValue()) + ) + ) + .collect(toList()); + } + + public Map<String, String> findChildTitles(IRI parent, IRI relation) throws MetadataRepositoryException { + Map<String, String> titles = new HashMap<>(); + + var results = runSparqlQuery(FIND_CHILD_TITLES, AbstractMetadataRepository.class, Map.of( + "parent", parent, + "relation", relation + )); + + for (var result : results) { + var childUri = result.getValue("child").stringValue(); + var title = result.getValue("title").stringValue(); + titles.put(childUri, title); + } + + return titles; + } + + public boolean checkExistence(Resource subject, IRI predicate, Value object) throws MetadataRepositoryException { try (RepositoryConnection conn = repository.getConnection()) { - log.info("Check if statements exists"); - return conn.hasStatement(rsrc, pred, value, false); + return conn.hasStatement(subject, predicate, object, false); } catch (RepositoryException e) { throw new MetadataRepositoryException("Error check statement existence :" + e.getMessage()); } } - public void storeStatements(List<Statement> statements, IRI... cntx) throws MetadataRepositoryException { + public void save(List<Statement> statements, IRI context) throws MetadataRepositoryException { try (RepositoryConnection conn = repository.getConnection()) { - if (cntx != null) { - conn.add(statements, cntx); - } else { - conn.add(statements); - } - + conn.add(statements, context); } catch (RepositoryException e) { throw new MetadataRepositoryException("Error storing statements :" + e.getMessage()); } } - public void removeStatement(Resource rsrc, IRI pred, Value value, IRI... contexts) throws MetadataRepositoryException { + public void removeAll() throws MetadataRepositoryException { try (RepositoryConnection conn = repository.getConnection()) { - conn.remove(rsrc, pred, value, contexts); + conn.clear(); } catch (RepositoryException e) { - throw (new MetadataRepositoryException("Error removing statement")); + throw new MetadataRepositoryException("Error remove all :" + e.getMessage()); } } - public void removeResource(IRI uri) throws MetadataRepositoryException { + public void remove(IRI uri) throws MetadataRepositoryException { removeStatement(null, null, null, uri); } + public void removeStatement(Resource subject, IRI predicate, Value object, IRI context) throws MetadataRepositoryException { + try (RepositoryConnection conn = repository.getConnection()) { + conn.remove(subject, predicate, object, context); + } catch (RepositoryException e) { + throw (new MetadataRepositoryException("Error removing statement")); + } + } + public List<BindingSet> runSparqlQuery(String queryName, Class repositoryType, Map<String, Value> bindings) throws MetadataRepositoryException { try (RepositoryConnection conn = repository.getConnection()) { String queryString = loadSparqlQuery(queryName, repositoryType); @@ -121,6 +166,4 @@ public abstract class AbstractMetadataRepository { URL fileURL = repositoryType.getResource(queryName); return Resources.toString(fileURL, Charsets.UTF_8); } - - } diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepository.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepository.java index 52dc525ae1c05c3b5a30812f8d20b9a20d4911a6..691a48e0e19b621f24da674930fe1f1a59389f46 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepository.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepository.java @@ -28,10 +28,8 @@ package nl.dtls.fairdatapoint.database.rdf.repository.common; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Value; +import nl.dtls.fairdatapoint.entity.search.SearchResult; +import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.query.BindingSet; import java.util.List; @@ -39,15 +37,23 @@ import java.util.Map; public interface MetadataRepository { - List<Statement> retrieveResource(IRI uri) throws MetadataRepositoryException; + List<Resource> findResources() throws MetadataRepositoryException; - void storeStatements(List<Statement> statements, IRI... iri) throws MetadataRepositoryException; + List<Statement> find(IRI context) throws MetadataRepositoryException; - void removeStatement(Resource rsrc, IRI uri, Value value, IRI... contexts) throws MetadataRepositoryException; + List<SearchResult> findByLiteral(Literal query) throws MetadataRepositoryException; - boolean isStatementExist(Resource rsrc, IRI pred, Value value) throws MetadataRepositoryException; + Map<String, String> findChildTitles(IRI parent, IRI relation) throws MetadataRepositoryException; - void removeResource(IRI uri) throws MetadataRepositoryException; + boolean checkExistence(Resource subject, IRI predicate, Value object) throws MetadataRepositoryException; + + void save(List<Statement> statements, IRI context) throws MetadataRepositoryException; + + void removeAll() throws MetadataRepositoryException; + + void remove(IRI uri) throws MetadataRepositoryException; + + void removeStatement(Resource subject, IRI predicate, Value object, IRI context) throws MetadataRepositoryException; List<BindingSet> runSparqlQuery(String queryName, Class repositoryType, Map<String, Value> bindings) throws MetadataRepositoryException; diff --git a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryImpl.java b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryImpl.java index 5b754625fa4df3d5d1975c875f88e98b74ef31ef..ab343bcb09af0743284d0ce960a41e559243391c 100755 --- a/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryImpl.java +++ b/src/main/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryImpl.java @@ -29,18 +29,16 @@ package nl.dtls.fairdatapoint.database.rdf.repository.generic; import nl.dtls.fairdatapoint.database.rdf.repository.common.AbstractMetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.*; +import org.eclipse.rdf4j.model.impl.LinkedHashModel; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.cache.Cache; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.stereotype.Service; import java.util.List; import static nl.dtls.fairdatapoint.config.CacheConfig.CATALOG_THEMES_CACHE; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getParent; @Service("genericMetadataRepository") public class GenericMetadataRepositoryImpl extends AbstractMetadataRepository implements GenericMetadataRepository { @@ -49,29 +47,30 @@ public class GenericMetadataRepositoryImpl extends AbstractMetadataRepository im private ConcurrentMapCacheManager cacheManager; @Override - public void storeStatements(List<Statement> statements, IRI... cntx) throws MetadataRepositoryException { - super.storeStatements(statements, cntx); - for (IRI uri : cntx) { - cache().evict(uri.toString()); - } + public void save(List<Statement> statements, IRI context) throws MetadataRepositoryException { + super.save(statements, context); + clearCatalogCache(context); } @Override - public void removeStatement(Resource rsrc, IRI pred, Value value, IRI... contexts) throws MetadataRepositoryException { - super.removeStatement(rsrc, pred, value, contexts); - if (pred != null) { - cache().evict(pred.toString()); - } + public void remove(IRI uri) throws MetadataRepositoryException { + clearCatalogCache(uri); + super.remove(uri); } @Override - public void removeResource(IRI uri) throws MetadataRepositoryException { - super.removeResource(uri); - cache().evict(uri.toString()); + public void removeStatement(Resource subject, IRI predicate, Value object, IRI context) throws MetadataRepositoryException { + clearCatalogCache(context); + super.removeStatement(subject, predicate, object, context); } - private Cache cache() { - return cacheManager.getCache(CATALOG_THEMES_CACHE); + private void clearCatalogCache(IRI uri) throws MetadataRepositoryException { + Model metadata = new LinkedHashModel(); + metadata.addAll(find(uri)); + IRI parent = getParent(metadata); + if (parent != null) { + cacheManager.getCache(CATALOG_THEMES_CACHE).evict(parent.stringValue()); + } } } diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/apikey/ApiKey.java b/src/main/java/nl/dtls/fairdatapoint/entity/apikey/ApiKey.java new file mode 100644 index 0000000000000000000000000000000000000000..58285ca222a7796de46291379c1060bd010da323 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/apikey/ApiKey.java @@ -0,0 +1,47 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.apikey; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Builder(toBuilder = true) +public class ApiKey { + + @Id + protected ObjectId id; + + private String uuid; + + private String userUuid; + + private String token; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/exception/FeatureDisabledException.java b/src/main/java/nl/dtls/fairdatapoint/entity/exception/FeatureDisabledException.java new file mode 100644 index 0000000000000000000000000000000000000000..e8e678965ee7b04f9971f0f3a66b4d4244ccf75a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/exception/FeatureDisabledException.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(value = HttpStatus.BAD_REQUEST) +public class FeatureDisabledException extends RuntimeException { + + public FeatureDisabledException(String message) { + super(message); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/exception/RdfValidationException.java b/src/main/java/nl/dtls/fairdatapoint/entity/exception/RdfValidationException.java index 46283e20097990afa87ff507da0da6fee2438fca..82d2b4037732d8c743e762e17ac6fc569d75c7ab 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/exception/RdfValidationException.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/exception/RdfValidationException.java @@ -33,6 +33,6 @@ import org.springframework.web.bind.annotation.ResponseStatus; @AllArgsConstructor public class RdfValidationException extends RuntimeException { - private Model model; + private final Model model; } diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/exception/ShapeImportException.java b/src/main/java/nl/dtls/fairdatapoint/entity/exception/ShapeImportException.java new file mode 100644 index 0000000000000000000000000000000000000000..2f70b560e697f8adcd18c047436887e1ac66f6c5 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/exception/ShapeImportException.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.exception; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(value = HttpStatus.BAD_REQUEST) +@Getter +@AllArgsConstructor +public class ShapeImportException extends RuntimeException { + + private final String from; + + private final String message; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntry.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..ca5cead25e207403bf0c702656d5e47a9d599db4 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntry.java @@ -0,0 +1,79 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.entry; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.Duration; +import java.time.Instant; + +@Document +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class IndexEntry { + + @Id + protected ObjectId id; + + private String uuid; + + private String clientUrl; + + private IndexEntryState state = IndexEntryState.Unknown; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant registrationTime; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant modificationTime; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant lastRetrievalTime; + + private RepositoryMetadata currentMetadata; + + public IndexEntry(String uuid, String clientUrl, IndexEntryState state, Instant registrationTime, + Instant modificationTime, Instant lastRetrievalTime, RepositoryMetadata currentMetadata) { + this.uuid = uuid; + this.clientUrl = clientUrl; + this.state = state; + this.registrationTime = registrationTime; + this.modificationTime = modificationTime; + this.lastRetrievalTime = lastRetrievalTime; + this.currentMetadata = currentMetadata; + } + + public Duration getLastRetrievalAgo() { + if (lastRetrievalTime == null) { + return null; + } + return Duration.between(lastRetrievalTime, Instant.now()); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntryState.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntryState.java new file mode 100644 index 0000000000000000000000000000000000000000..a5db38f2f7a803f290c00a505bb7a578046bebd5 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/IndexEntryState.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.entry; + +public enum IndexEntryState { + + Unknown, + + Valid, // Active / Inactive based on timestamps + + Unreachable, + + Invalid + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/RepositoryMetadata.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/RepositoryMetadata.java new file mode 100644 index 0000000000000000000000000000000000000000..d1139ae818eb037f69703961178addf91f539457 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/entry/RepositoryMetadata.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.entry; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.HashMap; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class RepositoryMetadata { + + public static final Integer CURRENT_VERSION = 1; + + private Integer metadataVersion = CURRENT_VERSION; + + private String repositoryUri; + + @NotNull + private HashMap<String, String> metadata = new HashMap<>(); + +} + diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/AdminTrigger.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/AdminTrigger.java new file mode 100644 index 0000000000000000000000000000000000000000..839d3e309168007ed37c96df6f8e1b105657e383 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/AdminTrigger.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AdminTrigger { + private String remoteAddr; + private String tokenName; + private String clientUrl; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/Event.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/Event.java new file mode 100644 index 0000000000000000000000000000000000000000..3443a8ab23f4fbb0f47c1a4a4792374735b4a241 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/Event.java @@ -0,0 +1,124 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.time.Instant; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Document(collection = "event") +public class Event { + @Id + protected ObjectId id; + @NotNull + private UUID uuid = UUID.randomUUID(); + @NotNull + private EventType type; + @NotNull + private Integer version; + + @DBRef + private Event triggeredBy; + @DBRef + private IndexEntry relatedTo; + + // Content (one of those) + private IncomingPing incomingPing; + private MetadataRetrieval metadataRetrieval; + private AdminTrigger adminTrigger; + private WebhookPing webhookPing; + private WebhookTrigger webhookTrigger; + + @NotNull + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant created = Instant.now(); + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant executed; + + @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) + private Instant finished; + + public boolean isExecuted() { + return executed != null; + } + + public void execute() { + executed = Instant.now(); + } + + public boolean isFinished() { + return finished != null; + } + + public void finish() { + finished = Instant.now(); + } + + public Event(Integer version, IncomingPing incomingPing) { + this.type = EventType.IncomingPing; + this.version = version; + this.incomingPing = incomingPing; + } + + public Event(Integer version, Event triggerEvent, IndexEntry relatedTo, MetadataRetrieval metadataRetrieval) { + this.type = EventType.MetadataRetrieval; + this.version = version; + this.triggeredBy = triggerEvent; + this.relatedTo = relatedTo; + this.metadataRetrieval = metadataRetrieval; + } + + public Event(Integer version, AdminTrigger adminTrigger) { + this.type = EventType.AdminTrigger; + this.version = version; + this.adminTrigger = adminTrigger; + } + + public Event(Integer version, WebhookTrigger webhookTrigger, Event triggerEvent) { + this.type = EventType.WebhookTrigger; + this.version = version; + this.webhookTrigger = webhookTrigger; + this.triggeredBy = triggerEvent; + this.relatedTo = triggerEvent.getRelatedTo(); + } + + public Event(Integer version, WebhookPing webhookPing) { + this.type = EventType.WebhookPing; + this.version = version; + this.webhookPing = webhookPing; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/EventType.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/EventType.java new file mode 100644 index 0000000000000000000000000000000000000000..54406f972a0738194290f8c01e74ffeef588095e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/EventType.java @@ -0,0 +1,31 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +public enum EventType { + AdminTrigger, + MetadataRetrieval, + WebhookTrigger, + IncomingPing, + WebhookPing, +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/IncomingPing.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/IncomingPing.java new file mode 100644 index 0000000000000000000000000000000000000000..118c3c8e28b0f149bad8eff440cab47af5731506 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/IncomingPing.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class IncomingPing { + private Exchange exchange; + private Boolean newEntry; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/MetadataRetrieval.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/MetadataRetrieval.java new file mode 100644 index 0000000000000000000000000000000000000000..6c65cbac27180ff7776606723a13285336ea3958 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/MetadataRetrieval.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import nl.dtls.fairdatapoint.entity.index.entry.RepositoryMetadata; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MetadataRetrieval { + private String error; + private Exchange exchange; + private RepositoryMetadata metadata; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookPing.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookPing.java new file mode 100644 index 0000000000000000000000000000000000000000..c0776fe735441e5c059b29d005dd3ab05dae3f65 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookPing.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WebhookPing { + private String remoteAddr; + private String tokenName; + private UUID webhookUuid; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookTrigger.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookTrigger.java new file mode 100644 index 0000000000000000000000000000000000000000..4c4d516734255fa2a44115849a3ae285a373d911 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/event/WebhookTrigger.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.event; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; +import nl.dtls.fairdatapoint.entity.index.webhook.Webhook; +import nl.dtls.fairdatapoint.entity.index.webhook.WebhookEvent; +import org.springframework.data.mongodb.core.mapping.DBRef; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class WebhookTrigger { + @DBRef + private Webhook webhook; + + private WebhookEvent matchedEvent; + + private Exchange exchange; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IncorrectPingFormatException.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IncorrectPingFormatException.java new file mode 100644 index 0000000000000000000000000000000000000000..5dec39b4da8d1f4176e2894dee811d60ba463c6a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IncorrectPingFormatException.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.exception; + +import org.springframework.http.HttpStatus; + +public class IncorrectPingFormatException extends IndexException { + + public IncorrectPingFormatException(String message) { + super(message, HttpStatus.BAD_REQUEST); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IndexException.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IndexException.java new file mode 100644 index 0000000000000000000000000000000000000000..bdfcb2932859208d74dcbfaf6ccd5eae5e88a394 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/IndexException.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.exception; + +import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; +import org.springframework.http.HttpStatus; + +public abstract class IndexException extends RuntimeException { + + protected final HttpStatus status; + + public IndexException(String message, HttpStatus status) { + super(message); + this.status = status; + } + + public HttpStatus getStatus() { + return status; + } + + public ErrorDTO getErrorDTO() { + return new ErrorDTO(getStatus(), getMessage()); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/PingDeniedException.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/PingDeniedException.java new file mode 100644 index 0000000000000000000000000000000000000000..3fd6f1d0ea68689c1579a7348248875bdac3d59d --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/PingDeniedException.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.exception; + +import org.springframework.http.HttpStatus; + +public class PingDeniedException extends IndexException { + + public PingDeniedException(String clientUrl) { + super("Client URL is denied: " + clientUrl, HttpStatus.FORBIDDEN); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/RateLimitException.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/RateLimitException.java new file mode 100644 index 0000000000000000000000000000000000000000..923ccb9f78a8332fdef3582bfc36ced0d1c3d0f1 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/exception/RateLimitException.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.exception; + +import org.springframework.http.HttpStatus; + +public class RateLimitException extends IndexException { + + public RateLimitException(String message) { + super(message, HttpStatus.TOO_MANY_REQUESTS); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Exchange.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Exchange.java new file mode 100644 index 0000000000000000000000000000000000000000..a6505399aa94cc9db449d8cb9850fe89eae5e31f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Exchange.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.http; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Exchange { + private ExchangeDirection direction; + private ExchangeState state = ExchangeState.Prepared; + private String remoteAddr; + private String error; + + private Request request = new Request(); + private Response response = new Response(); + + public Exchange(ExchangeDirection direction, String remoteAddr) { + this.direction = direction; + this.remoteAddr = remoteAddr; + } + + public Exchange(ExchangeDirection direction) { + this.direction = direction; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/membership/MembershipEntity.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeDirection.java old mode 100755 new mode 100644 similarity index 90% rename from src/main/java/nl/dtls/fairdatapoint/entity/membership/MembershipEntity.java rename to src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeDirection.java index d6ce75767da26326fab53eb064cf9700dcc3dc00..14bebd589823b751ab4cdcfe01d572c90259ead5 --- a/src/main/java/nl/dtls/fairdatapoint/entity/membership/MembershipEntity.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeDirection.java @@ -20,8 +20,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package nl.dtls.fairdatapoint.entity.membership; +package nl.dtls.fairdatapoint.entity.index.http; -public enum MembershipEntity { - CATALOG, DATASET, DISTRIBUTION +public enum ExchangeDirection { + INCOMING, + OUTGOING } diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeState.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeState.java new file mode 100644 index 0000000000000000000000000000000000000000..733c676e8149ffbcb3af4bfd405f7db9417f5513 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/ExchangeState.java @@ -0,0 +1,31 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.http; + +public enum ExchangeState { + Prepared, + Requested, + Timeout, + Failed, + Retrieved +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Request.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Request.java new file mode 100644 index 0000000000000000000000000000000000000000..e662148c448c0b8383f1abc1cb21fbdeed4c1da8 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Request.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.http; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.http.HttpEntity; + +import javax.servlet.http.HttpServletRequest; +import java.net.http.HttpRequest; +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Request { + private String method; + private String url; + + private Map<String, List<String>> headers; + private String body; + + public Map<String, List<String>> getHeaders() { + return headers; + } + + public void setHeaders(Map<String, List<String>> headers) { + this.headers = headers; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public void setFromHttpEntity(HttpEntity<String> httpEntity) { + body = httpEntity.getBody(); + headers = httpEntity.getHeaders(); + } + + public void setFromHttpServletRequest(HttpServletRequest request) { + method = request.getMethod(); + url = request.getRequestURI(); + } + + public void setFromHttpRequest(HttpRequest request) { + method = request.method(); + url = request.uri().toString(); + body = request.bodyPublisher().map(Object::toString).orElse(null); + headers = request.headers().map(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Response.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Response.java new file mode 100644 index 0000000000000000000000000000000000000000..719597c53cdc440c0c2197275a9ae630354c6b37 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/http/Response.java @@ -0,0 +1,50 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.http; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.net.http.HttpResponse; +import java.util.List; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Response { + private Integer code; + private String url; + private String origin; + + private Map<String, List<String>> headers; + private String body; + + public void setFromHttpResponse(HttpResponse<String> response) { + code = response.statusCode(); + url = response.uri().toString(); + headers = response.headers().map(); + body = response.body(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettings.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettings.java new file mode 100644 index 0000000000000000000000000000000000000000..c3227bce699ec9720b3ef914437e847588ff227e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettings.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.settings; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import javax.validation.constraints.NotNull; +import java.util.Objects; + +@Document +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +public class IndexSettings { + @Id + protected ObjectId id; + + @NotNull + private IndexSettingsRetrieval retrieval; + + @NotNull + private IndexSettingsPing ping; + + public static IndexSettings getDefault() { + IndexSettings settings = new IndexSettings(); + settings.setPing(IndexSettingsPing.getDefault()); + settings.setRetrieval(IndexSettingsRetrieval.getDefault()); + return settings; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IndexSettings that = (IndexSettings) o; + return retrieval.equals(that.retrieval) && ping.equals(that.ping); + } + + @Override + public int hashCode() { + return Objects.hash(retrieval, ping); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsPing.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsPing.java new file mode 100644 index 0000000000000000000000000000000000000000..32370ee23bdb0ab9bcf053d64f149d4a7a735fec --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsPing.java @@ -0,0 +1,59 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.settings; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.time.Duration; +import java.util.Collections; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +@EqualsAndHashCode +public class IndexSettingsPing { + @NotNull + private Duration validDuration; + + @NotNull + private Duration rateLimitDuration; + + @NotNull + private Integer rateLimitHits; + + @NotNull + private List<String> denyList; + + public static IndexSettingsPing getDefault() { + IndexSettingsPing ping = new IndexSettingsPing(); + ping.setValidDuration(Duration.ofDays(7)); + ping.setRateLimitDuration(Duration.ofHours(6)); + ping.setRateLimitHits(10); + ping.setDenyList(Collections.singletonList("^(http|https)://localhost(:[0-9]+){0,1}.*$")); + return ping; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsRetrieval.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsRetrieval.java new file mode 100644 index 0000000000000000000000000000000000000000..3aff145ca4f0aa1fe6f37bf2813c8a2bee80683c --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/settings/IndexSettingsRetrieval.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.settings; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.time.Duration; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) +@EqualsAndHashCode +public class IndexSettingsRetrieval { + @NotNull + private Duration rateLimitWait; + + @NotNull + private Duration timeout; + + public static IndexSettingsRetrieval getDefault() { + IndexSettingsRetrieval retrieval = new IndexSettingsRetrieval(); + retrieval.setRateLimitWait(Duration.ofMinutes(10)); + retrieval.setTimeout(Duration.ofMinutes(1)); + return retrieval; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/Webhook.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/Webhook.java new file mode 100644 index 0000000000000000000000000000000000000000..8721c74bc7e47c040429bf9c3d6e2a1a0e191814 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/Webhook.java @@ -0,0 +1,61 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.webhook; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Document(collection = "webhook") +public class Webhook { + @Id + protected ObjectId id; + + @NotNull + private UUID uuid = UUID.randomUUID(); + + private String payloadUrl; + + private String secret; + + private boolean allEvents; + + private List<WebhookEvent> events = new ArrayList<>(); + + private boolean allEntries; + + private List<String> entries = new ArrayList<>(); + + private boolean enabled; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/WebhookEvent.java b/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/WebhookEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..e4d22fca83099282a78d6c8c6592b5c158e0828e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/index/webhook/WebhookEvent.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.index.webhook; + +public enum WebhookEvent { + NewEntry, + IncomingPing, + EntryValid, + EntryInvalid, + EntryUnreachable, + AdminTrigger, + WebhookPing +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/membership/Membership.java b/src/main/java/nl/dtls/fairdatapoint/entity/membership/Membership.java index 0bf0a8cac37fb6b3f89e1e98a79d36d0d0c5550a..fb2fa00168ae6cc178c0b26713067db91458d154 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/membership/Membership.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/membership/Membership.java @@ -46,10 +46,9 @@ public class Membership { protected List<MembershipPermission> permissions; - protected List<MembershipEntity> allowedEntities; + protected List<String> allowedEntities; - public Membership(String uuid, String name, List<MembershipPermission> permissions, - List<MembershipEntity> allowedEntities) { + public Membership(String uuid, String name, List<MembershipPermission> permissions, List<String> allowedEntities) { this.uuid = uuid; this.name = name; this.permissions = permissions; diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/Metadata.java b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/Metadata.java index 38b5af070f0481f027cc67972c8b0fa3af04a065..82bc1b0752b012f3df202c17e60739ff7dce4cd7 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/Metadata.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/Metadata.java @@ -22,5 +22,23 @@ */ package nl.dtls.fairdatapoint.entity.metadata; +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Document +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@Builder(toBuilder = true) public class Metadata { + + @Id + protected ObjectId id; + + protected String uri; + + protected MetadataState state; } diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataGetter.java b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataGetter.java index 2962c76218cf2809b6d566143861cfb22e3cbec0..cbc28f421e869497efd7fcdb1aab027f23ab1979 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataGetter.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataGetter.java @@ -23,7 +23,6 @@ package nl.dtls.fairdatapoint.entity.metadata; import nl.dtls.fairdatapoint.util.ValueFactoryHelper; -import nl.dtls.fairdatapoint.vocabulary.DATACITE; import nl.dtls.fairdatapoint.vocabulary.FDP; import nl.dtls.fairdatapoint.vocabulary.R3D; import org.eclipse.rdf4j.model.IRI; @@ -32,8 +31,9 @@ import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.vocabulary.DCAT; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; -import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.stream.Collectors; @@ -52,7 +52,7 @@ public class MetadataGetter { } public static Identifier getMetadataIdentifier(Model metadata) { - return getIdentifier(metadata, DATACITE.HASIDENTIFIER); + return getIdentifier(metadata, FDP.METADATAIDENTIFIER); } public static IRI getParent(Model metadata) { @@ -77,6 +77,10 @@ public class MetadataGetter { return l(getObjectBy(metadata, null, DCTERMS.TITLE)); } + public static Literal getLabel(Model metadata) { + return l(getObjectBy(metadata, null, RDFS.LABEL)); + } + public static Literal getDescription(Model metadata) { return l(getObjectBy(metadata, null, DCTERMS.DESCRIPTION)); } @@ -89,17 +93,22 @@ public class MetadataGetter { return i(getObjectBy(metadata, null, DCTERMS.LICENSE)); } - public static LocalDateTime getIssued(Model metadata) { + public static OffsetDateTime getIssued(Model metadata) { String result = getStringObjectBy(metadata, null, FDP.METADATAISSUED); return result != null ? parseDateTimeLiteral(result) : null; } - public static LocalDateTime getModified(Model metadata) { + public static OffsetDateTime getModified(Model metadata) { String result = getStringObjectBy(metadata, null, FDP.METADATAMODIFIED); return result != null ? parseDateTimeLiteral(result) : null; } - public static LocalDateTime getMetadataModified(Model metadata) { + public static OffsetDateTime getMetadataIssued(Model metadata) { + String result = getStringObjectBy(metadata, null, DCTERMS.ISSUED); + return result != null ? parseDateTimeLiteral(result) : null; + } + + public static OffsetDateTime getMetadataModified(Model metadata) { String result = getStringObjectBy(metadata, null, DCTERMS.MODIFIED); return result != null ? parseDateTimeLiteral(result) : null; } @@ -132,8 +141,8 @@ public class MetadataGetter { // ------------------------------------------------------------------------------------------------------------ // Utils // ------------------------------------------------------------------------------------------------------------ - private static LocalDateTime parseDateTimeLiteral(String literal) { - return LocalDateTime.parse(literal, DateTimeFormatter.ISO_LOCAL_DATE_TIME); + private static OffsetDateTime parseDateTimeLiteral(String literal) { + return OffsetDateTime.parse(literal, DateTimeFormatter.ISO_OFFSET_DATE_TIME); } public static Identifier getIdentifier(Model metadata, IRI pred) { diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataSetter.java b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataSetter.java index c97a4e09248afd20726af07995a043a75192ea15..29d8d0771e889782c09f7c985c954ac785b7d168 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataSetter.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataSetter.java @@ -22,8 +22,8 @@ */ package nl.dtls.fairdatapoint.entity.metadata; -import nl.dtls.fairdatapoint.vocabulary.DATACITE; import nl.dtls.fairdatapoint.vocabulary.FDP; +import nl.dtls.fairdatapoint.vocabulary.R3D; import nl.dtls.fairdatapoint.vocabulary.Sio; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Literal; @@ -53,7 +53,7 @@ public class MetadataSetter { } public static void setMetadataIdentifier(Model metadata, IRI uri, Identifier identifier) { - setIdentifier(metadata, uri, identifier, DATACITE.HASIDENTIFIER); + setIdentifier(metadata, uri, identifier, FDP.METADATAIDENTIFIER); } public static void setParent(Model metadata, IRI uri, IRI parent) { @@ -69,7 +69,10 @@ public class MetadataSetter { // ------------------------------------------------------------------------------------------------------------ public static void setTitle(Model metadata, IRI uri, Literal title) { update(metadata, uri, DCTERMS.TITLE, title); - update(metadata, uri, RDFS.LABEL, title); + } + + public static void setLabel(Model metadata, IRI uri, Literal label) { + update(metadata, uri, RDFS.LABEL, label); } public static void setDescription(Model metadata, IRI uri, Literal description) { @@ -114,6 +117,10 @@ public class MetadataSetter { // Custom // ------------------------------------------------------------------------------------------------------------ + public static void setRepositoryIdentifier(Model metadata, IRI uri, Identifier identifier) { + setIdentifier(metadata, uri, identifier, R3D.REPOSITORYIDENTIFIER); + } + public static void setPublisher(Model metadata, IRI uri, Agent publisher) { setAgent(metadata, uri, publisher, DCTERMS.PUBLISHER); } diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataState.java b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataState.java new file mode 100644 index 0000000000000000000000000000000000000000..f4a0c96b172f5d777ed2ef3f69e9f32bdc87938a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/metadata/MetadataState.java @@ -0,0 +1,29 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.metadata; + +public enum MetadataState { + + DRAFT, PUBLISHED + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinition.java b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinition.java index f5fa887031230262e5e08ed02fda60c9863793bb..920d3f81f85855d7ec883ddcb960e926c4f38352 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinition.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinition.java @@ -22,11 +22,13 @@ */ package nl.dtls.fairdatapoint.entity.resource; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.*; import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import java.util.ArrayList; import java.util.List; @Document @@ -34,41 +36,34 @@ import java.util.List; @AllArgsConstructor @Getter @Setter +@EqualsAndHashCode @Builder(toBuilder = true) public class ResourceDefinition { @Id + @JsonIgnore protected ObjectId id; protected String uuid; protected String name; - protected String uriPrefix; + protected String urlPrefix; - protected String rdfType; + protected List<String> shapeUuids = new ArrayList<>(); - protected String specs; + protected List<ResourceDefinitionChild> children = new ArrayList<>(); - protected List<String> shaclTargetClasses; + protected List<ResourceDefinitionLink> externalLinks = new ArrayList<>(); - protected String child; - - protected String parentResourceDefinitionUuid; - - protected String childResourceDefinitionUuid; - - public ResourceDefinition(String uuid, String name, String uriPrefix, String rdfType, String specs, - List<String> shaclTargetClasses, String child, String parentResourceDefinitionUuid, - String childResourceDefinitionUuid) { + public ResourceDefinition(String uuid, String name, String urlPrefix, List<String> shapeUuids, + List<ResourceDefinitionChild> children, List<ResourceDefinitionLink> externalLinks) { this.uuid = uuid; this.name = name; - this.uriPrefix = uriPrefix; - this.rdfType = rdfType; - this.specs = specs; - this.shaclTargetClasses = shaclTargetClasses; - this.child = child; - this.parentResourceDefinitionUuid = parentResourceDefinitionUuid; - this.childResourceDefinitionUuid = childResourceDefinitionUuid; + this.urlPrefix = urlPrefix; + this.shapeUuids = shapeUuids; + this.children = children; + this.externalLinks = externalLinks; } + } \ No newline at end of file diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChild.java b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChild.java new file mode 100644 index 0000000000000000000000000000000000000000..1f62ca92dc81381ed6c601ae9a399bbcf1b9b49f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChild.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.resource; + +import lombok.*; +import nl.dtls.fairdatapoint.api.validator.ValidIri; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class ResourceDefinitionChild { + + @NotBlank + protected String resourceDefinitionUuid; + + @NotBlank + @ValidIri + protected String relationUri; + + @Valid + protected ResourceDefinitionChildListView listView; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListView.java b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListView.java new file mode 100644 index 0000000000000000000000000000000000000000..43474dbc28e5baf4934fa99aacdac11bbcd8a5c8 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListView.java @@ -0,0 +1,49 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.resource; + +import lombok.*; +import nl.dtls.fairdatapoint.api.validator.ValidIri; + +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class ResourceDefinitionChildListView { + + @NotBlank + protected String title; + + @ValidIri + protected String tagsUri; + + @Valid + protected List<ResourceDefinitionChildListViewMetadata> metadata; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListViewMetadata.java b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListViewMetadata.java new file mode 100644 index 0000000000000000000000000000000000000000..2fc935c3e1ca9893769886c9ff49c0d25fa14a10 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionChildListViewMetadata.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.resource; + +import lombok.*; +import nl.dtls.fairdatapoint.api.validator.ValidIri; + +import javax.validation.constraints.NotBlank; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class ResourceDefinitionChildListViewMetadata { + + @NotBlank + protected String title; + + @NotBlank + @ValidIri + protected String propertyUri; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionLink.java b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionLink.java new file mode 100644 index 0000000000000000000000000000000000000000..b132308f9f9d6ac6c5fe6bab7ee03bdb95407415 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/resource/ResourceDefinitionLink.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.resource; + +import lombok.*; +import nl.dtls.fairdatapoint.api.validator.ValidIri; + +import javax.validation.constraints.NotBlank; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +public class ResourceDefinitionLink { + + @NotBlank + protected String title; + + @NotBlank + @ValidIri + protected String propertyUri; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResult.java b/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResult.java new file mode 100644 index 0000000000000000000000000000000000000000..54e51088d5adb5f13ccc959a3a1cf5218a6e88ed --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResult.java @@ -0,0 +1,45 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.search; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +public class SearchResult { + + private String uri; + + private String type; + + private String title; + + private String description; + + private SearchResultRelation relation; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResultRelation.java b/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResultRelation.java new file mode 100644 index 0000000000000000000000000000000000000000..365909c8fd37763c51296d35a8e75868854c5887 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/search/SearchResultRelation.java @@ -0,0 +1,38 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.search; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@Setter +public class SearchResultRelation { + + private String predicate; + + private String object; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/settings/Settings.java b/src/main/java/nl/dtls/fairdatapoint/entity/settings/Settings.java new file mode 100644 index 0000000000000000000000000000000000000000..698463cdc4a069adfb705f4064d8023b2e8d262f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/settings/Settings.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.settings; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.List; +import java.util.Map; + +@Document +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class Settings { + + @Id + @JsonIgnore + protected ObjectId id; + + private List<SettingsMetricsEntry> metadataMetrics; + + private SettingsPing ping; + + private static final List<SettingsMetricsEntry> DEFAULT_METRICS = List.of( + new SettingsMetricsEntry("https://purl.org/fair-metrics/FM_F1A", "https://www.ietf.org/rfc/rfc3986.txt"), + new SettingsMetricsEntry("https://purl.org/fair-metrics/FM_A1.1", "https://www.wikidata.org/wiki/Q8777") + ); + + public static Settings getDefault() { + return Settings.builder() + .metadataMetrics(DEFAULT_METRICS) + .ping(SettingsPing.builder() + .enabled(true) + .endpoints(List.of("https://home.fairdatapoint.org")) + .build()) + .build(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsMetricsEntry.java b/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsMetricsEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..552afaae6054c979983d72f1c0b52f200f5f2ff9 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsMetricsEntry.java @@ -0,0 +1,39 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.settings; + +import lombok.*; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class SettingsMetricsEntry { + + private String metricUri; + + private String resourceUri; + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsPing.java b/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsPing.java new file mode 100644 index 0000000000000000000000000000000000000000..d13fca4455ded176b78c5d5caa65d53c6e24a04a --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/entity/settings/SettingsPing.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.entity.settings; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@EqualsAndHashCode +@Builder(toBuilder = true) +public class SettingsPing { + + private boolean enabled; + + @NotNull + private List<String> endpoints; +} diff --git a/src/main/java/nl/dtls/fairdatapoint/entity/shape/Shape.java b/src/main/java/nl/dtls/fairdatapoint/entity/shape/Shape.java index 17492e947800f988cda948ab24669bc41b07facf..7a6188757db988513b761bf2fb6a9773fc977619 100755 --- a/src/main/java/nl/dtls/fairdatapoint/entity/shape/Shape.java +++ b/src/main/java/nl/dtls/fairdatapoint/entity/shape/Shape.java @@ -27,6 +27,8 @@ import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; +import java.util.Set; + @Document @Getter @Setter @@ -42,8 +44,11 @@ public class Shape { private String name; + private boolean published; + private ShapeType type; private String definition; + private Set<String> targetClasses; } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/UtilityService.java b/src/main/java/nl/dtls/fairdatapoint/service/UtilityService.java new file mode 100644 index 0000000000000000000000000000000000000000..30e1ea5a886629595765202d3b4ddbe2ea94fa0f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/UtilityService.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service; + +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.util.HttpUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +@Service +public class UtilityService { + + @Autowired + private InstanceProperties instanceProperties; + + public String getRemoteAddr(HttpServletRequest request) { + return HttpUtil.getClientIpAddress(request, instanceProperties.isBehindProxy()); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/actuator/AppInfoContributor.java b/src/main/java/nl/dtls/fairdatapoint/service/actuator/AppInfoContributor.java index 0fa5b0a17203d700de0d187b80071c68ce55c244..d726951425eb4dba38e589ced9fd8af5debcb5d2 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/actuator/AppInfoContributor.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/actuator/AppInfoContributor.java @@ -47,10 +47,10 @@ public class AppInfoContributor implements InfoContributor { @Override public void contribute(Info.Builder builder) { builder.withDetail("name", "FAIR Data Point"); - if (tag != null && !tag.isEmpty()) { - builder.withDetail("version", tag); - } else { + if (tag == null || tag.isEmpty()) { builder.withDetail("version", format("%s~%s", branch, commitShort)); + } else { + builder.withDetail("version", format("%s~%s", tag, commitShort)); } builder.withDetail("builtAt", buildTime); } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4d64b4e8f6922f5023015f9a2a4138481bfe3593 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyMapper.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.apikey; + +import nl.dtls.fairdatapoint.api.dto.apikey.ApiKeyDTO; +import nl.dtls.fairdatapoint.entity.apikey.ApiKey; +import org.springframework.stereotype.Service; + +@Service +public class ApiKeyMapper { + + public ApiKeyDTO toDTO(ApiKey apiKey) { + return new ApiKeyDTO(apiKey.getUuid(), apiKey.getToken()); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyService.java b/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyService.java new file mode 100644 index 0000000000000000000000000000000000000000..fb3f17ed1d1c8147ac37f79bd1f9b78d1ad3f96f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/apikey/ApiKeyService.java @@ -0,0 +1,113 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.apikey; + +import nl.dtls.fairdatapoint.api.dto.apikey.ApiKeyDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.ApiKeyRepository; +import nl.dtls.fairdatapoint.entity.apikey.ApiKey; +import nl.dtls.fairdatapoint.entity.exception.ForbiddenException; +import nl.dtls.fairdatapoint.entity.exception.UnauthorizedException; +import nl.dtls.fairdatapoint.entity.user.User; +import nl.dtls.fairdatapoint.entity.user.UserRole; +import nl.dtls.fairdatapoint.service.security.MongoAuthenticationService; +import nl.dtls.fairdatapoint.service.user.CurrentUserService; +import org.apache.commons.lang3.RandomStringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +public class ApiKeyService { + + @Autowired + private ApiKeyRepository apiKeyRepository; + + @Autowired + private CurrentUserService currentUserService; + + @Autowired + private MongoAuthenticationService mongoAuthenticationService; + + @Autowired + private ApiKeyMapper apiKeyMapper; + + public List<ApiKeyDTO> getAll() { + Optional<User> oUser = currentUserService.getCurrentUser(); + if (oUser.isEmpty()) { + throw new UnauthorizedException("You have to be log in"); + } + User user = oUser.get(); + List<ApiKey> apiKeys = apiKeyRepository.findByUserUuid(user.getUuid()); + return apiKeys + .stream() + .map(apiKeyMapper::toDTO) + .collect(Collectors.toList()); + } + + public ApiKeyDTO create() { + Optional<User> oUser = currentUserService.getCurrentUser(); + if (oUser.isEmpty()) { + throw new UnauthorizedException("You have to be log in"); + } + User user = oUser.get(); + String generatedString = RandomStringUtils.random(128, true, true); + String uuid = UUID.randomUUID().toString(); + ApiKey apiKey = new ApiKey(null, uuid, user.getUuid(), generatedString); + apiKeyRepository.save(apiKey); + return apiKeyMapper.toDTO(apiKey); + } + + public boolean delete(String uuid) { + Optional<ApiKey> oApiKey = apiKeyRepository.findByUuid(uuid); + if (oApiKey.isEmpty()) { + return false; + } + ApiKey apiKey = oApiKey.get(); + Optional<User> oCurrentUser = currentUserService.getCurrentUser(); + if (oCurrentUser.isEmpty()) { + throw new ForbiddenException("You have to be log in"); + } + User currentUser = oCurrentUser.get(); + if (currentUser.getRole().equals(UserRole.ADMIN) || apiKey.getUserUuid().equals(currentUser.getUuid())) { + apiKeyRepository.delete(apiKey); + return true; + } else { + throw new ForbiddenException("You are not allow to delete the entry"); + } + } + + public Authentication getAuthentication(String token) { + Optional<ApiKey> oApiKey = apiKeyRepository.findByToken(token); + if (oApiKey.isEmpty()) { + throw new UnauthorizedException("Invalid or non-existing API key"); + } + ApiKey apiKey = oApiKey.get(); + return mongoAuthenticationService.getAuthentication(apiKey.getUserUuid()); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/config/ConfigService.java b/src/main/java/nl/dtls/fairdatapoint/service/config/ConfigService.java index f6275b51d6e8c155ce67c8a6af72ddbbe6e84684..e0b8bb6466aa65dfab3a47f4887bb7e2eb91c30e 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/config/ConfigService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/config/ConfigService.java @@ -23,10 +23,16 @@ package nl.dtls.fairdatapoint.service.config; import nl.dtls.fairdatapoint.api.dto.config.BootstrapConfigDTO; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionDTO; +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import java.util.List; + @Service public class ConfigService { @@ -34,8 +40,15 @@ public class ConfigService { @Qualifier("persistentUrl") private String persistentUrl; + @Autowired + private InstanceProperties instanceProperties; + + @Autowired + private ResourceDefinitionService resourceDefinitionService; + public BootstrapConfigDTO getBootstrapConfig() { - return new BootstrapConfigDTO(persistentUrl); + List<ResourceDefinitionDTO> resourceDefinitions = resourceDefinitionService.getAll(); + return new BootstrapConfigDTO(persistentUrl, resourceDefinitions, instanceProperties.isIndex()); } } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardMapper.java deleted file mode 100755 index 3ca7c0ef73ba5cc2c943bea76e636c4488f8326f..0000000000000000000000000000000000000000 --- a/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardMapper.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package nl.dtls.fairdatapoint.service.dashboard; - -import nl.dtls.fairdatapoint.api.dto.dashboard.DashboardItemDTO; -import nl.dtls.fairdatapoint.api.dto.membership.MembershipDTO; -import org.eclipse.rdf4j.model.Model; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Optional; - -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getTitle; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; - -@Service -public class DashboardMapper { - - public DashboardItemDTO toCatalogDTO(Model c, List<DashboardItemDTO> datasets, Optional<MembershipDTO> membership) { - return new DashboardItemDTO( - getUri(c).toString(), - getTitle(c).getLabel(), - datasets, - membership - ); - } - - public DashboardItemDTO toDatasetDTO(Model d, List<DashboardItemDTO> datasets, Optional<MembershipDTO> membership) { - return new DashboardItemDTO( - getUri(d).toString(), - getTitle(d).getLabel(), - datasets, - membership - ); - } - - public DashboardItemDTO toDistributionDTO(Model d, Optional<MembershipDTO> membership) { - return new DashboardItemDTO( - getUri(d).toString(), - getTitle(d).getLabel(), - List.of(), - membership - ); - } -} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardService.java b/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardService.java index a3aa138052c2e4c21796341eca48b996d4e2492c..84d6762605b78e50bd99b182f5b4f1bb88da79a5 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/dashboard/DashboardService.java @@ -24,87 +24,85 @@ package nl.dtls.fairdatapoint.service.dashboard; import nl.dtls.fairdatapoint.api.dto.dashboard.DashboardItemDTO; import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.membership.MembershipDTO; import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; import nl.dtls.fairdatapoint.service.member.MemberService; import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; -import static nl.dtls.fairdatapoint.util.ThrowingFunction.suppress; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getTitle; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; +import static nl.dtls.fairdatapoint.util.RdfUtil.getObjectsBy; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; @Service public class DashboardService { @Autowired - @Qualifier("catalogMetadataService") - private MetadataService catalogMetadataService; + @Qualifier("genericMetadataService") + private MetadataService metadataService; @Autowired - @Qualifier("genericMetadataService") - private MetadataService genericMetadataService; + private MetadataStateService metadataStateService; @Autowired private MemberService memberService; @Autowired - private DashboardMapper dashboardMapper; - - public List<DashboardItemDTO> getDashboard(IRI repositoryUri) throws MetadataServiceException { - Model repository = genericMetadataService.retrieve(repositoryUri); - return getDashboardCatalogs(repository); - } - - private List<DashboardItemDTO> getDashboardCatalogs(Model fdpMetadata) throws MetadataServiceException { - List<Model> catalogs = catalogMetadataService.retrieve(getCatalogs(fdpMetadata)); - return catalogs.stream() - .map(suppress(this::getDashboardCatalog)) - .filter(c -> c.getMembership().isPresent() || c.getChildren().size() > 0) - .collect(Collectors.toList()); - } + private ResourceDefinitionService resourceDefinitionService; - private DashboardItemDTO getDashboardCatalog(Model catalog) throws MetadataServiceException { - String catalogId = getMetadataIdentifier(catalog).getIdentifier().getLabel(); - Optional<MemberDTO> oCatalogMember = memberService.getMemberForCurrentUser(catalogId, Metadata.class); - List<DashboardItemDTO> datasetDtos = getDashboardDatasets(catalog); - return dashboardMapper.toCatalogDTO(catalog, datasetDtos, oCatalogMember.map(MemberDTO::getMembership)); - } - - private List<DashboardItemDTO> getDashboardDatasets(Model catalog) throws MetadataServiceException { - List<Model> datasets = genericMetadataService.retrieve(getDatasets(catalog)); - return datasets.stream() - .map(suppress(this::getDashboardDataset)) - .filter(d -> d.getMembership().isPresent() || d.getChildren().size() > 0) - .collect(Collectors.toList()); - } - - private DashboardItemDTO getDashboardDataset(Model dataset) throws MetadataServiceException { - String datasetId = getMetadataIdentifier(dataset).getIdentifier().getLabel(); - Optional<MemberDTO> oDatasetMember = memberService.getMemberForCurrentUser(datasetId, Metadata.class); - List<DashboardItemDTO> distributionDtos = getDashboardDistributions(dataset); - return dashboardMapper.toDatasetDTO(dataset, distributionDtos, oDatasetMember.map(MemberDTO::getMembership)); - } + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; - private List<DashboardItemDTO> getDashboardDistributions(Model dataset) throws MetadataServiceException { - List<Model> distributions = genericMetadataService.retrieve(getDistributions(dataset)); - return distributions.stream() - .map(this::getDashboardDistribution) - .filter(d -> d.getMembership().isPresent()) - .collect(Collectors.toList()); + public List<DashboardItemDTO> getDashboard(IRI repositoryUri) throws MetadataServiceException { + ResourceDefinition rd = resourceDefinitionService.getByUrlPrefix(""); + Model repository = metadataService.retrieve(repositoryUri); + return getDashboardItem(repositoryUri, repository, rd).getChildren(); } - private DashboardItemDTO getDashboardDistribution(Model distribution) { - String distributionId = getMetadataIdentifier(distribution).getIdentifier().getLabel(); - Optional<MemberDTO> oDistributionMember = memberService.getMemberForCurrentUser(distributionId, Metadata.class); - return dashboardMapper.toDistributionDTO(distribution, oDistributionMember.map(MemberDTO::getMembership)); + private DashboardItemDTO getDashboardItem(IRI metadataUri, Model model, ResourceDefinition rd) throws MetadataServiceException { + List<DashboardItemDTO> children = new ArrayList<>(); + for (ResourceDefinitionChild rdChild : rd.getChildren()) { + IRI relationUri = i(rdChild.getRelationUri()); + for (org.eclipse.rdf4j.model.Value childUri : getObjectsBy(model, metadataUri, relationUri)) { + IRI childIri = i(childUri.stringValue()); + DashboardItemDTO child = getDashboardItem( + childIri, + metadataService.retrieve(childIri), + resourceDefinitionCache.getByUuid(rdChild.getResourceDefinitionUuid()) + ); + children.add(child); + } + } + + Optional<MemberDTO> oMember = memberService.getMemberForCurrentUser(metadataUri.stringValue(), Metadata.class); + Optional<MembershipDTO> membership = oMember.map(MemberDTO::getMembership); + Metadata state = metadataStateService.get(metadataUri); + return new DashboardItemDTO( + metadataUri.toString(), + getTitle(model).getLabel(), + children + .stream() + .filter(e -> e.getMembership().isPresent() || e.getChildren().size() > 0) + .collect(Collectors.toList()), + membership, + state.getState() + ); } } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/common/IndexFeatureAspect.java b/src/main/java/nl/dtls/fairdatapoint/service/index/common/IndexFeatureAspect.java new file mode 100644 index 0000000000000000000000000000000000000000..87c37b3afa955efd38d9aa7e4e7ab16e52c6bd88 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/common/IndexFeatureAspect.java @@ -0,0 +1,50 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.common; + +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.entity.exception.FeatureDisabledException; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Aspect +@Component +public class IndexFeatureAspect { + + @Autowired + private InstanceProperties instanceProperties; + + @Around("@annotation(nl.dtls.fairdatapoint.service.index.common.RequiredEnabledIndexFeature)") + public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { + if (!instanceProperties.isIndex()) { + throw new FeatureDisabledException("Index functionality is turn off"); + } + return joinPoint.proceed(); + } + + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/common/RequiredEnabledIndexFeature.java b/src/main/java/nl/dtls/fairdatapoint/service/index/common/RequiredEnabledIndexFeature.java new file mode 100644 index 0000000000000000000000000000000000000000..705a810e245532a9208d0bb2f670623091accba0 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/common/RequiredEnabledIndexFeature.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.common; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RequiredEnabledIndexFeature { + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..b8f1b7b16b52e297cbf12a7b037b6bf24585ed2b --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryMapper.java @@ -0,0 +1,81 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.entry; + +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDetailDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryStateDTO; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.service.index.event.EventMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Service +public class IndexEntryMapper { + + @Autowired + private EventMapper eventMapper; + + public IndexEntryDTO toDTO(IndexEntry indexEntry, Instant validThreshold) { + return new IndexEntryDTO( + indexEntry.getUuid(), + indexEntry.getClientUrl(), + toStateDTO(indexEntry.getState(), indexEntry.getLastRetrievalTime(), validThreshold), + indexEntry.getRegistrationTime().toString(), + indexEntry.getModificationTime().toString() + ); + } + + public IndexEntryDetailDTO toDetailDTO(IndexEntry indexEntry, Iterable<Event> events, Instant validThreshold) { + return new IndexEntryDetailDTO( + indexEntry.getUuid(), + indexEntry.getClientUrl(), + toStateDTO(indexEntry.getState(), indexEntry.getLastRetrievalTime(), validThreshold), + indexEntry.getCurrentMetadata(), + StreamSupport.stream(events.spliterator(), false) + .map(eventMapper::toDTO) + .collect(Collectors.toList()), + indexEntry.getRegistrationTime().toString(), + indexEntry.getModificationTime().toString(), + indexEntry.getLastRetrievalTime().toString() + ); + } + + public IndexEntryStateDTO toStateDTO(IndexEntryState state, Instant lastRetrievalTime, Instant validThreshold) { + return switch (state) { + case Unknown -> IndexEntryStateDTO.UNKNOWN; + case Valid -> lastRetrievalTime.isAfter(validThreshold) + ? IndexEntryStateDTO.ACTIVE + : IndexEntryStateDTO.INACTIVE; + case Invalid -> IndexEntryStateDTO.INVALID; + case Unreachable -> IndexEntryStateDTO.UNREACHABLE; + }; + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryService.java b/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryService.java new file mode 100644 index 0000000000000000000000000000000000000000..151030295f27c8f094b509c3268350514f051a12 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/entry/IndexEntryService.java @@ -0,0 +1,168 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.entry; + +import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDetailDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryInfoDTO; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryStateDTO; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState; +import nl.dtls.fairdatapoint.service.index.common.RequiredEnabledIndexFeature; +import nl.dtls.fairdatapoint.service.index.event.EventService; +import nl.dtls.fairdatapoint.service.index.settings.IndexSettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.time.Instant; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryStateDTO.*; + +@Service +@Validated +@Log4j2 +public class IndexEntryService { + + @Autowired + private IndexEntryRepository repository; + + @Autowired + private IndexSettingsService indexSettingsService; + + @Autowired + private EventService eventService; + + @Autowired + private IndexEntryMapper mapper; + + @RequiredEnabledIndexFeature + public Iterable<IndexEntry> getAllEntries() { + return repository.findAll(); + } + + @RequiredEnabledIndexFeature + public List<IndexEntryDTO> getAllEntriesAsDTOs() { + Instant validThreshold = getValidThreshold(); + return StreamSupport.stream(getAllEntries().spliterator(), true).map(it -> mapper.toDTO(it, validThreshold)).collect(Collectors.toList()); + } + + @RequiredEnabledIndexFeature + public Page<IndexEntry> getEntriesPage(Pageable pageable, String state) { + Instant validThreshold = getValidThreshold(); + if (state.equalsIgnoreCase(ACTIVE.name())) { + return repository.findAllByStateEqualsAndLastRetrievalTimeAfter(pageable, IndexEntryState.Valid, + validThreshold); + } + if (state.equalsIgnoreCase(IndexEntryStateDTO.INACTIVE.name())) { + return repository.findAllByStateEqualsAndLastRetrievalTimeBefore(pageable, IndexEntryState.Valid, + validThreshold); + } + if (state.equalsIgnoreCase(IndexEntryStateDTO.UNREACHABLE.name())) { + return repository.findAllByStateEquals(pageable, IndexEntryState.Unreachable); + } + if (state.equalsIgnoreCase(IndexEntryStateDTO.INVALID.name())) { + return repository.findAllByStateEquals(pageable, IndexEntryState.Invalid); + } + if (state.equalsIgnoreCase(IndexEntryStateDTO.UNKNOWN.name())) { + return repository.findAllByStateEquals(pageable, IndexEntryState.Unknown); + } + return repository.findAll(pageable); + } + + @RequiredEnabledIndexFeature + public Page<IndexEntryDTO> getEntriesPageDTOs(Pageable pageable, String state) { + Instant validThreshold = getValidThreshold(); + return getEntriesPage(pageable, state).map(it -> mapper.toDTO(it, validThreshold)); + } + + @RequiredEnabledIndexFeature + public Optional<IndexEntry> getEntry(String uuid) { + return repository.findByUuid(uuid); + } + + @RequiredEnabledIndexFeature + public Optional<IndexEntryDetailDTO> getEntryDetailDTO(String uuid) { + Instant validThreshold = getValidThreshold(); + return getEntry(uuid).map(entry -> mapper.toDetailDTO(entry, eventService.getEvents(entry.getUuid()), validThreshold)); + } + + @RequiredEnabledIndexFeature + public IndexEntryInfoDTO getEntriesInfo() { + Instant validThreshold = getValidThreshold(); + Map<String, Long> entriesCount = new HashMap<>(); + entriesCount.put("ALL", repository.count()); + entriesCount.put(UNKNOWN.name(), repository.countAllByStateEquals(IndexEntryState.Unknown)); + entriesCount.put(ACTIVE.name(), + repository.countAllByStateEqualsAndLastRetrievalTimeAfter(IndexEntryState.Valid, validThreshold)); + entriesCount.put(INACTIVE.name(), + repository.countAllByStateEqualsAndLastRetrievalTimeBefore(IndexEntryState.Valid, validThreshold)); + entriesCount.put(UNREACHABLE.name(), repository.countAllByStateEquals(IndexEntryState.Unreachable)); + entriesCount.put(INVALID.name(), repository.countAllByStateEquals(IndexEntryState.Invalid)); + return new IndexEntryInfoDTO(entriesCount); + } + + @RequiredEnabledIndexFeature + public IndexEntry storeEntry(@Valid PingDTO pingDTO) { + var clientUrl = pingDTO.getClientUrl(); + var entity = repository.findByClientUrl(clientUrl); + var now = Instant.now(); + + final IndexEntry entry; + if (entity.isPresent()) { + log.info("Updating timestamp of existing entry {}", clientUrl); + entry = entity.orElseThrow(); + } else { + log.info("Storing new entry {}", clientUrl); + entry = new IndexEntry(); + entry.setUuid(UUID.randomUUID().toString()); + entry.setClientUrl(clientUrl); + entry.setRegistrationTime(now); + } + + entry.setModificationTime(now); + return repository.save(entry); + } + + @RequiredEnabledIndexFeature + @PreAuthorize("hasRole('ADMIN')") + public void deleteEntry(String uuid) { + IndexEntry entry = repository.findByUuid(uuid).orElseThrow(() -> new ResourceNotFoundException("Index entry not found")); + repository.delete(entry); + } + + private Instant getValidThreshold() { + return Instant.now().minus(indexSettingsService.getOrDefaults().getPing().getValidDuration()); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..c9b03b7be29119de95618e92a4e6d306564c30cf --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventMapper.java @@ -0,0 +1,56 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.event; + + +import nl.dtls.fairdatapoint.api.dto.index.event.EventDTO; +import nl.dtls.fairdatapoint.entity.index.event.AdminTrigger; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; + +@Service +public class EventMapper { + + private static final Integer VERSION = 1; + + public EventDTO toDTO(Event event) { + return new EventDTO( + event.getUuid(), + event.getType(), + event.getCreated().toString(), + event.getFinished().toString() + ); + } + + public Event toAdminTriggerEvent(HttpServletRequest request, Authentication authentication, String clientUrl, String remoteAddr) { + var adminTrigger = new AdminTrigger(); + adminTrigger.setRemoteAddr(remoteAddr); + adminTrigger.setTokenName(authentication.getName()); + adminTrigger.setClientUrl(clientUrl); + return new Event(VERSION, adminTrigger); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventService.java b/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventService.java new file mode 100644 index 0000000000000000000000000000000000000000..327d767f96844d520eaa6c36b7b6d0f40918c385 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/event/EventService.java @@ -0,0 +1,261 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.event; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.SneakyThrows; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.EventRepository; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.EventType; +import nl.dtls.fairdatapoint.entity.index.exception.IncorrectPingFormatException; +import nl.dtls.fairdatapoint.entity.index.exception.PingDeniedException; +import nl.dtls.fairdatapoint.entity.index.exception.RateLimitException; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeState; +import nl.dtls.fairdatapoint.service.UtilityService; +import nl.dtls.fairdatapoint.service.index.common.RequiredEnabledIndexFeature; +import nl.dtls.fairdatapoint.service.index.entry.IndexEntryService; +import nl.dtls.fairdatapoint.service.index.settings.IndexSettingsService; +import nl.dtls.fairdatapoint.service.index.webhook.WebhookService; +import nl.dtls.fairdatapoint.util.HttpUtil; +import org.eclipse.rdf4j.util.iterators.EmptyIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import java.time.Instant; +import java.util.Optional; + +@Service +public class EventService { + private static final Logger logger = LoggerFactory.getLogger(EventService.class); + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ThreadPoolTaskExecutor executor; + + @Autowired + private EventRepository eventRepository; + + @Autowired + private IndexEntryRepository indexEntryRepository; + + @Autowired + @Lazy + private IndexEntryService indexEntryService; + + @Autowired + private WebhookService webhookService; + + @Autowired + private EventMapper eventMapper; + + @Autowired + private UtilityService utilityService; + + @Autowired + private IncomingPingUtils incomingPingUtils; + + @Autowired + private IndexSettingsService indexSettingsService; + + public Iterable<Event> getEvents(IndexEntry indexEntry) { + // TODO: make events pagination in the future + return eventRepository.getAllByRelatedTo(indexEntry, PageRequest.of(0, 10, Sort.by(Sort.Direction.DESC, + "created"))); + } + + @RequiredEnabledIndexFeature + public Iterable<Event> getEvents(String indexEntryUuid) { + return indexEntryService.getEntry(indexEntryUuid).map(this::getEvents).orElse(EmptyIterator::new); + } + + @RequiredEnabledIndexFeature + @SneakyThrows + public Event acceptIncomingPing(PingDTO reqDto, HttpServletRequest request) { + var remoteAddr = utilityService.getRemoteAddr(request); + var pingSettings = indexSettingsService.getOrDefaults().getPing(); + + if (indexSettingsService.isPingDenied(reqDto)) { + logger.info("Received ping is denied"); + throw new PingDeniedException(reqDto.getClientUrl()); + } + + var rateLimitSince = Instant.now().minus(pingSettings.getRateLimitDuration()); + var previousPings = eventRepository.findAllByIncomingPingExchangeRemoteAddrAndCreatedAfter(remoteAddr, + rateLimitSince); + if (previousPings.size() > pingSettings.getRateLimitHits()) { + logger.warn("Rate limit for PING reached by {}", remoteAddr); + throw new RateLimitException(String.format( + "Rate limit reached for %s (max. %d per %s) - PING ignored", + remoteAddr, pingSettings.getRateLimitHits(), pingSettings.getRateLimitDuration().toString()) + ); + } + + var event = incomingPingUtils.prepareEvent(reqDto, request, remoteAddr); + eventRepository.save(event); + event.execute(); + try { + var indexEntry = indexEntryService.storeEntry(reqDto); + event.getIncomingPing().setNewEntry(indexEntry.getRegistrationTime().equals(indexEntry.getModificationTime())); + event.getIncomingPing().getExchange().getResponse().setCode(204); + event.setRelatedTo(indexEntry); + logger.info("Accepted incoming ping as a new event"); + } catch (Exception e) { + var ex = new IncorrectPingFormatException("Could not parse PING: " + e.getMessage()); + event.getIncomingPing().getExchange().getResponse().setCode(400); + event.getIncomingPing().getExchange().getResponse().setBody(objectMapper.writeValueAsString(ex.getErrorDTO())); + event.setFinished(Instant.now()); + eventRepository.save(event); + logger.info("Incoming ping has incorrect format: {}", e.getMessage()); + throw ex; + } + event.setFinished(Instant.now()); + return eventRepository.save(event); + } + + private void processMetadataRetrieval(Event event) { + var retrievalSettings = indexSettingsService.getOrDefaults().getRetrieval(); + var clientUrl = event.getRelatedTo().getClientUrl(); + if (MetadataRetrievalUtils.shouldRetrieve(event, retrievalSettings.getRateLimitWait())) { + indexEntryRepository.save(event.getRelatedTo()); + eventRepository.save(event); + event.execute(); + + logger.info("Retrieving metadata for {}", clientUrl); + MetadataRetrievalUtils.retrieveRepositoryMetadata(event, retrievalSettings.getTimeout()); + Exchange ex = event.getMetadataRetrieval().getExchange(); + if (ex.getState() == ExchangeState.Retrieved) { + try { + logger.info("Parsing metadata for {}", clientUrl); + var metadata = MetadataRetrievalUtils.parseRepositoryMetadata(ex.getResponse().getBody()); + if (metadata.isPresent()) { + event.getMetadataRetrieval().setMetadata(metadata.get()); + event.getRelatedTo().setCurrentMetadata(metadata.get()); + event.getRelatedTo().setState(IndexEntryState.Valid); + logger.info("Storing metadata for {}", clientUrl); + indexEntryRepository.save(event.getRelatedTo()); + } else { + logger.info("Repository not found in metadata for {}", clientUrl); + event.getRelatedTo().setState(IndexEntryState.Invalid); + event.getMetadataRetrieval().setError("Repository not found in metadata"); + } + } catch (Exception e) { + logger.info("Cannot parse metadata for {}", clientUrl); + event.getRelatedTo().setState(IndexEntryState.Invalid); + event.getMetadataRetrieval().setError("Cannot parse metadata"); + } + } else { + event.getRelatedTo().setState(IndexEntryState.Unreachable); + logger.info("Cannot retrieve metadata for {}: {}", clientUrl, ex.getError()); + } + } else { + logger.info("Rate limit reached for {} (skipping metadata retrieval)", clientUrl); + event.getMetadataRetrieval().setError("Rate limit reached (skipping)"); + } + event.getRelatedTo().setLastRetrievalTime(Instant.now()); + event.finish(); + event = eventRepository.save(event); + indexEntryRepository.save(event.getRelatedTo()); + webhookService.triggerWebhooks(event); + } + + @Async + @RequiredEnabledIndexFeature + public void triggerMetadataRetrieval(Event triggerEvent) { + logger.info("Initiating metadata retrieval triggered by {}", triggerEvent.getUuid()); + Iterable<Event> events = MetadataRetrievalUtils.prepareEvents(triggerEvent, indexEntryService); + for (Event event : events) { + logger.info("Triggering metadata retrieval for {} as {}", event.getRelatedTo().getClientUrl(), + event.getUuid()); + try { + processMetadataRetrieval(event); + } catch (Exception e) { + logger.error("Failed to retrieve metadata: {}", e.getMessage()); + } + } + logger.info("Finished metadata retrieval triggered by {}", triggerEvent.getUuid()); + } + + private void resumeUnfinishedEvents() { + logger.info("Resuming unfinished events"); + for (Event event : eventRepository.getAllByFinishedIsNull()) { + logger.info("Resuming event {}", event.getUuid()); + + try { + if (event.getType() == EventType.MetadataRetrieval) { + processMetadataRetrieval(event); + } else if (event.getType() == EventType.WebhookTrigger) { + webhookService.processWebhookTrigger(event); + } else { + logger.warn("Unknown event type {} ({})", event.getUuid(), event.getType()); + } + } catch (Exception e) { + logger.error("Failed to resume event {}: {}", event.getUuid(), e.getMessage()); + } + } + logger.info("Finished unfinished events"); + } + + @PostConstruct + public void startResumeUnfinishedEvents() { + executor.submit(this::resumeUnfinishedEvents); + } + + @RequiredEnabledIndexFeature + public Event acceptAdminTrigger(HttpServletRequest request, PingDTO pingDTO) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Event event = eventMapper.toAdminTriggerEvent(request, authentication, pingDTO.getClientUrl(), utilityService.getRemoteAddr(request)); + IndexEntry entry = indexEntryService.storeEntry(pingDTO); + event.setRelatedTo(entry); + event.finish(); + return eventRepository.save(event); + } + + @RequiredEnabledIndexFeature + public Event acceptAdminTriggerAll(HttpServletRequest request) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Event event = eventMapper.toAdminTriggerEvent(request, authentication, null, utilityService.getRemoteAddr(request)); + event.finish(); + return eventRepository.save(event); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/event/IncomingPingUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/index/event/IncomingPingUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..762c39f41ca74cd0ff72437bbcd7847f12962825 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/event/IncomingPingUtils.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.event; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.IncomingPing; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeDirection; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.util.*; + +@Service +public class IncomingPingUtils { + + private static final Integer VERSION = 1; + + @Autowired + private ObjectMapper objectMapper; + + public Event prepareEvent(PingDTO reqDto, HttpServletRequest request, String remoteAddr) { + var incomingPing = new IncomingPing(); + var ex = new Exchange(ExchangeDirection.INCOMING, remoteAddr); + incomingPing.setExchange(ex); + + ex.getRequest().setHeaders(getHeaders(request)); + ex.getRequest().setFromHttpServletRequest(request); + try { + ex.getRequest().setBody(objectMapper.writeValueAsString(reqDto)); + } catch (JsonProcessingException e) { + ex.getRequest().setBody(null); + } + + return new Event(VERSION, incomingPing); + } + + private Map<String, List<String>> getHeaders(HttpServletRequest request) { + Map<String, List<String>> map = new HashMap<>(); + Iterator<String> requestI = request.getHeaderNames().asIterator(); + while (requestI.hasNext()) { + String headerName = requestI.next(); + List<String> headerValues = new ArrayList<>(); + Iterator<String> headerI = request.getHeaders(headerName).asIterator(); + while (headerI.hasNext()) { + headerValues.add(headerI.next()); + } + map.put(headerName, headerValues); + } + return map; + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/event/MetadataRetrievalUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/index/event/MetadataRetrievalUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..b4ee686a8a110e3e741eddced7a5be6410910a83 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/event/MetadataRetrievalUtils.java @@ -0,0 +1,190 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.event; + +import nl.dtls.fairdatapoint.entity.index.entry.RepositoryMetadata; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.EventType; +import nl.dtls.fairdatapoint.entity.index.event.MetadataRetrieval; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeDirection; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeState; +import nl.dtls.fairdatapoint.service.index.entry.IndexEntryService; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.eclipse.rdf4j.rio.RDFParser; +import org.eclipse.rdf4j.rio.Rio; +import org.eclipse.rdf4j.rio.helpers.StatementCollector; +import org.springframework.http.HttpHeaders; + +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Map; +import java.util.Optional; + +public class MetadataRetrievalUtils { + + private static final EventType EVENT_TYPE = EventType.MetadataRetrieval; + + private static final Integer VERSION = 1; + + private static final IRI REPOSITORY = SimpleValueFactory.getInstance().createIRI("http://www.re3data" + + ".org/schema/3-0#Repository"); + + private static final IRI COUNTRY = SimpleValueFactory.getInstance().createIRI("http://www.re3data" + + ".org/schema/3-0#institutionCountry"); + + private static final Map<IRI, String> MAPPING = Map.of( + DCTERMS.TITLE, "title", + DCTERMS.DESCRIPTION, "description", + DCTERMS.HAS_VERSION, "version", + DCTERMS.PUBLISHER, "publisher", + COUNTRY, "country" + ); + + private static final HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.ALWAYS) + .build(); + + public static boolean shouldRetrieve(Event triggerEvent, Duration rateLimitWait) { + if (triggerEvent.getRelatedTo() == null) { + return false; + } + Instant lastRetrieval = triggerEvent.getRelatedTo().getLastRetrievalTime(); + if (lastRetrieval == null) { + return true; + } + return Duration.between(lastRetrieval, Instant.now()).compareTo(rateLimitWait) > 0; + } + + public static Iterable<Event> prepareEvents(Event triggerEvent, IndexEntryService indexEntryService) { + ArrayList<Event> events = new ArrayList<>(); + if (triggerEvent.getType() == EventType.IncomingPing) { + events.add(new Event(VERSION, triggerEvent, triggerEvent.getRelatedTo(), new MetadataRetrieval())); + } else if (triggerEvent.getType() == EventType.AdminTrigger) { + if (triggerEvent.getAdminTrigger().getClientUrl() == null) { + indexEntryService.getAllEntries().forEach( + entry -> events.add(new Event(VERSION, triggerEvent, entry, new MetadataRetrieval())) + ); + } else { + events.add(new Event(VERSION, triggerEvent, triggerEvent.getRelatedTo(), new MetadataRetrieval())); + } + } + return events; + } + + public static void retrieveRepositoryMetadata(Event event, Duration timeout) { + if (event.getType() != EVENT_TYPE) { + throw new IllegalArgumentException("Invalid event type"); + } + var ex = new Exchange(ExchangeDirection.OUTGOING); + event.getMetadataRetrieval().setExchange(ex); + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(event.getRelatedTo().getClientUrl())) + .timeout(timeout) + .header(HttpHeaders.ACCEPT, RDFFormat.TURTLE.getDefaultMIMEType()) + .GET().build(); + ex.getRequest().setFromHttpRequest(request); + ex.setState(ExchangeState.Requested); + HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); + ex.getResponse().setFromHttpResponse(response); + ex.setState(ExchangeState.Retrieved); + } catch (InterruptedException e) { + ex.setState(ExchangeState.Timeout); + ex.setError("Timeout"); + } catch (IllegalArgumentException e) { + ex.setState(ExchangeState.Failed); + ex.setError("Invalid URI: " + e.getMessage()); + } catch (IOException e) { + ex.setState(ExchangeState.Failed); + ex.setError("IO error: " + e.getMessage()); + } + } + + public static Optional<RepositoryMetadata> parseRepositoryMetadata(String metadata) throws IOException { + RDFParser parser = Rio.createParser(RDFFormat.TURTLE); + StatementCollector collector = new StatementCollector(); + parser.setRDFHandler(collector); + + parser.parse(new StringReader(metadata), String.valueOf(StandardCharsets.UTF_8)); + ArrayList<Statement> statements = new ArrayList<>(collector.getStatements()); + + return findRepository(statements).map(repository -> extractRepositoryMetadata(statements, repository)); + } + + private static RepositoryMetadata extractRepositoryMetadata(ArrayList<Statement> statements, Resource repository) { + var repositoryMetadata = new RepositoryMetadata(); + repositoryMetadata.setMetadataVersion(VERSION); + repositoryMetadata.setRepositoryUri(repository.toString()); + + Value publisher = null; + for (Statement st : statements) { + if (st.getSubject().equals(repository)) { + if (MAPPING.containsKey(st.getPredicate())) { + repositoryMetadata.getMetadata().put(MAPPING.get(st.getPredicate()), st.getObject().stringValue()); + } + if (st.getPredicate().equals(DCTERMS.PUBLISHER)) { + publisher = st.getObject(); + } + } + } + + if (publisher != null) { + for (Statement st : statements) { + if (st.getSubject().equals(publisher)) { + if (st.getPredicate().equals(FOAF.NAME)) { + repositoryMetadata.getMetadata().put("publisherName", st.getObject().stringValue()); + } + } + } + } + + return repositoryMetadata; + } + + private static Optional<Resource> findRepository(ArrayList<Statement> statements) { + for (Statement st : statements) { + if (st.getPredicate().equals(RDF.TYPE) && st.getObject().equals(REPOSITORY)) { + return Optional.of(st.getSubject()); + } + } + return Optional.empty(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterService.java b/src/main/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterService.java new file mode 100644 index 0000000000000000000000000000000000000000..19e08e8a47385092b9cf37b19a63897c17ec1257 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterService.java @@ -0,0 +1,157 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.harvester; + +import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.vocabulary.LDP; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.rio.RDFFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; +import org.springframework.web.client.RestTemplate; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static java.util.Optional.ofNullable; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getChildren; +import static nl.dtls.fairdatapoint.util.HttpUtil.getRdfContentType; +import static nl.dtls.fairdatapoint.util.RdfIOUtil.read; +import static nl.dtls.fairdatapoint.util.RdfIOUtil.readFile; +import static nl.dtls.fairdatapoint.util.RdfUtil.getObjectsBy; +import static nl.dtls.fairdatapoint.util.RdfUtil.getSubjectsBy; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +@Service +@Log4j2 +public class HarvesterService { + + private static final String DEFAULT_NAVIGATION_SHACL = "defaultNavigationShacl.ttl"; + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private GenericMetadataRepository genericMetadataRepository; + + @Async + public void harvest(String clientUrl) throws MetadataRepositoryException { + log.info(format("Start harvesting '%s'", clientUrl)); + + // 1. Get navigation relationships + List<IRI> navigationRelationships = getNavigationRelationships(clientUrl); + + // 2. Harvest data + Map<String, Model> result = visitNode(clientUrl, navigationRelationships, new HashMap<>()); + + // 3. Store data + for (Map.Entry<String, Model> item : result.entrySet()) { + genericMetadataRepository.save(new ArrayList<>(item.getValue()), i(item.getKey())); + } + + log.info(format("Harvesting for '%s' completed", clientUrl)); + } + + private List<IRI> getNavigationRelationships(String uri) { + Model model = readFile(DEFAULT_NAVIGATION_SHACL, "http://fairdatapoint.org"); + return getObjectsBy(model, null, "http://www.w3.org/ns/shacl#path") + .stream() + .map(i -> i(i.stringValue())) + .distinct() + .collect(Collectors.toList()); + } + + private Map<String, Model> visitNode(String uri, List<IRI> relationships, Map<String, Model> nodes) { + try { + Model model = makeRequest(uri); + nodes.put(uri, model); + + List<Resource> containers = getSubjectsBy(model, RDF.TYPE, LDP.DIRECT_CONTAINER); + if (containers.size() > 0) { + // Get children through LDP links + for (Value container : containers) { + for (Value child : getObjectsBy(model, i(container.stringValue()), LDP.CONTAINS)) { + if (!nodes.containsKey(child.stringValue())) { + nodes = visitNode(child.stringValue(), relationships, nodes); + } + } + } + } else { + // Get children through default navigation SHACL + for (IRI relationship : relationships) { + List<IRI> children = getChildren(model, relationship); + for (IRI child : children) { + if (!nodes.containsKey(child.stringValue())) { + nodes = visitNode(child.stringValue(), relationships, nodes); + } + } + } + } + + return nodes; + } catch (HttpClientErrorException ex) { + return nodes; + } + } + + private Model makeRequest(String uri) { + log.info(format("Making request to '%s'", uri)); + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(List.of(MediaType.parseMediaType(RDFFormat.TURTLE.getDefaultMIMEType()))); + HttpEntity<Void> entity = new HttpEntity<>(null, headers); + try { + ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class); + if (!response.getStatusCode().is2xxSuccessful()) { + log.info(format("Request to '%s' failed", uri)); + throw new HttpClientErrorException(response.getStatusCode()); + } + RDFFormat rdfContentType = getRdfContentType(response.getHeaders().getContentType().getType()); + log.info(format("Request to '%s' successfully received", uri)); + Model result = read(response.getBody(), uri, rdfContentType); + log.info(format("Request to '%s' successfully parsed", uri)); + return result; + } catch (RestClientException e) { + log.info(format("Request to '%s' failed", uri)); + throw new HttpClientErrorException( + HttpStatus.BAD_GATEWAY, + ofNullable(e.getMessage()).orElse("HTTP request failed to proceed") + ); + } + } + + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..b2a3ed2263cf6313c11f187fcb77af8efa743d82 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsMapper.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.settings; + +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsPingDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsRetrievalDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsUpdateDTO; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsPing; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsRetrieval; +import org.springframework.stereotype.Service; + +import java.time.Duration; + +@Service +public class IndexSettingsMapper { + + private IndexSettingsPingDTO toPingDTO(IndexSettingsPing indexSettingsPing) { + return new IndexSettingsPingDTO( + indexSettingsPing.getValidDuration().toString(), + indexSettingsPing.getRateLimitDuration().toString(), + indexSettingsPing.getRateLimitHits(), + indexSettingsPing.getDenyList() + ); + } + + private IndexSettingsRetrievalDTO toRetrievalDTO(IndexSettingsRetrieval indexSettingsRetrieval) { + return new IndexSettingsRetrievalDTO( + indexSettingsRetrieval.getRateLimitWait().toString(), + indexSettingsRetrieval.getTimeout().toString() + ); + } + + public IndexSettingsDTO toDTO(IndexSettings indexSettings) { + return new IndexSettingsDTO( + toRetrievalDTO(indexSettings.getRetrieval()), + toPingDTO(indexSettings.getPing()), + indexSettings.equals(IndexSettings.getDefault()) + ); + } + + public IndexSettingsUpdateDTO toUpdateDTO(IndexSettings indexSettings) { + return new IndexSettingsUpdateDTO( + toRetrievalDTO(indexSettings.getRetrieval()), + toPingDTO(indexSettings.getPing()) + ); + } + + private IndexSettingsPing fromDTO(IndexSettingsPingDTO dto, IndexSettingsPing ping) { + return + ping + .toBuilder() + .validDuration(Duration.parse(dto.getValidDuration())) + .rateLimitDuration(Duration.parse(dto.getRateLimitDuration())) + .rateLimitHits(dto.getRateLimitHits()) + .denyList(dto.getDenyList()) + .build(); + } + + private IndexSettingsRetrieval fromDTO(IndexSettingsRetrievalDTO dto, IndexSettingsRetrieval retrieval) { + return + retrieval + .toBuilder() + .rateLimitWait(Duration.parse(dto.getRateLimitWait())) + .timeout(Duration.parse(dto.getTimeout())) + .build(); + } + + public IndexSettings fromUpdateDTO(IndexSettingsUpdateDTO dto, IndexSettings indexSettings) { + return + indexSettings + .toBuilder() + .ping(fromDTO(dto.getPing(), indexSettings.getPing())) + .retrieval(fromDTO(dto.getRetrieval(), indexSettings.getRetrieval())) + .build(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsService.java b/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsService.java new file mode 100644 index 0000000000000000000000000000000000000000..940c105f0dd941e82f49f7b82f764d6a0d29eeda --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/settings/IndexSettingsService.java @@ -0,0 +1,72 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.settings; + +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsUpdateDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexSettingsRepository; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import nl.dtls.fairdatapoint.service.index.common.RequiredEnabledIndexFeature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.regex.Pattern; + +@Service +@Slf4j +public class IndexSettingsService { + + @Autowired + private IndexSettingsRepository repository; + + @Autowired + private IndexSettingsMapper mapper; + + @RequiredEnabledIndexFeature + public boolean isPingDenied(PingDTO ping) { + log.info("Checking if ping.clientUrl is on deny list: " + ping.getClientUrl()); + return getOrDefaults().getPing().getDenyList().parallelStream().anyMatch(pattern -> Pattern.matches(pattern, ping.getClientUrl())); + } + + @RequiredEnabledIndexFeature + public IndexSettings getOrDefaults() { + return repository.findFirstBy().orElse(IndexSettings.getDefault()); + } + + @RequiredEnabledIndexFeature + public IndexSettingsDTO getCurrentSettings() { + return mapper.toDTO(getOrDefaults()); + } + + @RequiredEnabledIndexFeature + public IndexSettingsDTO updateSettings(IndexSettingsUpdateDTO dto) { + return mapper.toDTO(repository.save(mapper.fromUpdateDTO(dto, getOrDefaults()))); + } + + @RequiredEnabledIndexFeature + public IndexSettingsDTO resetSettings() { + return updateSettings(mapper.toUpdateDTO(IndexSettings.getDefault())); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5b888d891eb9f10d0983234fb1f28589ae0d4757 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookMapper.java @@ -0,0 +1,68 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.webhook; + +import nl.dtls.fairdatapoint.api.dto.index.webhook.WebhookPayloadDTO; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.WebhookPing; +import nl.dtls.fairdatapoint.entity.index.event.WebhookTrigger; +import nl.dtls.fairdatapoint.entity.index.webhook.Webhook; +import nl.dtls.fairdatapoint.entity.index.webhook.WebhookEvent; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.time.Instant; +import java.util.UUID; + +@Service +public class WebhookMapper { + + private static final Integer VERSION = 1; + + public Event toTriggerEvent(Webhook webhook, WebhookEvent webhookEvent, Event triggerEvent) { + var webhookTrigger = new WebhookTrigger(); + webhookTrigger.setWebhook(webhook); + webhookTrigger.setMatchedEvent(webhookEvent); + return new Event(VERSION, webhookTrigger, triggerEvent); + } + + public Event toPingEvent(HttpServletRequest request, Authentication authentication, UUID webhookUuid, String remoteAddr) { + var webhookPing = new WebhookPing(); + webhookPing.setWebhookUuid(webhookUuid); + webhookPing.setRemoteAddr(remoteAddr); + webhookPing.setTokenName(authentication.getName()); + return new Event(VERSION, webhookPing); + } + + public WebhookPayloadDTO toWebhookPayloadDTO(Event event) { + WebhookPayloadDTO webhookPayload = new WebhookPayloadDTO(); + webhookPayload.setEvent(event.getWebhookTrigger().getMatchedEvent()); + webhookPayload.setClientUrl(event.getRelatedTo().getClientUrl()); + webhookPayload.setSecret(event.getWebhookTrigger().getWebhook().getSecret()); + webhookPayload.setUuid(event.getUuid().toString()); + webhookPayload.setTimestamp(Instant.now().toString()); + return webhookPayload; + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookService.java b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookService.java new file mode 100644 index 0000000000000000000000000000000000000000..ab1ea736a24d6b477df7795dccba3218452fe884 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookService.java @@ -0,0 +1,149 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.webhook; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import nl.dtls.fairdatapoint.api.dto.index.webhook.WebhookPayloadDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.EventRepository; +import nl.dtls.fairdatapoint.database.mongo.repository.WebhookRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.webhook.Webhook; +import nl.dtls.fairdatapoint.entity.index.webhook.WebhookEvent; +import nl.dtls.fairdatapoint.service.UtilityService; +import nl.dtls.fairdatapoint.service.index.common.RequiredEnabledIndexFeature; +import nl.dtls.fairdatapoint.service.index.settings.IndexSettingsService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpServletRequest; +import java.security.NoSuchAlgorithmException; +import java.util.Optional; +import java.util.UUID; + + +@Service +public class WebhookService { + private static final Logger logger = LoggerFactory.getLogger(WebhookService.class); + + @Autowired + private WebhookMapper webhookMapper; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + WebhookRepository webhookRepository; + + @Autowired + EventRepository eventRepository; + + @Autowired + private IndexSettingsService indexSettingsService; + + @Autowired + private UtilityService utilityService; + + private static final String SECRET_PLACEHOLDER = "*** HIDDEN ***"; + + @RequiredEnabledIndexFeature + public void processWebhookTrigger(Event event) { + var retrievalSettings = indexSettingsService.getOrDefaults().getRetrieval(); + event.execute(); + eventRepository.save(event); + WebhookPayloadDTO webhookPayload = webhookMapper.toWebhookPayloadDTO(event); + try { + String payloadWithSecret = objectMapper.writeValueAsString(webhookPayload); + String signature = WebhookUtils.computeHashSignature(payloadWithSecret); + webhookPayload.setSecret(SECRET_PLACEHOLDER); + String payloadWithoutSecret = objectMapper.writeValueAsString(webhookPayload); + WebhookUtils.postWebhook(event, retrievalSettings.getTimeout(), payloadWithoutSecret, signature); + } catch (JsonProcessingException e) { + logger.error("Failed to convert webhook payload to string"); + } catch (NoSuchAlgorithmException e) { + logger.error("Could not compute SHA-1 signature of payload"); + } + event.finish(); + eventRepository.save(event); + } + + @Async + @RequiredEnabledIndexFeature + public void triggerWebhook(Webhook webhook, WebhookEvent webhookEvent, Event triggerEvent) { + Event event = webhookMapper.toTriggerEvent(webhook, webhookEvent, triggerEvent); + processWebhookTrigger(event); + } + + @Async + @RequiredEnabledIndexFeature + public void triggerWebhooks(WebhookEvent webhookEvent, Event triggerEvent) { + logger.info("Triggered webhook event {} by event {}", webhookEvent, triggerEvent.getUuid()); + WebhookUtils.filterMatching(webhookRepository.findAll(), webhookEvent, triggerEvent).forEach(webhook -> triggerWebhook(webhook, webhookEvent, triggerEvent)); + } + + @RequiredEnabledIndexFeature + public Event handleWebhookPing(HttpServletRequest request, UUID webhookUuid) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + Optional<Webhook> webhook = webhookRepository.findByUuid(webhookUuid); + Event event = eventRepository.save(webhookMapper.toPingEvent(request, authentication, webhookUuid, utilityService.getRemoteAddr(request))); + if (webhook.isEmpty()) { + throw new ResourceNotFoundException("There is no such webhook: " + webhookUuid); + } + return event; + } + + @Async + @RequiredEnabledIndexFeature + public void triggerWebhooks(Event triggerEvent) { + switch (triggerEvent.getType()) { + case AdminTrigger: + triggerWebhooks(WebhookEvent.AdminTrigger, triggerEvent); + break; + case IncomingPing: + triggerWebhooks(WebhookEvent.IncomingPing, triggerEvent); + if (triggerEvent.getIncomingPing().getNewEntry()) { + triggerWebhooks(WebhookEvent.NewEntry, triggerEvent); + } + break; + case MetadataRetrieval: + switch (triggerEvent.getRelatedTo().getState()) { + case Valid -> triggerWebhooks(WebhookEvent.EntryValid, triggerEvent); + case Invalid -> triggerWebhooks(WebhookEvent.EntryInvalid, triggerEvent); + case Unreachable -> triggerWebhooks(WebhookEvent.EntryUnreachable, triggerEvent); + default -> logger.warn("Invalid state of MetadataRetrieval: {}", triggerEvent.getRelatedTo().getState()); + } + break; + case WebhookPing: + triggerWebhooks(WebhookEvent.WebhookPing, triggerEvent); + break; + default: + logger.warn("Invalid event type for webhook trigger: {}", triggerEvent.getType()); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..ae263aa5164d6d28fe7778093e0d2194153c58bb --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/index/webhook/WebhookUtils.java @@ -0,0 +1,101 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.webhook; + +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.http.Exchange; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeDirection; +import nl.dtls.fairdatapoint.entity.index.http.ExchangeState; +import nl.dtls.fairdatapoint.entity.index.webhook.Webhook; +import nl.dtls.fairdatapoint.entity.index.webhook.WebhookEvent; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; + +import java.io.IOException; +import java.math.BigInteger; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.time.Duration; +import java.util.List; +import java.util.stream.Stream; + +public class WebhookUtils { + + private static final HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.ALWAYS) + .build(); + + private static boolean webhookMatches(Webhook webhook, WebhookEvent webhookEvent, Event triggerEvent) { + boolean matchEvent = webhook.isAllEvents() || webhook.getEvents().contains(webhookEvent); + boolean matchEntry = + webhook.isAllEntries() || triggerEvent.getRelatedTo() == null || webhook.getEntries().contains(triggerEvent.getRelatedTo().getClientUrl()); + return matchEvent && matchEntry && webhook.isEnabled(); + } + + public static Stream<Webhook> filterMatching(List<Webhook> webhooks, WebhookEvent webhookEvent, + Event triggerEvent) { + return webhooks.parallelStream().filter(webhook -> WebhookUtils.webhookMatches(webhook, webhookEvent, + triggerEvent)); + } + + public static String computeHashSignature(String value) throws NoSuchAlgorithmException { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + digest.reset(); + digest.update(value.getBytes(StandardCharsets.UTF_8)); + return String.format("sha1=%040x", new BigInteger(1, digest.digest())); + } + + public static void postWebhook(Event event, Duration timeout, String payload, String signature) { + var ex = new Exchange(ExchangeDirection.OUTGOING); + event.getWebhookTrigger().setExchange(ex); + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(event.getWebhookTrigger().getWebhook().getPayloadUrl())) + .timeout(timeout) + .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON.toString()) + .header("X-Signature", signature) + .POST(HttpRequest.BodyPublishers.ofString(payload)) + .build(); + ex.getRequest().setFromHttpRequest(request); + ex.setState(ExchangeState.Requested); + HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); + ex.getResponse().setFromHttpResponse(response); + ex.setState(ExchangeState.Retrieved); + } catch (InterruptedException e) { + ex.setState(ExchangeState.Timeout); + ex.setError("Timeout"); + } catch (IllegalArgumentException e) { + ex.setState(ExchangeState.Failed); + ex.setError("Invalid URI: " + e.getMessage()); + } catch (IOException e) { + ex.setState(ExchangeState.Failed); + ex.setError("IO error: " + e.getMessage()); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/jwt/JwtService.java b/src/main/java/nl/dtls/fairdatapoint/service/jwt/JwtService.java index 5784ab17364f66eee9d6c2c5c5fc909161b6b7ec..a6449c931af33f1413509258bf8ea57e75e588a3 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/jwt/JwtService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/jwt/JwtService.java @@ -30,7 +30,6 @@ import nl.dtls.fairdatapoint.entity.user.User; import nl.dtls.fairdatapoint.service.security.MongoAuthenticationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; @@ -38,14 +37,12 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import javax.servlet.http.HttpServletRequest; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; import java.util.Base64; import java.util.Date; import java.util.Optional; -import static java.util.Optional.of; -import static java.util.Optional.ofNullable; - @Component public class JwtService { @@ -64,9 +61,15 @@ public class JwtService { @Autowired private MongoAuthenticationService mongoAuthenticationService; + private JwtParser parser; + + private Key key; + @PostConstruct protected void init() { secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes()); + key = new SecretKeySpec(secretKey.getBytes(), SignatureAlgorithm.HS256.getJcaName()); + parser = Jwts.parserBuilder().setSigningKey(key).build(); } public String createToken(AuthDTO authDTO) { @@ -85,21 +88,15 @@ public class JwtService { } public String getUserUuid(String token) { - return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject(); - } - - public String resolveToken(HttpServletRequest req) { - return ofNullable(req.getHeader(HttpHeaders.AUTHORIZATION)) - .filter(h -> h.startsWith("Bearer ")) - .flatMap(h -> of(h.substring(7))) - .orElse(null); + return parser.parseClaimsJws(token).getBody().getSubject(); } public boolean validateToken(String token) { try { - Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); + Jws<Claims> claims = parser.parseClaimsJws(token); return !claims.getBody().getExpiration().before(new Date()); } catch (JwtException | IllegalArgumentException e) { + System.out.println(e); throw new UnauthorizedException("Expired or invalid JWT token"); } } @@ -112,7 +109,7 @@ public class JwtService { .setClaims(claims) .setIssuedAt(now) .setExpiration(validity) - .signWith(SignatureAlgorithm.HS256, secretKey) + .signWith(key) .compact(); } -} \ No newline at end of file +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/label/LabelService.java b/src/main/java/nl/dtls/fairdatapoint/service/label/LabelService.java new file mode 100644 index 0000000000000000000000000000000000000000..e71d664358c54ab86744722a768e2763a2ea0677 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/label/LabelService.java @@ -0,0 +1,91 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.label; + +import static java.util.function.Predicate.isEqual; +import static nl.dtls.fairdatapoint.config.CacheConfig.LABEL_CACHE; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import com.github.fairdevkit.rdf.resolver.api.ResourceResolver; +import com.github.fairdevkit.rdf.resolver.core.ContentNegotiationStrategy; +import com.github.fairdevkit.rdf.resolver.core.CoreResourceResolver; +import com.github.fairdevkit.rdf.resolver.core.PathExtensionStrategy; +import java.util.Optional; + +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.api.dto.label.LabelDTO; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Literal; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.util.Models; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.eclipse.rdf4j.model.vocabulary.SKOS; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@CacheConfig(cacheNames = LABEL_CACHE) +public class LabelService { + private final ResourceResolver resolver; + + public LabelService() { + var resolver = new CoreResourceResolver(); + resolver.register(new ContentNegotiationStrategy()); + resolver.register(new PathExtensionStrategy()); + + this.resolver = resolver; + } + + @Cacheable + public Optional<LabelDTO> getLabel(String iri, String lang) { + try { + var subject = i(iri); + + return resolver.resolveResource(iri) + .flatMap(model -> getPropertyLiteralByLanguage(model, subject, SKOS.PREF_LABEL, lang) + .or(() -> getPropertyLiteralWithoutLanguage(model, subject, SKOS.PREF_LABEL)) + .or(() -> getPropertyLiteralByLanguage(model, subject, RDFS.LABEL, lang)) + .or(() -> getPropertyLiteralWithoutLanguage(model, subject, RDFS.LABEL)) + ) + .map(literal -> new LabelDTO(literal.getLabel(), literal.getLanguage().orElse(""))); + } catch (Exception e) { + log.warn("Unable to resolve label for {} (lang {}): {}", iri, lang, e.getMessage()); + return Optional.empty(); + } + } + + private static Optional<Literal> getPropertyLiteralByLanguage(Model model, IRI subject, IRI predicate, String lang) { + return Models.getPropertyLiterals(model, subject, predicate) + .stream() + .filter(literal -> literal.getLanguage().filter(isEqual(lang)).isPresent()) + .findFirst(); + } + + private static Optional<Literal> getPropertyLiteralWithoutLanguage(Model model, IRI subject, IRI predicate) { + return Models.getPropertyLiterals(model, subject, predicate) + .stream() + .filter(literal -> literal.getLanguage().isEmpty()) + .findFirst(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/membership/MembershipService.java b/src/main/java/nl/dtls/fairdatapoint/service/membership/MembershipService.java index 7c0c10020639abb5d0f11d9613f037c65c64d4ce..e42b03cad4d255d226b6804d3ca08532dddda27e 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/membership/MembershipService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/membership/MembershipService.java @@ -25,6 +25,7 @@ package nl.dtls.fairdatapoint.service.membership; import nl.dtls.fairdatapoint.api.dto.membership.MembershipDTO; import nl.dtls.fairdatapoint.database.mongo.repository.MembershipRepository; import nl.dtls.fairdatapoint.entity.membership.Membership; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -49,4 +50,50 @@ public class MembershipService { .map(membershipMapper::toDTO) .collect(toList()); } + + public void addToMembership(ResourceDefinition resourceDefinition) { + String rdUuid = resourceDefinition.getUuid(); + + // Add to owner + Membership owner = membershipRepository.findByUuid("49f2bcfd-ef0a-4a3a-a1a3-0fc72a6892a8").get(); + addEntityIfMissing(owner, rdUuid); + membershipRepository.save(owner); + + // Add to data provider + if (resourceDefinition.getUrlPrefix().equals("catalog")) { + Membership dataProvider = membershipRepository.findByUuid("87a2d984-7db2-43f6-805c-6b0040afead5").get(); + addEntityIfMissing(dataProvider, rdUuid); + membershipRepository.save(dataProvider); + } + } + + public void removeFromMembership(ResourceDefinition resourceDefinition) { + String rdUuid = resourceDefinition.getUuid(); + + // Add to owner + Membership owner = membershipRepository.findByUuid("49f2bcfd-ef0a-4a3a-a1a3-0fc72a6892a8").get(); + removeEntityIfPresent(owner, rdUuid); + membershipRepository.save(owner); + + // Add to data provider + if (resourceDefinition.getUrlPrefix().equals("catalog")) { + Membership dataProvider = membershipRepository.findByUuid("87a2d984-7db2-43f6-805c-6b0040afead5").get(); + removeEntityIfPresent(dataProvider, rdUuid); + membershipRepository.save(dataProvider); + } + } + + private void addEntityIfMissing(Membership membership, String rdUuid) { + if (!membership.getAllowedEntities().contains(rdUuid)) { + membership.getAllowedEntities().add(rdUuid); + } + } + + private void removeEntityIfPresent(Membership membership, String rdUuid) { + int index = membership.getAllowedEntities().indexOf(rdUuid); + if (index != -1) { + membership.getAllowedEntities().remove(index); + } + } + } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataService.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataService.java index 50921e8c444df186057b38497496399617762761..2001c5a5712f2e20475a737392a62d27fdcedd83 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataService.java @@ -25,6 +25,7 @@ package nl.dtls.fairdatapoint.service.metadata.catalog; import lombok.extern.slf4j.Slf4j; import nl.dtls.fairdatapoint.database.rdf.repository.catalog.CatalogMetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.service.metadata.common.AbstractMetadataService; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; import org.eclipse.rdf4j.model.IRI; @@ -34,9 +35,8 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import javax.annotation.Nonnull; -import java.util.*; +import java.util.List; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getThemeTaxonomies; import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.setThemeTaxonomies; @Service("catalogMetadataService") @@ -52,14 +52,23 @@ public class CatalogMetadataService extends AbstractMetadataService { Model catalog = super.retrieve(uri); try { List<IRI> themes = metadataRepository.getDatasetThemesForCatalog(uri); - Set<IRI> set = new TreeSet<>(Comparator.comparing(IRI::toString)); - set.addAll(getThemeTaxonomies(catalog)); - set.addAll(themes); - setThemeTaxonomies(catalog, uri, new ArrayList<>(set)); + setThemeTaxonomies(catalog, uri, themes); } catch (MetadataRepositoryException ex) { log.error("Error retrieving the metadata"); throw new MetadataServiceException(ex.getMessage()); } return catalog; } + + @Override + public Model store(Model metadata, IRI uri, ResourceDefinition resourceDefinition) throws MetadataServiceException { + setThemeTaxonomies(metadata, uri, null); + return super.store(metadata, uri, resourceDefinition); + } + + @Override + public Model update(Model metadata, IRI uri, ResourceDefinition rd) throws MetadataServiceException { + setThemeTaxonomies(metadata, uri, null); + return super.update(metadata, uri, rd); + } } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/common/AbstractMetadataService.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/common/AbstractMetadataService.java index 37e0fee01afc09f2aea230ad8abc91eb7527aa86..43cc9729e1da4501bdd63ed454a7a074f125f024 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadata/common/AbstractMetadataService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/common/AbstractMetadataService.java @@ -22,20 +22,22 @@ */ package nl.dtls.fairdatapoint.service.metadata.common; -import com.google.common.base.Preconditions; import lombok.extern.slf4j.Slf4j; -import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; import nl.dtls.fairdatapoint.database.rdf.repository.common.MetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; import nl.dtls.fairdatapoint.entity.metadata.Metadata; import nl.dtls.fairdatapoint.entity.metadata.MetadataGetter; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; import nl.dtls.fairdatapoint.entity.user.User; import nl.dtls.fairdatapoint.service.member.MemberService; import nl.dtls.fairdatapoint.service.metadata.enhance.MetadataEnhancer; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; import nl.dtls.fairdatapoint.service.metadata.validator.MetadataValidator; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; import nl.dtls.fairdatapoint.service.user.CurrentUserService; import nl.dtls.fairdatapoint.vocabulary.FDP; @@ -47,13 +49,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.access.prepost.PreAuthorize; -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.time.OffsetDateTime; +import java.util.*; import java.util.stream.Collectors; +import static java.lang.String.format; import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getChildren; import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getParent; import static nl.dtls.fairdatapoint.util.ThrowingFunction.suppress; @@ -73,31 +73,34 @@ public abstract class AbstractMetadataService implements MetadataService { private CurrentUserService currentUserService; @Autowired - protected ResourceDefinitionRepository resourceDefinitionRepository; + protected MetadataEnhancer metadataEnhancer; @Autowired - protected ResourceDefinitionService resourceDefinitionService; + protected MetadataValidator metadataValidator; @Autowired - protected MetadataEnhancer metadataEnhancer; + private ResourceDefinitionCache resourceDefinitionCache; @Autowired - protected MetadataValidator metadataValidator; + private MetadataStateService metadataStateService; + + @Autowired + private ResourceDefinitionService resourceDefinitionService; @Override public Model retrieve(IRI uri) throws MetadataServiceException, ResourceNotFoundException { - Model metadata = new LinkedHashModel(); try { - Preconditions.checkNotNull(uri, "Resource uri not be null."); - List<Statement> statements = metadataRepository.retrieveResource(uri); + // 1. Get metadata + List<Statement> statements = metadataRepository.find(uri); if (statements.isEmpty()) { - String msg = ("No metadata found for the uri : " + uri); - throw new ResourceNotFoundException(msg); + throw new ResourceNotFoundException(format("No metadata found for the uri '%s'", uri)); } + + // 2. Convert to model + Model metadata = new LinkedHashModel(); metadata.addAll(statements); return metadata; } catch (MetadataRepositoryException ex) { - log.error("Error retrieving the metadata"); throw new MetadataServiceException(ex.getMessage()); } } @@ -116,12 +119,12 @@ public abstract class AbstractMetadataService implements MetadataService { try { metadataValidator.validate(metadata, uri, resourceDefinition); metadataEnhancer.enhance(metadata, uri, resourceDefinition); - metadataRepository.storeStatements(new ArrayList<>(metadata), uri); + metadataRepository.save(new ArrayList<>(metadata), uri); updateParent(metadata, uri, resourceDefinition); addPermissions(uri); + addState(uri); return metadata; } catch (MetadataRepositoryException e) { - log.error("Error storing distribution metadata"); throw new MetadataServiceException(e.getMessage()); } } @@ -129,75 +132,81 @@ public abstract class AbstractMetadataService implements MetadataService { @Override @PreAuthorize("hasPermission(#uri.stringValue(), 'nl.dtls.fairdatapoint.entity.metadata.Metadata', 'WRITE') " + "or hasRole('ADMIN')") - public Model update(Model metadata, IRI uri, ResourceDefinition resourceDefinition) throws MetadataServiceException { + public Model update(Model metadata, IRI uri, ResourceDefinition rd) throws MetadataServiceException { try { - metadataValidator.validate(metadata, uri, resourceDefinition); + metadataValidator.validate(metadata, uri, rd); Model oldMetadata = retrieve(uri); - metadataEnhancer.enhance(metadata, uri, resourceDefinition, oldMetadata); - metadataRepository.removeResource(uri); - metadataRepository.storeStatements(new ArrayList<>(metadata), uri); - updateParent(metadata, uri, resourceDefinition); + metadataEnhancer.enhance(metadata, uri, rd, oldMetadata); + metadataRepository.remove(uri); + metadataRepository.save(new ArrayList<>(metadata), uri); + updateParent(metadata, uri, rd); return metadata; } catch (MetadataRepositoryException | MetadataServiceException e) { - log.error("Error updating metadata"); throw (new MetadataServiceException(e.getMessage())); } } @Override @PreAuthorize("hasRole('ADMIN')") - public void delete(IRI uri, ResourceDefinition resourceDefinition) throws MetadataServiceException { + public void delete(IRI uri, ResourceDefinition rd) throws MetadataServiceException { try { Model metadata = retrieve(uri); - String childPredicate = resourceDefinition.getChild(); // Delete all children - if (childPredicate != null) { - String childRdUuid = resourceDefinition.getChildResourceDefinitionUuid(); - ResourceDefinition childRd = resourceDefinitionService.getByUuid(childRdUuid); - List<IRI> children = getChildren(metadata, i(childPredicate)); - for (IRI child : children) { - delete(child, childRd); + for (ResourceDefinitionChild child : rd.getChildren()) { + String childRdUuid = child.getResourceDefinitionUuid(); + ResourceDefinition rdChild = resourceDefinitionCache.getByUuid(childRdUuid); + if (rdChild != null) { + List<IRI> children = getChildren(metadata, i(child.getRelationUri())); + for (IRI childUri : children) { + delete(childUri, rdChild); + } } } // Remove reference at parent - String parentRdUuid = resourceDefinition.getParentResourceDefinitionUuid(); - if (parentRdUuid != null) { - ResourceDefinition parentRd = resourceDefinitionService.getByUuid(parentRdUuid); + Set<ResourceDefinition> rdParents = resourceDefinitionCache.getParentsByUuid(rd.getUuid()); + // select parent based on URI prefix + for (ResourceDefinition rdParent : rdParents) { IRI parentUri = getParent(metadata); - Model parent = retrieve(parentUri); - parent.remove(null, i(parentRd.getChild()), uri); - update(parent, parentUri, parentRd); + Model parentMetadata = retrieve(parentUri); + for (ResourceDefinitionChild rdChild : rdParent.getChildren()) { + if (rdChild.getResourceDefinitionUuid().equals(rd.getUuid())) { + parentMetadata.remove(null, i(rdChild.getRelationUri()), uri); + update(parentMetadata, parentUri, rdParent); + } + } } // Delete itself - metadataRepository.removeResource(uri); + metadataRepository.remove(uri); } catch (MetadataRepositoryException | MetadataServiceException e) { - log.error("Error updating metadata"); throw (new MetadataServiceException(e.getMessage())); } } - protected void updateParent(Model metadata, IRI uri, ResourceDefinition resourceDefinition) throws MetadataServiceException { + protected void updateParent(Model metadata, IRI uri, ResourceDefinition rd) throws MetadataServiceException { IRI parent = MetadataGetter.getParent(metadata); if (parent != null) { - String parentRdUuid = resourceDefinition.getParentResourceDefinitionUuid(); - ResourceDefinition parentResourceDefinition = resourceDefinitionService.getByUuid(parentRdUuid); - try { - List<Statement> statements = new ArrayList<>(); - if (parentResourceDefinition.getChild() != null) { - statements.add(s(parent, i(parentResourceDefinition.getChild()), uri)); + ResourceDefinition rdParent = resourceDefinitionService.getByUrl(parent.toString()); + if (rdParent != null) { + try { + List<Statement> statements = new ArrayList<>(); + for (ResourceDefinitionChild rdChild : rdParent.getChildren()) { + if (rdChild.getResourceDefinitionUuid().equals(rd.getUuid())) { + statements.add(s(parent, i(rdChild.getRelationUri()), uri)); + } + } + metadataRepository.removeStatement(parent, FDP.METADATAMODIFIED, null, parent); + statements.add(s(parent, FDP.METADATAMODIFIED, l(OffsetDateTime.now()))); + metadataRepository.save(statements, parent); + } catch (MetadataRepositoryException e) { + throw new MetadataServiceException("Problem with updating parent timestamp"); } - metadataRepository.removeStatement(parent, FDP.METADATAMODIFIED, null); - statements.add(s(parent, FDP.METADATAMODIFIED, l(LocalDateTime.now()))); - metadataRepository.storeStatements(statements, parent); - } catch (MetadataRepositoryException e) { - throw new MetadataServiceException("Problem with updating parent timestamp"); + Model parentMetadata = retrieve(parent); + updateParent(parentMetadata, parent, rdParent); } - Model parentMetadata = retrieve(parent); - updateParent(parentMetadata, parent, parentResourceDefinition); } } @@ -209,4 +218,9 @@ public abstract class AbstractMetadataService implements MetadataService { User user = oUser.get(); memberService.createOwner(uri.stringValue(), Metadata.class, user.getUuid()); } + + private void addState(IRI uri) { + metadataStateService.initState(uri); + } + } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/enhance/MetadataEnhancer.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/enhance/MetadataEnhancer.java index f605e04359a895f7d1b0c4bb6f3b8294dcda5259..a9121d320294405327d3e21007e654d0509aee26 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadata/enhance/MetadataEnhancer.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/enhance/MetadataEnhancer.java @@ -22,25 +22,32 @@ */ package nl.dtls.fairdatapoint.service.metadata.enhance; -import nl.dtls.fairdatapoint.entity.metadata.Agent; import nl.dtls.fairdatapoint.entity.metadata.Identifier; -import nl.dtls.fairdatapoint.entity.metadata.MetadataSetter; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; -import nl.dtls.fairdatapoint.service.metadatametrics.FairMetadataMetricsService; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import nl.dtls.fairdatapoint.service.metadata.metric.MetricsMetadataService; +import nl.dtls.fairdatapoint.service.profile.ProfileService; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; +import nl.dtls.fairdatapoint.util.ValueFactoryHelper; import nl.dtls.fairdatapoint.vocabulary.DATACITE; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; -import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.stream.Collectors; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getIssued; +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.*; import static nl.dtls.fairdatapoint.util.RdfUtil.containsObject; +import static nl.dtls.fairdatapoint.util.RdfUtil.getObjectsBy; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.l; @@ -59,33 +66,45 @@ public class MetadataEnhancer { private IRI license; @Autowired - @Qualifier("publisher") - private Agent publisher; + private MetricsMetadataService metricsMetadataService; @Autowired - private FairMetadataMetricsService fmMetricsService; + private ProfileService profileService; - public void enhance(Model metadata, IRI uri, ResourceDefinition resourceDefinition, Model oldMetadata) { - enhance(metadata, uri, resourceDefinition); - setIssued(metadata, uri, l(getIssued(oldMetadata))); - } + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + + @Autowired + private ResourceDefinitionService resourceDefinitionService; + + public void enhance(Model metadata, IRI uri, ResourceDefinition rd, Model oldMetadata) { + enhance(metadata, uri, rd); - public void enhance(Model metadata, IRI uri, ResourceDefinition resourceDefinition) { - addDefaultValues(metadata, uri, resourceDefinition); - setSpecification(metadata, uri, resourceDefinition); - setTimestamps(metadata, uri); + // Populate with current data from the triple store + setIssued(metadata, uri, l(getIssued(oldMetadata))); + if (rd.getUrlPrefix().equals("catalog")) { + setMetadataIssued(metadata, uri, l(getMetadataIssued(oldMetadata))); + } } - private void addDefaultValues(Model metadata, IRI uri, ResourceDefinition resourceDefinition) { + public void enhance(Model metadata, IRI uri, ResourceDefinition rd) { // Add RDF Type - setRdfTypes(metadata, uri, i(resourceDefinition.getRdfType()), i("http://www.w3.org/ns/dcat#Resource")); - - // Add PID - setMetadataIdentifier(metadata, uri, createMetadataIdentifier(uri)); + List<IRI> targetClassUris = resourceDefinitionService.getTargetClassUris(rd) + .stream() + .map(ValueFactoryHelper::i) + .collect(Collectors.toList()); + setRdfTypes(metadata, uri, targetClassUris); + + // Add identifiers + Identifier identifier = createMetadataIdentifier(uri); + setMetadataIdentifier(metadata, uri, identifier); + if (rd.getUrlPrefix().equals("")) { + setRepositoryIdentifier(metadata, uri, identifier); + } - // Add default publisher - if (!containsObject(metadata, uri.stringValue(), DCTERMS.PUBLISHER.stringValue()) && publisher != null) { - setPublisher(metadata, uri, publisher); + // Add label + if (containsObject(metadata, uri.stringValue(), DCTERMS.TITLE.stringValue())) { + setLabel(metadata, uri, getTitle(metadata)); } // Add default language @@ -105,20 +124,41 @@ public class MetadataEnhancer { } // Add FAIR metrics - setMetrics(metadata, uri, fmMetricsService.getMetrics(uri)); + setMetrics(metadata, uri, metricsMetadataService.generateMetrics(uri)); + + // Add timestamps + OffsetDateTime timestamp = OffsetDateTime.now(); + setIssued(metadata, uri, l(timestamp)); + setModified(metadata, uri, l(timestamp)); + if (rd.getUrlPrefix().equals("catalog")) { + setMetadataIssued(metadata, uri, l(timestamp)); + setMetadataModified(metadata, uri, l(timestamp)); + } } - private void setSpecification(Model metadata, IRI uri, ResourceDefinition rd) { - MetadataSetter.setSpecification(metadata, uri, i(rd.getSpecs())); + public void enhanceWithLinks(IRI entityUri, Model entity, ResourceDefinition rd, String persistentUrl, + Model resultRdf) { + for (ResourceDefinitionChild child : rd.getChildren()) { + ResourceDefinition rdChild = resourceDefinitionCache.getByUuid(child.getResourceDefinitionUuid()); + IRI container = i(format("%s/%s/", persistentUrl, rdChild.getUrlPrefix())); + + resultRdf.add(container, RDF.TYPE, LDP.DIRECT_CONTAINER); + resultRdf.add(container, DCTERMS.TITLE, l(child.getListView().getTitle())); + resultRdf.add(container, LDP.MEMBERSHIP_RESOURCE, entityUri); + resultRdf.add(container, LDP.HAS_MEMBER_RELATION, i(child.getRelationUri())); + for (org.eclipse.rdf4j.model.Value childUri : getObjectsBy(entity, entityUri, i(child.getRelationUri()))) { + resultRdf.add(container, LDP.CONTAINS, i(childUri.stringValue())); + } + } } - private void setTimestamps(Model metadata, IRI uri) { - setIssued(metadata, uri, l(LocalDateTime.now())); - setModified(metadata, uri, l(LocalDateTime.now())); + public void enhanceWithResourceDefinition(IRI entityUri, ResourceDefinition rd, Model resultRdf) { + resultRdf.add(entityUri, DCTERMS.CONFORMS_TO, profileService.getProfileUri(rd)); + resultRdf.add(profileService.getProfileUri(rd), RDFS.LABEL, l(format("%s Profile", rd.getName()))); } private Identifier createMetadataIdentifier(IRI uri) { - IRI identifierUri = i(uri.stringValue() + "/#identifier"); + IRI identifierUri = i(uri.stringValue() + "#identifier"); return new Identifier(identifierUri, DATACITE.IDENTIFIER, l(uri)); } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataService.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataService.java index 7d26d2e356c5c12fc37a4bc7762124487f04c69c..fb76164997ba0e3527dc90b6fe31b1cc339ee9cf 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataService.java @@ -23,6 +23,7 @@ package nl.dtls.fairdatapoint.service.metadata.generic; import nl.dtls.fairdatapoint.entity.exception.ForbiddenException; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; import nl.dtls.fairdatapoint.entity.metadata.Metadata; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.entity.user.UserRole; @@ -45,7 +46,7 @@ public class GenericMetadataService extends AbstractMetadataService { if (!rd.getName().equals("Repository")) { // 1. Check permissions String parentId = Optional.ofNullable(getParent(metadata)) - .orElseThrow(() -> new MetadataServiceException("Metadata has no parent")).stringValue(); + .orElseThrow(() -> new ValidationException("Metadata has no parent")).stringValue(); if (!(memberService.checkPermission(parentId, Metadata.class, BasePermission.CREATE) || memberService.checkRole(UserRole.ADMIN))) { throw new ForbiddenException("You are not allow to add new entry"); } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataService.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataService.java new file mode 100644 index 0000000000000000000000000000000000000000..6ba76a5a22456e7dab9eaf506f03d9724165a877 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataService.java @@ -0,0 +1,66 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package nl.dtls.fairdatapoint.service.metadata.metric; + +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.entity.metadata.Metric; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.service.settings.SettingsService; +import org.apache.commons.codec.digest.DigestUtils; +import org.eclipse.rdf4j.model.IRI; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +@Slf4j +@Service +public class MetricsMetadataService { + + @Autowired + private SettingsService settingsService; + + public List<Metric> generateMetrics(@Nonnull IRI metadataURI) { + Settings settings = settingsService.getOrDefaults(); + return settings.getMetadataMetrics().stream() + .map(entry -> + new Metric( + i(format("%s/metrics/%s", metadataURI.toString(), DigestUtils.md5Hex(entry.getMetricUri()))), + i(entry.getResourceUri()), + i(entry.getResourceUri()))) + .collect(Collectors.toList()); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/state/MetadataStateService.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/state/MetadataStateService.java new file mode 100644 index 0000000000000000000000000000000000000000..29955f5b18f2df525bd227c486f8f4122a3c9950 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/state/MetadataStateService.java @@ -0,0 +1,125 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.metadata.state; + +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import nl.dtls.fairdatapoint.service.metadata.validator.MetadataStateValidator; +import nl.dtls.fairdatapoint.service.user.CurrentUserService; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; +import static nl.dtls.fairdatapoint.util.RdfUtil.getObjectsBy; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +@Service +public class MetadataStateService { + + @Autowired + private MetadataRepository metadataRepository; + + @Autowired + private MetadataStateValidator metadataStateValidator; + + @Autowired + private CurrentUserService currentUserService; + + public Metadata get(IRI metadataUri) { + Optional<Metadata> oMetadata = metadataRepository.findByUri(metadataUri.stringValue()); + if (oMetadata.isEmpty()) { + throw new ResourceNotFoundException(format("Metadata info '%s' was not found", metadataUri)); + } + return oMetadata.get(); + } + + public MetaStateDTO getState(IRI metadataUri, Model model, ResourceDefinition rd) { + // 1. Return null if user is not log in + if (currentUserService.getCurrentUser().isEmpty()) { + return null; + } + + // 2. Get metadata info for current + Optional<Metadata> oMetadata = metadataRepository.findByUri(metadataUri.stringValue()); + if (oMetadata.isEmpty()) { + throw new ResourceNotFoundException(format("Metadata info '%s' was not found", metadataUri)); + } + Metadata metadata = oMetadata.get(); + + // 3. Get metadata info for children + List<String> childrenUris = new ArrayList<>(); + for (ResourceDefinitionChild rdChild : rd.getChildren()) { + IRI relationUri = i(rdChild.getRelationUri()); + for (org.eclipse.rdf4j.model.Value childUri : getObjectsBy(model, metadataUri, relationUri)) { + childrenUris.add(childUri.stringValue()); + } + } + Map<String, MetadataState> children = + metadataRepository.findByUriIn(childrenUris) + .stream() + .collect(Collectors.toMap(Metadata::getUri, Metadata::getState)); + + // 4. Build response + return new MetaStateDTO( + metadata.getState(), + children + ); + } + + public void initState(IRI metadataUri) { + Metadata metadata = new Metadata(null, metadataUri.stringValue(), MetadataState.DRAFT); + metadataRepository.save(metadata); + } + + public void modifyState(IRI metadataUri, MetaStateChangeDTO reqDto) { + // 1. Get metadata info for current + Optional<Metadata> oMetadata = metadataRepository.findByUri(metadataUri.stringValue()); + if (oMetadata.isEmpty()) { + throw new ResourceNotFoundException(format("Metadata info '%s' was not found", metadataUri)); + } + Metadata metadata = oMetadata.get(); + + // 2. Validate + metadataStateValidator.validate(reqDto, metadata); + + // 3. Update + metadata.setState(reqDto.getCurrent()); + metadataRepository.save(metadata); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataStateValidator.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataStateValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..ff0c005e8e452a2db2f9b62b6fb6bd217cfe5808 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataStateValidator.java @@ -0,0 +1,44 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.metadata.validator; + +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.springframework.stereotype.Service; + +@Service +public class MetadataStateValidator { + + public void validate(MetaStateChangeDTO reqDto, Metadata metadata) { + if (reqDto.getCurrent().equals(MetadataState.DRAFT)) { + throw new ValidationException("You can not change state to DRAFT"); + } + + if (metadata.getState().equals(MetadataState.PUBLISHED)) { + throw new ValidationException("Metadata is already published"); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataValidator.java b/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataValidator.java index 8544bf59cf60be06e7ea7e63c6834f4727fa4f99..b546566093e6eac6a78bac79d0a0cafe7c64a6a3 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataValidator.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/metadata/validator/MetadataValidator.java @@ -22,13 +22,13 @@ */ package nl.dtls.fairdatapoint.service.metadata.validator; -import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; import nl.dtls.fairdatapoint.database.rdf.repository.common.MetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; import nl.dtls.fairdatapoint.entity.exception.ValidationException; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; import nl.dtls.fairdatapoint.service.rdf.ShaclValidator; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; import nl.dtls.fairdatapoint.service.shape.ShapeService; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; @@ -37,17 +37,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import java.util.Optional; - +import static java.lang.String.format; import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getParent; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; @Service public class MetadataValidator { - @Autowired - private ResourceDefinitionRepository resourceDefinitionRepository; - @Autowired @Qualifier("genericMetadataRepository") private MetadataRepository metadataRepository; @@ -58,9 +54,12 @@ public class MetadataValidator { @Autowired private ShapeService shapeService; + @Autowired + private ResourceDefinitionService resourceDefinitionService; + public void validate(Model metadata, IRI uri, ResourceDefinition rd) throws MetadataServiceException { validateByShacl(metadata, uri); - if (!rd.getName().equals("Repository")) { + if (!rd.getUrlPrefix().isEmpty()) { validateParent(metadata, rd); } } @@ -77,16 +76,18 @@ public class MetadataValidator { throw new ValidationException("Not parent uri"); } - // 2. Check correctness of parent type + // 2. Get parent resource definition + ResourceDefinition rdParent = resourceDefinitionService.getByUrl(parent.toString()); + if (rdParent.getChildren().stream().noneMatch(rdChild -> rdChild.getResourceDefinitionUuid().equals(rd.getUuid()))) { + throw new ValidationException(format("Parent is not of correct type (RD: %s)", rdParent.getName())); + } + + // 3. Check correctness of parent type try { - String parentRdUuid = rd.getParentResourceDefinitionUuid(); - if (parentRdUuid != null) { - Optional<ResourceDefinition> oParentDefinition = resourceDefinitionRepository.findByUuid(parentRdUuid); - if (oParentDefinition.isPresent()) { - ResourceDefinition parentDefinition = oParentDefinition.get(); - if (!metadataRepository.isStatementExist(parent, RDF.TYPE, i(parentDefinition.getRdfType()))) { - throw new ValidationException("Parent is not of correct type"); - } + // select parent based on URI prefix + for (String rdfType : resourceDefinitionService.getTargetClassUris(rdParent)) { + if (!metadataRepository.checkExistence(parent, RDF.TYPE, i(rdfType))) { + throw new ValidationException(format("Parent is not of type (missing type: %s)", rdfType)); } } } catch (MetadataRepositoryException e) { diff --git a/src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImpl.java b/src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImpl.java deleted file mode 100755 index c23a757e1dcbce386868bdd2adee9afb3f9c52c6..0000000000000000000000000000000000000000 --- a/src/main/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImpl.java +++ /dev/null @@ -1,108 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package nl.dtls.fairdatapoint.service.metadatametrics; - -import com.google.common.base.Preconditions; -import nl.dtls.fairdatapoint.entity.metadata.Metric; -import org.apache.commons.codec.digest.DigestUtils; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@Service -public class FairMetadataMetricsServiceImpl implements FairMetadataMetricsService { - - private static final Logger LOGGER = LoggerFactory.getLogger(FairMetadataMetricsServiceImpl.class); - - private static final ValueFactory VALUEFACTORY = SimpleValueFactory.getInstance(); - - @Autowired - @Qualifier("metadataMetrics") - private Map<String, String> metadataMetrics; - - /** - * This method returns list of fair metrics for metadata - * - * @param metadataURI metadata URI - * @return List of fair metrics - */ - @Override - public List<Metric> getMetrics(@Nonnull IRI metadataURI) { - Preconditions.checkNotNull(metadataURI, "Metadata URI must not be null."); - List<Metric> metrics = new ArrayList<>(); - - metadataMetrics.forEach((metric, metricValue) -> { - - // Create metric uri - StringBuilder metricUri = new StringBuilder(metadataURI.toString()); - metricUri.append("/metrics/"); - metricUri.append(DigestUtils.md5Hex(metric)); - - addMetric(metrics, metricUri.toString(), metric, metricValue); - }); - return metrics; - } - - /** - * We are using this method to reduce the NPath complexity measure. This method add a FM to the - * list if the metric valueUri URI is provided. - * - * @param metrics List<Mertic> object - * @param uri Metric uri - * @param typeUri Metric typeUri uri - * @param valueUri Metric valueUri uri - */ - private void addMetric(List<Metric> metrics, String uri, String typeUri, String valueUri) { - try { - Preconditions.checkNotNull(uri, "Metadata URI must not be null."); - Preconditions.checkState(!uri.isEmpty(), "Metadata URI must not be empty."); - Preconditions.checkNotNull(typeUri, "Type URI must not be null."); - Preconditions.checkState(!typeUri.isEmpty(), "Type URI must not be empty."); - Preconditions.checkNotNull(valueUri, "Value URI must not be null."); - Preconditions.checkState(!valueUri.isEmpty(), "Value URI must not be empty."); - - Metric m = new Metric(); - m.setUri(VALUEFACTORY.createIRI(uri)); - m.setMetricType(VALUEFACTORY.createIRI(typeUri)); - m.setValue(VALUEFACTORY.createIRI(valueUri)); - metrics.add(m); - } catch (Exception e) { - LOGGER.error("Error adding metrics {}", e.getMessage()); - } - } -} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiGenerator.java b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..8a9d81562f39edd5cbc97da7b311188069dfe694 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiGenerator.java @@ -0,0 +1,492 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.openapi; + +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import io.swagger.v3.oas.models.tags.Tag; +import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; +import nl.dtls.fairdatapoint.api.dto.member.MemberCreateDTO; +import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import java.util.Map; + +public class OpenApiGenerator { + + public static final String FDP_TAG_PRIORITY = "FDP-TP"; + + public static final String TAG_PREFIX = "Metadata: "; + + private static final Schema<String> SCHEMA_STRING = new Schema<String>().type("string"); + + private static final Schema<String> SCHEMA_ERROR = new Schema<ErrorDTO>().$ref("#/components/schemas/ErrorDTO"); + + private static final Schema<String> SCHEMA_META = new Schema<MetaDTO>().$ref("#/components/schemas/MetaDTO"); + + private static final Schema<String> SCHEMA_META_STATE_CHANGE = new Schema<MetaStateChangeDTO>().$ref("#/components/schemas/MetaStateChangeDTO"); + + private static final Schema<String> SCHEMA_MEMBER = new Schema<MemberDTO>().$ref("#/components/schemas/MemberDTO"); + + private static final ArraySchema SCHEMA_MEMBERS = new ArraySchema().items(SCHEMA_MEMBER); + + private static final Schema<String> SCHEMA_MEMBER_CREATE = new Schema<MemberCreateDTO>().$ref("#/components/schemas/MemberDTO"); + + private static final Content CONTENT_RDF = new Content() + .addMediaType("text/turtle", new MediaType().schema(SCHEMA_STRING)) + .addMediaType("application/ld+json", new MediaType().schema(SCHEMA_STRING)) + .addMediaType("application/rdf+xml", new MediaType().schema(SCHEMA_STRING)) + .addMediaType("text/n3", new MediaType().schema(SCHEMA_STRING)); + + private static final Content CONTENT_ERROR = new Content() + .addMediaType("text/plain", new MediaType().schema(SCHEMA_STRING)) + .addMediaType("application/json", new MediaType().schema(SCHEMA_ERROR)); + + private static final Content CONTENT_META_STATE_CHANGE = new Content() + .addMediaType("application/json", new MediaType().schema(SCHEMA_META_STATE_CHANGE)); + + private static final ApiResponse RESPONSE_BAD_REQUEST = new ApiResponse() + .description("Bad Request") + .content(CONTENT_ERROR); + + private static final ApiResponse RESPONSE_FORBIDDEN = new ApiResponse() + .description("Forbidden") + .content(CONTENT_ERROR); + + private static final ApiResponse RESPONSE_UNAUTHORIZED = new ApiResponse() + .description("Unauthorized") + .content(CONTENT_ERROR); + + private static final ApiResponse RESPONSE_NOT_FOUND = new ApiResponse() + .description("Not Found") + .content(CONTENT_ERROR); + + private static final ApiResponse RESPONSE_NO_CONTENT = new ApiResponse() + .description("No Content"); + + private static final ApiResponse RESPONSE_INTERNAL_SERVER_ERROR = new ApiResponse() + .description("Internal Server Error") + .content(CONTENT_ERROR); + + private static final ApiResponse RESPONSE_OK_RDF = new ApiResponse() + .description("OK") + .content(CONTENT_RDF); + + private static final ApiResponses RESPONSES_RDF = new ApiResponses() + .addApiResponse("200", RESPONSE_OK_RDF) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final ApiResponses RESPONSES_DELETE = new ApiResponses() + .addApiResponse("204", RESPONSE_NO_CONTENT) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final ApiResponses RESPONSES_META = new ApiResponses() + .addApiResponse("200", new ApiResponse() + .description("OK") + .content(new Content() + .addMediaType("application/json", new MediaType().schema(SCHEMA_META))) + ) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final ApiResponses RESPONSES_META_STATE = new ApiResponses() + .addApiResponse("200", new ApiResponse() + .description("OK") + .content(CONTENT_META_STATE_CHANGE) + ) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final ApiResponses RESPONSES_MEMBERS = new ApiResponses() + .addApiResponse("200", new ApiResponse() + .description("OK") + .content(new Content() + .addMediaType("application/json", new MediaType().schema(SCHEMA_MEMBERS))) + ) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final ApiResponses RESPONSES_MEMBER = new ApiResponses() + .addApiResponse("200", new ApiResponse() + .description("OK") + .content(new Content() + .addMediaType("application/json", new MediaType().schema(SCHEMA_MEMBER))) + ) + .addApiResponse("400", RESPONSE_BAD_REQUEST) + .addApiResponse("401", RESPONSE_UNAUTHORIZED) + .addApiResponse("403", RESPONSE_FORBIDDEN) + .addApiResponse("404", RESPONSE_NOT_FOUND) + .addApiResponse("500", RESPONSE_INTERNAL_SERVER_ERROR); + + private static final RequestBody BODY_META_STATE = new RequestBody() + .description("New state") + .content(CONTENT_META_STATE_CHANGE) + .required(true); + + private static final RequestBody BODY_MEMBERSHIP = new RequestBody() + .description("New membership") + .content(new Content().addMediaType("application/json", new MediaType().schema(SCHEMA_MEMBER_CREATE))) + .required(true); + + private static final Parameter PARAM_USER_UUID = new Parameter() + .name("userUuid") + .in("path") + .schema(SCHEMA_STRING); + + private static final Parameter PARAM_CHILD_PREFIX = new Parameter() + .name("childPrefix") + .in("path") + .schema(SCHEMA_STRING); + + public static void generatePathsForRootResourceDefinition(Paths paths, ResourceDefinition resourceDefinition) { + String tag = TAG_PREFIX + resourceDefinition.getName(); + String operationSuffix = resourceDefinition.getName(); + Map<String, Object> extensions = Map.of("fdpResourceDefinition", resourceDefinition.getUuid()); + // CRUD: GET, PUT, DELETE + paths.addPathItem( + "/", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix) + .description("Get " + resourceDefinition.getName()) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + .put(new Operation() + .operationId("put" + operationSuffix) + .description("Edit existing " + resourceDefinition.getName()) + .addTagsItem(tag) + .requestBody(new RequestBody() + .description(resourceDefinition.getName() + " in RDF") + .content(CONTENT_RDF) + .required(true) + ) + .responses(RESPONSES_RDF) + ) + .delete(new Operation() + .operationId("delete" + operationSuffix) + .description("Delete existing " + resourceDefinition.getName()) + .addTagsItem(tag) + .responses(RESPONSES_DELETE) + ) + ); + // Spec (SHACL Shape) + paths.addPathItem( + "/spec", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Spec") + .description("Get SHACL shape specification for " + resourceDefinition.getName()) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Expanded + paths.addPathItem( + "/expanded", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + StringUtils.capitalize(operationSuffix) + "Expanded") + .description("Get " + resourceDefinition.getName() + " with its children") + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Page + paths.addPathItem( + "/page/{childPrefix}", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "ChildrenPage") + .description("Get a page of " + resourceDefinition.getName() + " children") + .addParametersItem(PARAM_CHILD_PREFIX) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Meta + paths.addPathItem( + "/meta", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Meta") + .description("Get metadata (memberships and state) for " + resourceDefinition.getName()) + .addTagsItem(tag) + .responses(RESPONSES_META) + ) + ); + paths.addPathItem( + "/meta/state", + new PathItem() + .extensions(extensions) + .put(new Operation() + .operationId("put" + operationSuffix + "MetaState") + .description("Change state of " + resourceDefinition.getName()) + .addTagsItem(tag) + .requestBody(BODY_META_STATE) + .responses(RESPONSES_META_STATE) + ) + ); + // Membership + paths.addPathItem( + "/members", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Members") + .description("Get members of a specific " + resourceDefinition.getName()) + .addTagsItem(tag) + .responses(RESPONSES_MEMBERS) + ) + ); + paths.addPathItem( + "/members/{userUuid}", + new PathItem() + .extensions(extensions) + .put(new Operation() + .operationId("put" + operationSuffix + "Member") + .description("Set membership for specific user in some " + resourceDefinition.getName()) + .addParametersItem(PARAM_USER_UUID) + .addTagsItem(tag) + .requestBody(BODY_MEMBERSHIP) + .responses(RESPONSES_MEMBER) + ) + .delete(new Operation() + .operationId("delete" + operationSuffix + "Member") + .description("Set membership for specific user in some " + resourceDefinition.getName()) + .addParametersItem(PARAM_USER_UUID) + .addTagsItem(tag) + .responses(RESPONSES_DELETE) + ) + ); + } + + public static void generatePathsForResourceDefinition(Paths paths, ResourceDefinition resourceDefinition) { + String prefix = resourceDefinition.getUrlPrefix(); + String operationSuffix = StringUtils.capitalize(prefix); + if (prefix.isEmpty()) { + generatePathsForRootResourceDefinition(paths, resourceDefinition); + return; + } + String parameterName = "uuid"; + String nestedPrefix = "/" + prefix; + Parameter parameter = new Parameter() + .name(parameterName) + .in("path") + .schema(new Schema<String>().type("string")); + String tag = TAG_PREFIX + resourceDefinition.getName(); + Map<String, Object> extensions = Map.of("fdpResourceDefinition", resourceDefinition.getUuid()); + // CRUD: POST + paths.addPathItem( + "/" + prefix, + new PathItem() + .extensions(extensions) + .post(new Operation() + .operationId("post" + operationSuffix) + .description("Create a new " + resourceDefinition.getName()) + .addTagsItem(tag) + .requestBody(new RequestBody() + .description(resourceDefinition.getName() + " in RDF") + .content(CONTENT_RDF) + .required(true) + ) + .responses(RESPONSES_RDF) + ) + ); + // CRUD: GET, PUT, DELETE + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix) + .description("Get " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + .put(new Operation() + .operationId("put" + operationSuffix) + .description("Edit existing " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .requestBody(new RequestBody() + .description(resourceDefinition.getName() + " in RDF") + .content(CONTENT_RDF) + .required(true) + ) + .responses(RESPONSES_RDF) + ) + .delete(new Operation() + .operationId("delete" + operationSuffix) + .description("Delete existing " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_DELETE) + ) + ); + // Spec (SHACL Shape) + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/spec", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Spec") + .description("Get SHACL shape specification for " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Expanded + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/expanded", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Expanded") + .description("Get " + resourceDefinition.getName() + " with its children") + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Page + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/page/{childPrefix}", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "ChildrenPage") + .description("Get a page of " + resourceDefinition.getName() + " children") + .addParametersItem(parameter) + .addParametersItem(PARAM_CHILD_PREFIX) + .addTagsItem(tag) + .responses(RESPONSES_RDF) + ) + ); + // Meta + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/meta", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Meta") + .description("Get metadata (memberships and state) for " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_META) + ) + ); + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/meta/state", + new PathItem() + .extensions(extensions) + .put(new Operation() + .operationId("put" + operationSuffix + "MetaState") + .description("Change state of " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .requestBody(BODY_META_STATE) + .responses(RESPONSES_META_STATE) + ) + ); + // Membership + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/members", + new PathItem() + .extensions(extensions) + .get(new Operation() + .operationId("get" + operationSuffix + "Members") + .description("Get members of a specific " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addTagsItem(tag) + .responses(RESPONSES_MEMBERS) + ) + ); + paths.addPathItem( + nestedPrefix + "/{" + parameterName + "}/members/{userUuid}", + new PathItem() + .extensions(extensions) + .put(new Operation() + .operationId("put" + operationSuffix + "Member") + .description("Set membership for specific user in some " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addParametersItem(PARAM_USER_UUID) + .addTagsItem(tag) + .requestBody(BODY_MEMBERSHIP) + .responses(RESPONSES_MEMBER) + ) + .delete(new Operation() + .operationId("delete" + operationSuffix + "Member") + .description("Set membership for specific user in some " + resourceDefinition.getName()) + .addParametersItem(parameter) + .addParametersItem(PARAM_USER_UUID) + .addTagsItem(tag) + .responses(RESPONSES_DELETE) + ) + ); + } + + public static Tag generateTag(ResourceDefinition resourceDefinition) { + return new Tag() + .name(TAG_PREFIX + resourceDefinition.getName()) + .description("Metadata according to the " + resourceDefinition.getName() + " resource definition") + .extensions(Map.of(FDP_TAG_PRIORITY, 10)); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiService.java b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiService.java new file mode 100644 index 0000000000000000000000000000000000000000..b8455ce6e73d00facf9253a3b2f7832979bba9a4 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiService.java @@ -0,0 +1,118 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.openapi; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.tags.Tag; +import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Log4j2 +public class OpenApiService { + + @Autowired + private OpenAPI openAPI; + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + private Paths getGenericPaths() { + return (Paths) openAPI.getExtensions().get("fdpGenericPaths"); + } + + private boolean isRelatedToResourceDefinition(PathItem pathItem, ResourceDefinition rd) { + String rdUuid = (String) pathItem.getExtensions().getOrDefault("fdpResourceDefinition", ""); + return rdUuid.equals(rd.getUuid()); + } + + public void updateTags(List<ResourceDefinition> resourceDefinitions) { + openAPI.setTags(OpenApiTagsUtils.listTags(resourceDefinitions)); + } + + public void removeGenericPaths(ResourceDefinition rd) { + Paths fdpGenericPaths = getGenericPaths(); + Set<String> toRemove = fdpGenericPaths + .entrySet() + .stream() + .filter(item -> isRelatedToResourceDefinition(item.getValue(), rd)) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + log.info("Removing OpenAPI paths: {}", toRemove); + openAPI.getPaths().keySet().removeAll(toRemove); + fdpGenericPaths.keySet().removeAll(toRemove); + // Update tags + updateTags(resourceDefinitionRepository.findAll()); + } + + public void removeAllGenericPaths() { + Paths fdpGenericPaths = getGenericPaths(); + log.info("Removing OpenAPI paths: {}", fdpGenericPaths.keySet()); + openAPI.getPaths().keySet().removeAll(fdpGenericPaths.keySet()); + fdpGenericPaths.clear(); + } + + public void updateGenericPaths(ResourceDefinition rd) { + Paths fdpGenericPaths = getGenericPaths(); + // Cleanup + removeGenericPaths(rd); + // Generate + OpenApiGenerator.generatePathsForResourceDefinition(fdpGenericPaths, rd); + // Apply + log.info("Adding OpenAPI paths: {}", fdpGenericPaths.keySet()); + openAPI.getPaths().putAll(fdpGenericPaths); + // Update tags + updateTags(resourceDefinitionRepository.findAll()); + } + + public void updateAllGenericPaths() { + Paths fdpGenericPaths = getGenericPaths(); + // Cleanup + removeAllGenericPaths(); + // Re-generate from Resource Definitions + List<ResourceDefinition> resourceDefinitions = resourceDefinitionRepository.findAll(); + resourceDefinitions.forEach(rd -> OpenApiGenerator.generatePathsForResourceDefinition(fdpGenericPaths, rd)); + // Apply + log.info("Adding OpenAPI paths: {}", fdpGenericPaths.keySet()); + openAPI.getPaths().putAll(fdpGenericPaths); + updateTags(resourceDefinitions); + } + + @PostConstruct + public void init() { + log.info("Initializing OpenAPI with generic paths"); + updateAllGenericPaths(); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiTagsUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiTagsUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..c9c6f21d91e0535cefc5e97e283552ad5f802b05 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/openapi/OpenApiTagsUtils.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.openapi; + +import io.swagger.v3.oas.models.tags.Tag; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; + +import java.util.*; +import java.util.stream.Collectors; + +public class OpenApiTagsUtils { + + private static final Comparator<String> STRING_COMPARATOR = Comparator.comparing(String::toString); + + private static final Comparator<Tag> TAG_COMPARATOR = (o1, o2) -> { + int priority1 = (int)o1.getExtensions().getOrDefault(OpenApiGenerator.FDP_TAG_PRIORITY, 90); + int priority2 = (int)o2.getExtensions().getOrDefault(OpenApiGenerator.FDP_TAG_PRIORITY, 90); + if (priority1 < priority2) { + return -1; + } else if (priority1 > priority2) { + return 1; + } + return STRING_COMPARATOR.compare(o1.getName(), o2.getName()); + }; + + public static final Tag METADATA_TAG = new Tag() + .name("Metadata") + .description("Common operations with all metadata") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 0)); + + public static final Tag METADATA_MMODEL_TAG = new Tag() + .name("Metadata Model") + .description("Manipulation with model of metadata") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 20)); + + public static final Tag METADATA_CLIENT_TAG = new Tag() + .name("Client") + .description("Endpoints for FAIR Data Point Client") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 30)); + + public static final Tag METADATA_INDEX_TAG = new Tag() + .name("Index") + .description("FAIR Data Point Index endpoints") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 40)); + + public static final Tag METADATA_AA_TAG = new Tag() + .name("Authentication and Authorization") + .description("Management of access to FDP (not specific type of metadata)") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 50)); + + public static final Tag METADATA_USERMGMT_TAG = new Tag() + .name("User Management") + .description("Management of user accounts") + .extensions(Map.of(OpenApiGenerator.FDP_TAG_PRIORITY, 60)); + + public static final List<Tag> STATIC_TAGS = Arrays.asList(METADATA_TAG, METADATA_MMODEL_TAG, METADATA_CLIENT_TAG, METADATA_INDEX_TAG, METADATA_AA_TAG, METADATA_USERMGMT_TAG); + + public static List<Tag> listTags(List<ResourceDefinition> resourceDefinitions) { + List<Tag> tags = resourceDefinitions.stream().map(OpenApiGenerator::generateTag).collect(Collectors.toList()); + tags.addAll(STATIC_TAGS); + tags.sort(TAG_COMPARATOR); + return tags; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/ping/PingService.java b/src/main/java/nl/dtls/fairdatapoint/service/ping/PingService.java new file mode 100644 index 0000000000000000000000000000000000000000..64d5e6aed13051d0ee3c6cf79e27d91f627b2026 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/ping/PingService.java @@ -0,0 +1,80 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.ping; + + +import lombok.extern.log4j.Log4j2; +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.config.properties.PingProperties; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.service.settings.SettingsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.List; +import java.util.Map; + +@Log4j2 +@Service +@ConditionalOnProperty(name = "ping.enabled", havingValue = "true", matchIfMissing = true) +public class PingService { + + @Autowired + private PingProperties pingProperties; + + @Autowired + private InstanceProperties instanceProperties; + + @Autowired + private SettingsService settingsService; + + @Autowired + private RestTemplate client; + + @Scheduled(initialDelayString = "${ping.initDelay:#{10*1000}}", fixedRateString = "${ping.interval:P7D}") + public void ping() { + Settings settings = settingsService.getOrDefaults(); + if (!settings.getPing().isEnabled() || !pingProperties.isEnabled()) { + return; + } + var request = Map.of("clientUrl", instanceProperties.getClientUrl()); + for (String endpoint : settings.getPing().getEndpoints()) { + pingEndpoint(endpoint.trim(), request); + } + } + + @Async + void pingEndpoint(String endpoint, Map<String, String> request) { + try { + log.info("Pinging {}", endpoint); + client.postForEntity(endpoint, request, String.class); + } catch (Exception e) { + log.warn("Failed to ping {}: {}", endpoint, e.getMessage()); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/profile/ProfileService.java b/src/main/java/nl/dtls/fairdatapoint/service/profile/ProfileService.java new file mode 100644 index 0000000000000000000000000000000000000000..3d0f757a5558efa96a0d78a5d4a8b3e0227d1d11 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/profile/ProfileService.java @@ -0,0 +1,93 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.profile; + +import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionService; +import nl.dtls.fairdatapoint.service.shape.ShapeService; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.util.ModelBuilder; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Optional; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.*; + +@Service +public class ProfileService { + + private static final String PROFILE_PREFIX = "http://www.w3.org/ns/dx/prof/"; + + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + + @Autowired + private ShapeRepository shapeRepository; + + @Autowired + private ResourceDefinitionService resourceDefinitionService; + + private Model getProfileForResourceDefinition(ResourceDefinition rd, IRI uri) { + Model profile = new LinkedHashModel(); + profile.add(uri, RDF.TYPE, i(format("%sProfile", PROFILE_PREFIX))); + profile.add(uri, RDFS.LABEL, l(format("%s Profile", rd.getName()))); + profile.add(uri, i(format("%sisProfileOf", PROFILE_PREFIX)), i(format("%s/profile/core", + persistentUrl))); + rd.getShapeUuids().forEach(shapeUuid -> shapeRepository.findByUuid(shapeUuid).map(shape -> { + ModelBuilder modelBuilder = new ModelBuilder(); + Resource resource = bn(); + modelBuilder.subject(resource); + modelBuilder.add(RDF.TYPE, i(format("%s#ResourceDescriptor", PROFILE_PREFIX))); + modelBuilder.add(DCTERMS.FORMAT, i("https://w3id.org/mediatype/text/turtle")); + modelBuilder.add(DCTERMS.CONFORMS_TO, i("https://www.w3.org/TR/shacl/")); + modelBuilder.add(i(format("%shasRole", PROFILE_PREFIX)), i(format("%srole/Validation", + PROFILE_PREFIX))); + modelBuilder.add(i(format("%shasArtifact", PROFILE_PREFIX)), i(format("%s/shapes/%s", + persistentUrl, shapeUuid))); + profile.add(uri, i(format("%shasResource", PROFILE_PREFIX)), resource); + profile.addAll(new ArrayList<>(modelBuilder.build())); + return null; + })); + return profile; + } + + public Optional<Model> getProfileByUuid(String uuid, IRI uri) { + return resourceDefinitionService.getByUuid(uuid).map(rd -> getProfileForResourceDefinition(rd, uri)); + } + + public IRI getProfileUri(ResourceDefinition rd) { + return i(format("%s/profile/%s", persistentUrl, rd.getUuid())); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/reset/FactoryDefaults.java b/src/main/java/nl/dtls/fairdatapoint/service/reset/FactoryDefaults.java new file mode 100644 index 0000000000000000000000000000000000000000..d387e5b2291f84a8cc03481d9c2e1b20c77cf358 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/reset/FactoryDefaults.java @@ -0,0 +1,395 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.reset; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import nl.dtls.fairdatapoint.entity.membership.Membership; +import nl.dtls.fairdatapoint.entity.membership.MembershipPermission; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import nl.dtls.fairdatapoint.entity.resource.*; +import nl.dtls.fairdatapoint.entity.shape.Shape; +import nl.dtls.fairdatapoint.entity.shape.ShapeType; +import nl.dtls.fairdatapoint.entity.user.User; +import nl.dtls.fairdatapoint.entity.user.UserRole; +import nl.dtls.fairdatapoint.service.shape.ShapeShaclUtils; +import nl.dtls.fairdatapoint.vocabulary.DATACITE; +import nl.dtls.fairdatapoint.vocabulary.FDP; +import nl.dtls.fairdatapoint.vocabulary.R3D; +import nl.dtls.fairdatapoint.vocabulary.Sio; +import org.apache.commons.codec.digest.DigestUtils; +import org.bson.BasicBSONObject; +import org.bson.Document; +import org.bson.types.BasicBSONList; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; + +import java.io.IOException; +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.*; + +public class FactoryDefaults { + + //== USERS + // Changes: Migration_0001_Init + public static final User USER_ALBERT = User.builder() + .uuid("7e64818d-6276-46fb-8bb1-732e6e09f7e9") + .firstName("Albert") + .lastName("Einstein") + .email("albert.einstein@example.com") + .passwordHash("$2a$10$t2foZfp7cZFQo2u/33ZqTu2WNitBqYd2EY2tQO0/rBUdf8QfsAxyW") + .role(UserRole.ADMIN) + .build(); + + public static final User USER_NIKOLA = User.builder() + .uuid("b5b92c69-5ed9-4054-954d-0121c29b6800") + .firstName("Nikola") + .lastName("Tesla") + .email("nikola.tesla@example.com") + .passwordHash("$2a$10$t2foZfp7cZFQo2u/33ZqTu2WNitBqYd2EY2tQO0/rBUdf8QfsAxyW") + .role(UserRole.USER) + .build(); + + //== MEMBERSHIPS + // Changes: Migration_0001_Init, Migration_0004_ResourceDefinition + public static final Membership MEMBERSHIP_OWNER = Membership.builder() + .uuid("49f2bcfd-ef0a-4a3a-a1a3-0fc72a6892a8") + .name("Owner") + .permissions(List.of( + new MembershipPermission(2, 'W'), + new MembershipPermission(4, 'C'), + new MembershipPermission(8, 'D'), + new MembershipPermission(16, 'A') + )) + .allowedEntities(List.of( + "a0949e72-4466-4d53-8900-9436d1049a4b", + "2f08228e-1789-40f8-84cd-28e3288c3604", + "02c649de-c579-43bb-b470-306abdc808c7" + )) + .build(); + + public static final Membership MEMBERSHIP_DATA_PROVIDER = Membership.builder() + .uuid("87a2d984-7db2-43f6-805c-6b0040afead5") + .name("Data Provider") + .permissions(List.of( + new MembershipPermission(4, 'C') + )) + .allowedEntities(List.of( + "a0949e72-4466-4d53-8900-9436d1049a4b" + )) + .build(); + + //== SHAPE UUIDS + private static final String SHAPE_RESOURCE_UUID = "6a668323-3936-4b53-8380-a4fd2ed082ee"; + + private static final String SHAPE_REPOSITORY_UUID = "a92958ab-a414-47e6-8e17-68ba96ba3a2b"; + + private static final String SHAPE_CATALOG_UUID = "2aa7ba63-d27a-4c0e-bfa6-3a4e250f4660"; + + private static final String SHAPE_DATASET_UUID = "866d7fb8-5982-4215-9c7c-18d0ed1bd5f3"; + + private static final String SHAPE_DISTRIBUTION_UUID = "ebacbf83-cd4f-4113-8738-d73c0735b0ab"; + + //== RESOURCE DEFINITIONS + // Changes: Migration_0002_CustomMetamodel, Migration_0004_ResourceDefinition + public static final ResourceDefinition RESOURCE_DEFINITION_REPOSITORY = ResourceDefinition.builder() + .uuid("77aaad6a-0136-4c6e-88b9-07ffccd0ee4c") + .name("Repository") + .urlPrefix("") + .shapeUuids(List.of( + SHAPE_RESOURCE_UUID, + SHAPE_REPOSITORY_UUID + )) + .children(List.of( + ResourceDefinitionChild.builder() + .resourceDefinitionUuid("a0949e72-4466-4d53-8900-9436d1049a4b") + .relationUri("http://www.re3data.org/schema/3-0#dataCatalog") + .listView( + ResourceDefinitionChildListView.builder() + .title("Catalogs") + .tagsUri("http://www.w3.org/ns/dcat#themeTaxonomy") + .metadata(List.of()) + .build() + ) + .build() + )) + .externalLinks(List.of()) + .build(); + + public static final ResourceDefinition RESOURCE_DEFINITION_CATALOG = ResourceDefinition.builder() + .uuid("a0949e72-4466-4d53-8900-9436d1049a4b") + .name("Catalog") + .urlPrefix("catalog") + .shapeUuids(List.of( + SHAPE_RESOURCE_UUID, + SHAPE_CATALOG_UUID + )) + .children(List.of( + ResourceDefinitionChild.builder() + .resourceDefinitionUuid("2f08228e-1789-40f8-84cd-28e3288c3604") + .relationUri("http://www.w3.org/ns/dcat#dataset") + .listView( + ResourceDefinitionChildListView.builder() + .title("Datasets") + .tagsUri("http://www.w3.org/ns/dcat#theme") + .metadata(List.of()) + .build() + ) + .build() + )) + .externalLinks(List.of()) + .build(); + + public static final ResourceDefinition RESOURCE_DEFINITION_DATASET = ResourceDefinition.builder() + .uuid("2f08228e-1789-40f8-84cd-28e3288c3604") + .name("Dataset") + .urlPrefix("dataset") + .shapeUuids(List.of( + SHAPE_RESOURCE_UUID, + SHAPE_DATASET_UUID + )) + .children(List.of( + ResourceDefinitionChild.builder() + .resourceDefinitionUuid("02c649de-c579-43bb-b470-306abdc808c7") + .relationUri("http://www.w3.org/ns/dcat#distribution") + .listView( + ResourceDefinitionChildListView.builder() + .title("Distributions") + .tagsUri(null) + .metadata(List.of( + new ResourceDefinitionChildListViewMetadata( + "Media Type", + "http://www.w3.org/ns/dcat#mediaType" + ) + )) + .build() + ) + .build() + )) + .externalLinks(List.of()) + .build(); + + public static ResourceDefinition RESOURCE_DEFINITION_DISTRIBUTION = ResourceDefinition.builder() + .uuid("02c649de-c579-43bb-b470-306abdc808c7") + .name("Distribution") + .urlPrefix("distribution") + .shapeUuids(List.of( + SHAPE_RESOURCE_UUID, + SHAPE_DISTRIBUTION_UUID + )) + .children(List.of()) + .externalLinks(List.of( + new ResourceDefinitionLink( + "Access online", + "http://www.w3.org/ns/dcat#accessURL" + ), + new ResourceDefinitionLink( + "Download", + "http://www.w3.org/ns/dcat#downloadURL" + ) + )) + .build(); + + //== SHAPES + //== Changes: Migration_0003_ShapeDefinition, Migration_0005_UpdateShapeDefinition, Migration_0006_ShapesSharing + public static Shape shapeResource() throws Exception { + String definition = loadShape("shape-resource.ttl"); + return Shape.builder() + .uuid(SHAPE_RESOURCE_UUID) + .name("Resource") + .type(ShapeType.INTERNAL) + .published(false) + .definition(definition) + .targetClasses(ShapeShaclUtils.extractTargetClasses(definition)) + .build(); + } + + public static Shape shapeRepository() throws Exception { + String definition = loadShape("shape-repository.ttl"); + return Shape.builder() + .uuid(SHAPE_REPOSITORY_UUID) + .name("Repository") + .type(ShapeType.INTERNAL) + .published(false) + .definition(definition) + .targetClasses(ShapeShaclUtils.extractTargetClasses(definition)) + .build(); + } + + public static Shape shapeCatalog() throws Exception { + String definition = loadShape("shape-catalog.ttl"); + return Shape.builder() + .uuid(SHAPE_CATALOG_UUID) + .name("Catalog") + .type(ShapeType.INTERNAL) + .published(false) + .definition(definition) + .targetClasses(ShapeShaclUtils.extractTargetClasses(definition)) + .build(); + } + + public static Shape shapeDataset() throws Exception { + String definition = loadShape("shape-dataset.ttl"); + return Shape.builder() + .uuid(SHAPE_DATASET_UUID) + .name("Dataset") + .type(ShapeType.CUSTOM) + .published(false) + .definition(definition) + .targetClasses(ShapeShaclUtils.extractTargetClasses(definition)) + .build(); + } + + public static Shape shapeDistribution() throws Exception { + String definition = loadShape("shape-distribution.ttl"); + return Shape.builder() + .uuid(SHAPE_DISTRIBUTION_UUID) + .name("Distribution") + .type(ShapeType.CUSTOM) + .published(false) + .definition(definition) + .targetClasses(ShapeShaclUtils.extractTargetClasses(definition)) + .build(); + } + + // Repository ACL + public static Document aclRepository(String persistentUrl) { + BasicBSONObject owner = new BasicBSONObject() + .append("name", USER_ALBERT.getUuid()) + .append("isPrincipal", true); + Document acl = new Document(); + acl.append("className", "nl.dtls.fairdatapoint.entity.metadata.FDPMetadata"); + acl.append("instanceId", persistentUrl); + acl.append("owner", owner); + acl.append("inheritPermissions", true); + BasicBSONList permissions = new BasicBSONList(); + permissions.add( + new Document() + .append("sid", owner) + .append("permission", 2) + .append("granting", true) + .append("auditFailure", false) + .append("auditSuccess", false)); + permissions.add( + new Document() + .append("sid", owner) + .append("permission", 4) + .append("granting", true) + .append("auditFailure", false) + .append("auditSuccess", false)); + permissions.add( + new Document() + .append("sid", owner) + .append("permission", 8) + .append("granting", true) + .append("auditFailure", false) + .append("auditSuccess", false)); + permissions.add( + new Document() + .append("sid", owner) + .append("permission", 16) + .append("granting", true) + .append("auditFailure", false) + .append("auditSuccess", false)); + acl.append("permissions", permissions); + acl.append("_class", "org.springframework.security.acls.domain.MongoAcl"); + return acl; + } + + // Repository RDF statements + private static final String LIPSUM_TEXT = "Duis pellentesque, nunc a fringilla varius, magna dui porta quam, nec " + + "ultricies augue turpis sed velit. Donec id consectetur ligula. Suspendisse pharetra egestas " + + "massa, vel varius leo viverra at. Donec scelerisque id ipsum id semper. Maecenas facilisis augue" + + " vel justo molestie aliquet. Maecenas sed mattis lacus, sed viverra risus. Donec iaculis quis " + + "lacus vitae scelerisque. Nullam fermentum lectus nisi, id vulputate nisi congue nec. Morbi " + + "fermentum justo at justo bibendum, at tempus ipsum tempor. Donec facilisis nibh sed lectus " + + "blandit venenatis. Cras ullamcorper, justo vitae feugiat commodo, orci metus suscipit purus, " + + "quis sagittis turpis ante eget ex. Pellentesque malesuada a metus eu pulvinar. Morbi rutrum " + + "euismod eros at varius. Duis finibus dapibus ex, a hendrerit mauris efficitur at."; + + public static List<Statement> repositoryStatements(String persistentUrl, IRI license, IRI language, String accessRightsDescription) { + List<Statement> s = new ArrayList<>(); + IRI baseUrl = i(persistentUrl); + FactoryDefaults.add(s, RDF.TYPE, R3D.REPOSITORY, baseUrl); + FactoryDefaults.add(s, RDF.TYPE, i("http://www.w3.org/ns/dcat#Resource"), baseUrl); + FactoryDefaults.add(s, DCTERMS.TITLE, l("My FAIR Data Point"), baseUrl); + FactoryDefaults.add(s, RDFS.LABEL, l("My FAIR Data Point"), baseUrl); + FactoryDefaults.add(s, DCTERMS.HAS_VERSION, l(1.0f), baseUrl); + FactoryDefaults.add(s, FDP.METADATAISSUED, l(OffsetDateTime.now()), baseUrl); + FactoryDefaults.add(s, FDP.METADATAMODIFIED, l(OffsetDateTime.now()), baseUrl); + FactoryDefaults.add(s, DCTERMS.LICENSE, license, baseUrl); + FactoryDefaults.add(s, DCTERMS.DESCRIPTION, l(LIPSUM_TEXT), baseUrl); + FactoryDefaults.add(s, DCTERMS.CONFORMS_TO, i("https://www.purl.org/fairtools/fdp/schema/0.1/fdpMetadata"), baseUrl); + FactoryDefaults.add(s, DCTERMS.LANGUAGE, language, baseUrl); + // Identifier + IRI identifierIri = i(persistentUrl + "#identifier"); + FactoryDefaults.add(s, FDP.METADATAIDENTIFIER, identifierIri, baseUrl); + FactoryDefaults.add(s, identifierIri, RDF.TYPE, DATACITE.IDENTIFIER, baseUrl); + FactoryDefaults.add(s, identifierIri, DCTERMS.IDENTIFIER, l(persistentUrl), baseUrl); + // Repository Identifier + FactoryDefaults.add(s, R3D.REPOSITORYIDENTIFIER, identifierIri, baseUrl); + // Access Rights + IRI arIri = i(persistentUrl + "#accessRights"); + FactoryDefaults.add(s, DCTERMS.ACCESS_RIGHTS, arIri, baseUrl); + FactoryDefaults.add(s, arIri, RDF.TYPE, DCTERMS.RIGHTS_STATEMENT, baseUrl); + FactoryDefaults.add(s, arIri, DCTERMS.DESCRIPTION, l(accessRightsDescription), baseUrl); + // Publisher + IRI publisherIri = i(persistentUrl + "#publisher"); + FactoryDefaults.add(s, DCTERMS.PUBLISHER, publisherIri, baseUrl); + FactoryDefaults.add(s, publisherIri, RDF.TYPE, FOAF.AGENT, baseUrl); + FactoryDefaults.add(s, publisherIri, FOAF.NAME, l("Default Publisher"), baseUrl); + return s; + } + + public static Metadata metadataRepository(String persistentUrl) { + return Metadata.builder() + .uri(persistentUrl) + .state(MetadataState.PUBLISHED) + .build(); + } + + private static String loadShape(String name) throws Exception { + return Resources.toString( + FactoryDefaults.class.getResource(name), + Charsets.UTF_8 + ); + } + + private static void add(List<Statement> statements, IRI predicate, org.eclipse.rdf4j.model.Value object, IRI base) { + statements.add(s(base, predicate, object, base)); + } + + private static void add(List<Statement> statements, IRI subject, IRI predicate, org.eclipse.rdf4j.model.Value object, IRI base) { + statements.add(s(subject, predicate, object, base)); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/reset/ResetService.java b/src/main/java/nl/dtls/fairdatapoint/service/reset/ResetService.java new file mode 100644 index 0000000000000000000000000000000000000000..080d2acf8e9e62b3cca3202fccdf661cd2eba299 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/reset/ResetService.java @@ -0,0 +1,242 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.reset; + +import com.mongodb.client.MongoCollection; +import lombok.extern.slf4j.Slf4j; +import nl.dtls.fairdatapoint.api.dto.reset.ResetDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.*; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; +import nl.dtls.fairdatapoint.service.metadata.generic.GenericMetadataService; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionTargetClassesCache; +import nl.dtls.fairdatapoint.service.settings.SettingsService; +import nl.dtls.fairdatapoint.vocabulary.DATACITE; +import nl.dtls.fairdatapoint.vocabulary.FDP; +import nl.dtls.fairdatapoint.vocabulary.R3D; +import nl.dtls.fairdatapoint.vocabulary.Sio; +import org.apache.commons.codec.digest.DigestUtils; +import org.bson.Document; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Statement; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.RDFS; +import org.eclipse.rdf4j.repository.Repository; +import org.eclipse.rdf4j.repository.RepositoryConnection; +import org.eclipse.rdf4j.repository.RepositoryException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.acls.dao.AclRepository; +import org.springframework.security.acls.model.AclCache; +import org.springframework.stereotype.Service; + +import java.time.OffsetDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.l; + +@Slf4j +@Service +public class ResetService { + + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + + @Value("${metadataProperties.accessRightsDescription:This resource has no access restriction}") + private String accessRightsDescription; + + @Autowired + private IRI license; + + @Autowired + private IRI language; + + @Autowired + protected Repository repository; + + @Autowired + private ApiKeyRepository apiKeyRepository; + + @Autowired + private MembershipRepository membershipRepository; + + @Autowired + private AclRepository aclRepository; + + @Autowired + private AclCache aclCache; + + @Autowired + private UserRepository userRepository; + + @Autowired + private ShapeRepository shapeRepository; + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + + @Autowired + private ResourceDefinitionTargetClassesCache resourceDefinitionTargetClassesCache; + + @Autowired + private MetadataRepository metadataRepository; + + @Autowired + private GenericMetadataService genericMetadataService; + + @Autowired + private SettingsService settingsService; + + @Autowired + private MongoTemplate mongoTemplate; + + @PreAuthorize("hasRole('ADMIN')") + public void resetToFactoryDefaults(ResetDTO reqDto) throws Exception { + log.info("Resetting to factory defaults"); + if (reqDto.isSettings()) { + settingsService.resetSettings(); + } + if (reqDto.isUsers() || reqDto.isMetadata()) { + clearMemberships(); + restoreDefaultMemberships(); + } + if (reqDto.isUsers()) { + clearApiKeys(); + clearUsers(); + restoreDefaultUsers(); + } + if (reqDto.isMetadata()) { + clearMetadata(); + restoreDefaultMetadata(); + } + if (reqDto.isResourceDefinitions()) { + clearShapes(); + clearResourceDefinitions(); + restoreDefaultShapes(); + restoreDefaultResourceDefinitions(); + } + resourceDefinitionCache.computeCache(); + resourceDefinitionTargetClassesCache.computeCache(); + } + + private void clearApiKeys() { + log.debug("Clearing API keys"); + apiKeyRepository.deleteAll(); + } + + private void clearMemberships() { + log.debug("Clearing memberships"); + membershipRepository.deleteAll(); + log.debug("Clearing ACL cache"); + aclRepository.deleteAll(); + aclCache.clearCache(); + } + + private void clearUsers() { + log.debug("Clearing users"); + userRepository.deleteAll(); + } + + private void clearShapes() { + log.debug("Clearing SHACL shapes"); + shapeRepository.deleteAll(); + } + + private void clearResourceDefinitions() { + log.debug("Clearing resource definitions"); + resourceDefinitionRepository.deleteAll(); + } + + private void clearMetadata() throws MetadataServiceException { + log.debug("Clearing metadata"); + Optional<ResourceDefinition> rd = resourceDefinitionRepository.findByUrlPrefix(""); + if (rd.isPresent()) { + genericMetadataService.delete(i(persistentUrl), rd.get()); + metadataRepository.deleteAll(); + } + } + + private void restoreDefaultUsers() { + log.debug("Creating default users"); + userRepository.save(FactoryDefaults.USER_ALBERT); + userRepository.save(FactoryDefaults.USER_NIKOLA); + } + + private void restoreDefaultMemberships() { + log.debug("Creating default users"); + membershipRepository.save(FactoryDefaults.MEMBERSHIP_OWNER); + membershipRepository.save(FactoryDefaults.MEMBERSHIP_DATA_PROVIDER); + + MongoCollection<Document> aclCol = mongoTemplate.getCollection("ACL"); + aclCol.insertOne(FactoryDefaults.aclRepository(persistentUrl)); + } + + private void restoreDefaultMetadata() { + log.debug("Creating default metadata"); + try (RepositoryConnection conn = repository.getConnection()) { + List<Statement> s = FactoryDefaults.repositoryStatements( + persistentUrl, + license, + language, + accessRightsDescription + ); + conn.add(s); + metadataRepository.save(FactoryDefaults.metadataRepository(persistentUrl)); + } catch (RepositoryException e) { + log.error(e.getMessage(), e); + } + } + + private void restoreDefaultShapes() throws Exception { + log.debug("Creating default shapes"); + shapeRepository.save(FactoryDefaults.shapeResource()); + shapeRepository.save(FactoryDefaults.shapeRepository()); + shapeRepository.save(FactoryDefaults.shapeCatalog()); + shapeRepository.save(FactoryDefaults.shapeDataset()); + shapeRepository.save(FactoryDefaults.shapeDistribution()); + } + + private void restoreDefaultResourceDefinitions() { + log.debug("Creating default resource definitions"); + resourceDefinitionRepository.save(FactoryDefaults.RESOURCE_DEFINITION_REPOSITORY); + resourceDefinitionRepository.save(FactoryDefaults.RESOURCE_DEFINITION_CATALOG); + resourceDefinitionRepository.save(FactoryDefaults.RESOURCE_DEFINITION_DATASET); + resourceDefinitionRepository.save(FactoryDefaults.RESOURCE_DEFINITION_DISTRIBUTION); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCache.java b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCache.java new file mode 100644 index 0000000000000000000000000000000000000000..fd2cbbd63df36ec0e685446c221cc1d4edc75fe9 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCache.java @@ -0,0 +1,108 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import lombok.Getter; +import lombok.Setter; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.validation.constraints.NotNull; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static nl.dtls.fairdatapoint.config.CacheConfig.RESOURCE_DEFINITION_CACHE; +import static nl.dtls.fairdatapoint.config.CacheConfig.RESOURCE_DEFINITION_PARENT_CACHE; + +@Service +public class ResourceDefinitionCache { + + @Getter + private static class ResourceDefinitionParents { + private final HashSet<ResourceDefinition> parents = new HashSet<>(); + + public void add(ResourceDefinition rdParent) { + parents.add(rdParent); + } + } + + @Autowired + private ConcurrentMapCacheManager cacheManager; + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @PostConstruct + public void computeCache() { + // Get cache + Cache cache = cache(); + Cache parentCache = parentCache(); + + // Clear cache + cache.clear(); + parentCache.clear(); + + // Add to cache + List<ResourceDefinition> rds = resourceDefinitionRepository.findAll(); + rds.forEach(rd -> { + parentCache.put(rd.getUuid(), new ResourceDefinitionParents()); + }); + rds.forEach(rd -> { + cache.put(rd.getUuid(), rd); + rd.getChildren().forEach(c -> parentCache.get(c.getResourceDefinitionUuid(), ResourceDefinitionParents.class).add(rd)); + }); + } + + public ResourceDefinition getByUuid(String uuid) { + return cache().get(uuid, ResourceDefinition.class); + } + + public Set<ResourceDefinition> getParentsByUuid(String uuid) { + var parents = parentCache().get(uuid, ResourceDefinitionParents.class); + if (parents == null) { + computeCache(); // Try to recompute cache (the object should be there) + parents = parentCache().get(uuid, ResourceDefinitionParents.class); + if (parents == null) { + return Collections.emptySet(); + } + } + return parents.getParents(); + } + + private Cache cache() { + return cacheManager.getCache(RESOURCE_DEFINITION_CACHE); + } + + private Cache parentCache() { + return cacheManager.getCache(RESOURCE_DEFINITION_PARENT_CACHE); + } + + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..04d464840c1e2bb59f439ccb65d0490d9e6a6a30 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionMapper.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionChangeDTO; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionDTO; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ResourceDefinitionMapper { + + public ResourceDefinition fromChangeDTO(ResourceDefinitionChangeDTO dto, String uuid) { + return new ResourceDefinition( + uuid, + dto.getName(), + dto.getUrlPrefix(), + dto.getShapeUuids(), + dto.getChildren(), + dto.getExternalLinks()); + } + + public ResourceDefinitionChangeDTO toChangeDTO(ResourceDefinition rd) { + return new ResourceDefinitionChangeDTO( + rd.getName(), + rd.getUrlPrefix(), + rd.getShapeUuids(), + rd.getChildren(), + rd.getExternalLinks()); + } + + public ResourceDefinitionDTO toDTO(ResourceDefinition rd, List<String> targetClassUris) { + return new ResourceDefinitionDTO( + rd.getUuid(), + rd.getName(), + rd.getUrlPrefix(), + rd.getShapeUuids(), + targetClassUris, + rd.getChildren(), + rd.getExternalLinks() + ); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionService.java b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionService.java index 4e4a57ebf3e4e5a96ea0c947421d30544f6d6631..ac34448246b13913f5831846beca2d9157ae9f74 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionService.java @@ -22,39 +22,173 @@ */ package nl.dtls.fairdatapoint.service.resource; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionChangeDTO; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionDTO; import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.membership.MembershipService; +import nl.dtls.fairdatapoint.service.openapi.OpenApiService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Service; +import org.springframework.validation.BindException; -import java.util.Optional; +import java.util.*; +import java.util.stream.Collectors; import static java.lang.String.format; @Service public class ResourceDefinitionService { + @Autowired + @Qualifier("persistentUrl") + private String persistentUrl; + @Autowired private ResourceDefinitionRepository resourceDefinitionRepository; - public ResourceDefinition getByUuid(String uuid) { - Optional<ResourceDefinition> oRd = resourceDefinitionRepository.findByUuid(uuid); + @Autowired + private ResourceDefinitionValidator resourceDefinitionValidator; + + @Autowired + private ResourceDefinitionMapper resourceDefinitionMapper; + + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + + @Autowired + private ResourceDefinitionTargetClassesCache targetClassesCache; + + @Autowired + private MembershipService membershipService; + + @Autowired + private OpenApiService openApiService; + + public ResourceDefinitionDTO toDTO(ResourceDefinition rd) { + return resourceDefinitionMapper.toDTO(rd, getTargetClassUris(rd)); + } + + public List<ResourceDefinitionDTO> getAll() { + return resourceDefinitionRepository + .findAll() + .stream() + .map(this::toDTO) + .toList(); + } + + public Optional<ResourceDefinition> getByUuid(String uuid) { + return resourceDefinitionRepository.findByUuid(uuid); + } + + public Optional<ResourceDefinitionDTO> getDTOByUuid(String uuid) { + return getByUuid(uuid).map(this::toDTO); + } + + public ResourceDefinition getByUrl(String url) { + String[] parts = url.replace(persistentUrl, "").split("/"); + String parentPrefix = ""; // Repository + if (parts.length > 1 && parts[0].isEmpty()) { + parentPrefix = parts[1]; // Other prefix (first empty caused by leading /) + } else if (parts.length > 0) { + parentPrefix = parts[0]; // Other prefix + } + return getByUrlPrefix(parentPrefix); + } + + public ResourceDefinition getByUrlPrefix(String urlPrefix) { + Optional<ResourceDefinition> oRd = resourceDefinitionRepository.findByUrlPrefix(urlPrefix); if (oRd.isEmpty()) { - throw new IllegalStateException( - format("Resource with provided uuid ('%s') is not defined", uuid) + throw new ResourceNotFoundException( + format("Resource with provided uri prefix ('%s') is not defined", urlPrefix) ); } return oRd.get(); } - public ResourceDefinition getByUriPrefix(String uriPrefix) { - Optional<ResourceDefinition> oRd = resourceDefinitionRepository.findByUriPrefix(uriPrefix); + @PreAuthorize("hasRole('ADMIN')") + public ResourceDefinitionDTO create(ResourceDefinitionChangeDTO reqDto) throws BindException { + String uuid = UUID.randomUUID().toString(); + ResourceDefinition rd = resourceDefinitionMapper.fromChangeDTO(reqDto, uuid); + + // TODO: check if shapes exist + + resourceDefinitionValidator.validate(rd); + resourceDefinitionRepository.save(rd); + resourceDefinitionCache.computeCache(); + targetClassesCache.computeCache(); + + membershipService.addToMembership(rd); + openApiService.updateGenericPaths(rd); + return toDTO(rd); + } + + @PreAuthorize("hasRole('ADMIN')") + public Optional<ResourceDefinitionDTO> update(String uuid, ResourceDefinitionChangeDTO reqDto) throws BindException { + Optional<ResourceDefinition> oRd = resourceDefinitionRepository.findByUuid(uuid); if (oRd.isEmpty()) { - throw new IllegalStateException( - format("Resource with provided uri prefix ('%s') is not defined", uriPrefix) - ); + return Optional.empty(); } - return oRd.get(); + ResourceDefinition rd = oRd.get(); + ResourceDefinition updatedRd = resourceDefinitionMapper.fromChangeDTO(reqDto, rd.getUuid()); + updatedRd.setId(rd.getId()); + + // TODO: check if shapes exist + + resourceDefinitionValidator.validate(updatedRd); + resourceDefinitionRepository.save(updatedRd); + resourceDefinitionCache.computeCache(); + targetClassesCache.computeCache(); + openApiService.updateGenericPaths(updatedRd); + return Optional.of(updatedRd).map(this::toDTO); + } + + @PreAuthorize("hasRole('ADMIN')") + public boolean deleteByUuid(String uuid) { + // 1. Get resource definition + Optional<ResourceDefinition> oRd = resourceDefinitionRepository.findByUuid(uuid); + if (oRd.isEmpty()) { + return false; + } + ResourceDefinition rd = oRd.get(); + + // 2. Delete from parent resource definitions + Set<ResourceDefinition> rdParents = resourceDefinitionCache.getParentsByUuid(rd.getUuid()); + rdParents.forEach(rdParent -> { + rdParent = resourceDefinitionRepository.findByUuid(rdParent.getUuid()).get(); + rdParent.setChildren( + rdParent.getChildren() + .stream() + .filter(x -> !x.getResourceDefinitionUuid().equals(rd.getUuid())) + .collect(Collectors.toList()) + ); + resourceDefinitionRepository.save(rdParent); + }); + + // 3. Delete resource definition + resourceDefinitionRepository.delete(rd); + + // 4. Delete entity from membership + membershipService.removeFromMembership(rd); + + // 5. Recompute cache + resourceDefinitionCache.computeCache(); + targetClassesCache.computeCache(); + + // 6. Delete from OpenAPI docs + openApiService.removeGenericPaths(rd); + return true; } + public List<String> getTargetClassUris(ResourceDefinition rd) { + List<String> result = targetClassesCache.getByUuid(rd.getUuid()); + if (result == null) { + targetClassesCache.computeCache(); + return targetClassesCache.getByUuid(rd.getUuid()); + } + return result; + } } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionTargetClassesCache.java b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionTargetClassesCache.java new file mode 100644 index 0000000000000000000000000000000000000000..6b22f4c23354d33178909b4a6f1767a45dc5be67 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionTargetClassesCache.java @@ -0,0 +1,83 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.shape.Shape; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +import static nl.dtls.fairdatapoint.config.CacheConfig.RESOURCE_DEFINITION_TARGET_CLASSES_CACHE; + +@Service +public class ResourceDefinitionTargetClassesCache { + + @Autowired + private ConcurrentMapCacheManager cacheManager; + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Autowired + private ShapeRepository shapeRepository; + + @PostConstruct + public void computeCache() { + // Get cache + Cache cache = cache(); + + // Clear cache + cache.clear(); + + // Add to cache + List<ResourceDefinition> rds = resourceDefinitionRepository.findAll(); + Map<String, Shape> shapes = shapeRepository.findAll().stream().collect(Collectors.toMap(Shape::getUuid, Function.identity())); + rds.forEach(rd -> { + Set<String> targetClassUris = new HashSet<>(); + rd.getShapeUuids().forEach(shapeUuid -> { + if (shapes.containsKey(shapeUuid)) { + targetClassUris.addAll(shapes.get(shapeUuid).getTargetClasses()); + } + }); + cache.put(rd.getUuid(), targetClassUris.stream().toList()); + }); + } + + public List<String> getByUuid(String uuid) { + return cache().get(uuid, List.class); + } + + private Cache cache() { + return cacheManager.getCache(RESOURCE_DEFINITION_TARGET_CLASSES_CACHE); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidator.java b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..a15c1153b371fcba9892bd3b9c34c74c19b09f21 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidator.java @@ -0,0 +1,85 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.validation.BindException; + +import java.util.List; +import java.util.Optional; + +import static nl.dtls.fairdatapoint.util.ValidationUtil.uniquenessValidationFailed; + +@Service +public class ResourceDefinitionValidator { + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + + public void validate(ResourceDefinition reqDto) throws BindException { + // Check uniqueness + Optional<ResourceDefinition> oRdByName = resourceDefinitionRepository.findByName(reqDto.getName()); + if (oRdByName.isPresent() && !oRdByName.get().getUuid().equals(reqDto.getUuid())) { + uniquenessValidationFailed("name", reqDto); + } + Optional<ResourceDefinition> oRdByUrlPrefix = + resourceDefinitionRepository.findByUrlPrefix(reqDto.getUrlPrefix()); + if (oRdByUrlPrefix.isPresent() && !oRdByUrlPrefix.get().getUuid().equals(reqDto.getUuid())) { + uniquenessValidationFailed("urlPrefix", reqDto); + } + + // Check existence of connected entities + for (ResourceDefinitionChild child : reqDto.getChildren()) { + if (resourceDefinitionCache.getByUuid(child.getResourceDefinitionUuid()) == null) { + throw new ValidationException("Child doesn't exist"); + } + } + + // Check existence of dependency cycles + validateDependencyCycles(reqDto, reqDto.getChildren()); + } + + private void validateDependencyCycles(ResourceDefinition reqDto, List<ResourceDefinitionChild> children) { + for (ResourceDefinitionChild child : children) { + String childUuid = child.getResourceDefinitionUuid(); + if (reqDto.getUuid().equals(childUuid)) { + throw new ValidationException("Detect dependency cycle through child"); + } + + ResourceDefinition rdChild = resourceDefinitionCache.getByUuid(childUuid); + if (rdChild.getChildren().isEmpty()) { + return; + } + validateDependencyCycles(reqDto, rdChild.getChildren()); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/search/SearchService.java b/src/main/java/nl/dtls/fairdatapoint/service/search/SearchService.java new file mode 100644 index 0000000000000000000000000000000000000000..1960a00280e1f3ca83ae92f0f3305c55d1d11545 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/search/SearchService.java @@ -0,0 +1,84 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.search; + +import nl.dtls.fairdatapoint.api.dto.search.SearchQueryDTO; +import nl.dtls.fairdatapoint.api.dto.search.SearchResultDTO; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import nl.dtls.fairdatapoint.entity.search.SearchResult; +import nl.dtls.fairdatapoint.service.metadata.state.MetadataStateService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.stream.Collectors.toList; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.l; + +@Service +public class SearchService { + + @Autowired + private GenericMetadataRepository metadataRepository; + + @Autowired + private MetadataStateService metadataStateService; + + public List<SearchResultDTO> search(SearchQueryDTO reqDto) throws MetadataRepositoryException { + return metadataRepository.findByLiteral(l(reqDto.getQ())) + .stream() + .collect(Collectors.groupingBy(SearchResult::getUri, Collectors.mapping(i -> i, toList()))) + .entrySet() + .stream() + .filter(entry -> { + try { + return !metadataStateService.get(i(entry.getKey())).getState().equals(MetadataState.DRAFT); + } catch (ResourceNotFoundException e) { + return true; + } + }) + .map(entry -> new SearchResultDTO( + entry.getKey(), + entry.getValue() + .stream() + .map(SearchResult::getType) + .distinct() + .filter(t -> !t.equals("http://www.w3.org/ns/dcat#Resource")) + .collect(Collectors.toList()), + entry.getValue().get(0).getTitle(), + entry.getValue().get(0).getDescription(), + entry.getValue() + .stream() + .map(SearchResult::getRelation) + .distinct() + .collect(Collectors.toList()) + )) + .collect(toList()); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/security/MongoUserDetailsService.java b/src/main/java/nl/dtls/fairdatapoint/service/security/MongoUserDetailsService.java index a95737cc6d52a697b295a5721592a8cef2acf959..b41478b0f75a90627b9622f0ad151051dede6f26 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/security/MongoUserDetailsService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/security/MongoUserDetailsService.java @@ -23,12 +23,12 @@ package nl.dtls.fairdatapoint.service.security; import nl.dtls.fairdatapoint.database.mongo.repository.UserRepository; +import nl.dtls.fairdatapoint.entity.exception.UnauthorizedException; import nl.dtls.fairdatapoint.entity.user.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.List; @@ -43,10 +43,10 @@ public class MongoUserDetailsService implements UserDetailsService { private UserRepository repository; @Override - public UserDetails loadUserByUsername(String uuid) throws UsernameNotFoundException { + public UserDetails loadUserByUsername(String uuid) { Optional<User> oUser = repository.findByUuid(uuid); if (oUser.isEmpty()) { - throw new UsernameNotFoundException("User not found"); + throw new UnauthorizedException("User not found"); } User user = oUser.get(); List<SimpleGrantedAuthority> authorities = List.of(new SimpleGrantedAuthority(format("ROLE_%s", diff --git a/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsCache.java b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsCache.java new file mode 100644 index 0000000000000000000000000000000000000000..93b7f1f8c229b13a2325a7b47cff8d4eb7881ce2 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsCache.java @@ -0,0 +1,71 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.settings; + +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.concurrent.ConcurrentMapCacheManager; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.List; + +import static nl.dtls.fairdatapoint.config.CacheConfig.SETTINGS_CACHE; + +@Service +public class SettingsCache { + + @Autowired + private ConcurrentMapCacheManager cacheManager; + + @Autowired + private SettingsRepository settingsRepository; + + private static final String SETTINGS_KEY = "settings"; + + @PostConstruct + public void updateCachedSettings() { + updateCachedSettings(settingsRepository.findFirstBy().orElse(Settings.getDefault())); + } + + public void updateCachedSettings(Settings settings) { + // Get cache + Cache cache = cache(); + + // Clear cache + cache.clear(); + + // Add to cache + cache.put(SETTINGS_KEY, settings); + } + + public Settings getOrDefaults() { + return cache().get(SETTINGS_KEY, Settings.class); + } + + private Cache cache() { + return cacheManager.getCache(SETTINGS_CACHE); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..784860fac5535c9dd4ca087d866119e172d6811f --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsMapper.java @@ -0,0 +1,104 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.settings; + +import nl.dtls.fairdatapoint.api.dto.settings.*; +import nl.dtls.fairdatapoint.config.properties.InstanceProperties; +import nl.dtls.fairdatapoint.config.properties.PingProperties; +import nl.dtls.fairdatapoint.config.properties.RepositoryProperties; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.entity.settings.SettingsPing; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class SettingsMapper { + + @Autowired + private InstanceProperties instanceProperties; + + @Autowired + private PingProperties pingProperties; + + @Autowired + private RepositoryProperties repositoryProperties; + + public SettingsDTO toDTO(Settings settings) { + return new SettingsDTO( + instanceProperties.getClientUrl(), + instanceProperties.getPersistentUrl(), + settings.getMetadataMetrics(), + toDTO(settings.getPing()), + getRepositoryDTO() + ); + } + + public SettingsPingDTO toDTO(SettingsPing settingsPing) { + return new SettingsPingDTO( + settingsPing.isEnabled(), + settingsPing.getEndpoints(), + pingProperties.getInterval().toString() + ); + } + + public SettingsRepositoryDTO getRepositoryDTO() { + return new SettingsRepositoryDTO( + repositoryProperties.getStringType(), + repositoryProperties.getDir(), + repositoryProperties.getUrl(), + repositoryProperties.getRepository(), + repositoryProperties.getUsername(), + repositoryProperties.getPassword() != null ? "<SECRET>" : null + ); + } + + public Settings fromUpdateDTO(SettingsUpdateDTO dto, Settings settings) { + return settings.toBuilder() + .metadataMetrics(dto.getMetadataMetrics()) + .ping(fromUpdateDTO(dto.getPing(), settings.getPing())) + .build(); + } + + public SettingsPing fromUpdateDTO(SettingsPingUpdateDTO dto, SettingsPing settingsPing) { + return settingsPing.toBuilder() + .enabled(dto.isEnabled()) + .endpoints(dto.getEndpoints()) + .build(); + } + + public SettingsUpdateDTO toUpdateDTO(Settings settings) { + return new SettingsUpdateDTO( + settings.getMetadataMetrics(), + toUpdateDTO(settings.getPing()) + ); + } + + public SettingsPingUpdateDTO toUpdateDTO(SettingsPing settingsPing) { + return new SettingsPingUpdateDTO( + settingsPing.isEnabled(), + settingsPing.getEndpoints() + ); + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsService.java b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsService.java new file mode 100644 index 0000000000000000000000000000000000000000..bc50a60c22f89ce40f9dbfa99f014265ef92018e --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/settings/SettingsService.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.settings; + +import nl.dtls.fairdatapoint.api.dto.settings.SettingsDTO; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsUpdateDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class SettingsService { + + @Autowired + private SettingsRepository repository; + + @Autowired + private SettingsMapper mapper; + + @Autowired + private SettingsCache cache; + + public Settings getOrDefaults() { + return cache.getOrDefaults(); + } + + public SettingsDTO getCurrentSettings() { + return mapper.toDTO(getOrDefaults()); + } + + public SettingsDTO updateSettings(SettingsUpdateDTO dto) { + Settings settings = repository.save(mapper.fromUpdateDTO(dto, getOrDefaults())); + cache.updateCachedSettings(settings); + return mapper.toDTO(settings); + } + + public SettingsDTO resetSettings() { + return updateSettings(mapper.toUpdateDTO(Settings.getDefault())); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeMapper.java index c85723efcc9e96da4bbf26d7d52b0a3b5c2d3119..7e068de5e3e83e2aac029b8eb78ee087c489ac78 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeMapper.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeMapper.java @@ -24,6 +24,7 @@ package nl.dtls.fairdatapoint.service.shape; import nl.dtls.fairdatapoint.api.dto.shape.ShapeChangeDTO; import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeRemoteDTO; import nl.dtls.fairdatapoint.entity.shape.Shape; import nl.dtls.fairdatapoint.entity.shape.ShapeType; import org.springframework.stereotype.Service; @@ -36,8 +37,11 @@ public class ShapeMapper { new ShapeDTO( shape.getUuid(), shape.getName(), + shape.isPublished(), shape.getType(), - shape.getDefinition()); + shape.getDefinition(), + shape.getTargetClasses().stream().sorted().toList() + ); } public Shape fromChangeDTO(ShapeChangeDTO dto, String uuid) { @@ -46,8 +50,11 @@ public class ShapeMapper { null, uuid, dto.getName(), + dto.isPublished(), ShapeType.CUSTOM, - dto.getDefinition()); + dto.getDefinition(), + ShapeShaclUtils.extractTargetClasses(dto.getDefinition()) + ); } @@ -56,7 +63,28 @@ public class ShapeMapper { shape .toBuilder() .name(dto.getName()) + .published(dto.isPublished()) .definition(dto.getDefinition()) + .targetClasses(ShapeShaclUtils.extractTargetClasses(dto.getDefinition())) .build(); } + + public ShapeRemoteDTO toRemoteDTO(String fdpUrl, ShapeDTO shape) { + return + new ShapeRemoteDTO( + fdpUrl, + shape.getUuid(), + shape.getName(), + shape.getDefinition() + ); + } + + public ShapeChangeDTO fromRemoteDTO(ShapeRemoteDTO shape) { + return + new ShapeChangeDTO( + shape.getName(), + false, + shape.getDefinition() + ); + } } diff --git a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeRetrievalUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeRetrievalUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..fffe2a27bb5178284bf18984e50a7a7a7fb6d056 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeRetrievalUtils.java @@ -0,0 +1,70 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.shape; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.entity.exception.ShapeImportException; +import org.springframework.http.HttpHeaders; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Optional; + +public class ShapeRetrievalUtils { + + private static final HttpClient client = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .followRedirects(HttpClient.Redirect.ALWAYS) + .connectTimeout(Duration.ofMinutes(1)) + .build(); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final TypeReference<List<ShapeDTO>> responseType = new TypeReference<>() { + }; + + public static List<ShapeDTO> retrievePublishedShapes(String fdpUrl) { + try { + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(fdpUrl.replaceAll("/$", "") + "/shapes/public")) + .header(HttpHeaders.ACCEPT, "application/json") + .GET().build(); + HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); + return objectMapper.readValue(response.body(), responseType); + } catch (JsonProcessingException e) { + throw new ShapeImportException(fdpUrl, "Cannot process response: " + e.getMessage()); + } catch (IOException e) { + throw new ShapeImportException(fdpUrl, "Cannot get response: " + e.getMessage()); + } catch (Exception e) { + throw new ShapeImportException(fdpUrl, e.getMessage()); + } + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeService.java b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeService.java index 3c500a2916c912bfa4421650fe975c2b34f77ed0..2d0d23534fbed5103874993c52bc62cba331ba0a 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeService.java @@ -24,10 +24,15 @@ package nl.dtls.fairdatapoint.service.shape; import nl.dtls.fairdatapoint.api.dto.shape.ShapeChangeDTO; import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeRemoteDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; +import nl.dtls.fairdatapoint.entity.exception.ShapeImportException; import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.entity.shape.Shape; import nl.dtls.fairdatapoint.entity.shape.ShapeType; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionTargetClassesCache; import nl.dtls.fairdatapoint.util.RdfIOUtil; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.impl.LinkedHashModel; @@ -39,7 +44,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; +import java.util.stream.Collectors; +import static java.lang.String.format; import static java.util.Optional.empty; import static java.util.Optional.of; import static java.util.stream.Collectors.toList; @@ -50,12 +57,18 @@ public class ShapeService { @Autowired private ShapeRepository shapeRepository; + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + @Autowired private ShapeMapper shapeMapper; @Autowired private ShapeValidator shapeValidator; + @Autowired + private ResourceDefinitionTargetClassesCache targetClassesCache; + public List<ShapeDTO> getShapes() { List<Shape> shapes = shapeRepository.findAll(); return @@ -65,6 +78,15 @@ public class ShapeService { .collect(toList()); } + public List<ShapeDTO> getPublishedShapes() { + List<Shape> shapes = shapeRepository.findAllByPublishedIsTrue(); + return + shapes + .stream() + .map(shapeMapper::toDTO) + .collect(toList()); + } + public Optional<ShapeDTO> getShapeByUuid(String uuid) { return shapeRepository @@ -72,12 +94,20 @@ public class ShapeService { .map(shapeMapper::toDTO); } + public Optional<Model> getShapeContentByUuid(String uuid) { + return + shapeRepository + .findByUuid(uuid) + .map(shape -> RdfIOUtil.read(shape.getDefinition(), "")); + } + @PreAuthorize("hasRole('ADMIN')") public ShapeDTO createShape(ShapeChangeDTO reqDto) { shapeValidator.validate(reqDto); String uuid = UUID.randomUUID().toString(); Shape shape = shapeMapper.fromChangeDTO(reqDto, uuid); shapeRepository.save(shape); + targetClassesCache.computeCache(); return shapeMapper.toDTO(shape); } @@ -89,12 +119,9 @@ public class ShapeService { return empty(); } Shape shape = oShape.get(); - if (shape.getType() == ShapeType.INTERNAL) { - throw new ValidationException("You can't edit INTERNAL Shape"); - } - Shape updatedShape = shapeMapper.fromChangeDTO(reqDto, shape); shapeRepository.save(updatedShape); + targetClassesCache.computeCache(); return of(shapeMapper.toDTO(updatedShape)); } @@ -105,7 +132,17 @@ public class ShapeService { return false; } Shape shape = oShape.get(); + + List<ResourceDefinition> resourceDefinitions = resourceDefinitionRepository.findByShapeUuidsIsContaining(shape.getUuid()); + if (!resourceDefinitions.isEmpty()) { + throw new ValidationException(format("Shape is used in %d resource definitions", resourceDefinitions.size())); + } + + if (shape.getType() == ShapeType.INTERNAL) { + throw new ValidationException("You can't delete INTERNAL Shape"); + } shapeRepository.delete(shape); + targetClassesCache.computeCache(); return true; } @@ -118,4 +155,30 @@ public class ShapeService { return shacl; } -} \ No newline at end of file + public List<ShapeRemoteDTO> getRemoteShapes(String fdpUrl) { + List<ShapeDTO> shapes = ShapeRetrievalUtils.retrievePublishedShapes(fdpUrl); + return shapes + .stream() + .map(s -> shapeMapper.toRemoteDTO(fdpUrl, s)) + .collect(Collectors.toList()); + } + + private ShapeDTO importShape(ShapeChangeDTO reqDto) { + shapeValidator.validate(reqDto); + String uuid = UUID.randomUUID().toString(); + Shape shape = shapeMapper.fromChangeDTO(reqDto, uuid); + shapeRepository.save(shape); + return shapeMapper.toDTO(shape); + } + + public List<ShapeDTO> importShapes(List<ShapeRemoteDTO> reqDtos) { + List<ShapeDTO> result = + reqDtos + .stream() + .map(s -> shapeMapper.fromRemoteDTO(s)) + .map(this::importShape) + .collect(Collectors.toList()); + targetClassesCache.computeCache(); + return result; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeShaclUtils.java b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeShaclUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..6a6f1da22df7698968aefd6bb4ac574fbf534de1 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/shape/ShapeShaclUtils.java @@ -0,0 +1,59 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.shape; + +import nl.dtls.fairdatapoint.util.RdfIOUtil; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.Resource; +import org.eclipse.rdf4j.model.Value; +import org.eclipse.rdf4j.model.vocabulary.SHACL; + +import java.util.Set; +import java.util.stream.Collectors; + +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; + +public class ShapeShaclUtils { + + public static Set<String> extractTargetClasses(String definition) { + var model = RdfIOUtil.read(definition, ""); + return model + .filter(null, SHACL.TARGET_CLASS, null) + .objects() + .stream() + .map(Value::stringValue) + .filter(iri -> isRootNodeOfTargetClass(model, iri)) + .collect(Collectors.toSet()); + } + + private static boolean isRootNodeOfTargetClass(Model model, String iri) { + var resource = i(iri); + for (Resource subject : model.filter(null, null, resource).subjects()) { + if (model.contains(null, null, subject)) { + return false; + } + } + return true; + } +} diff --git a/src/main/java/nl/dtls/fairdatapoint/service/user/UserMapper.java b/src/main/java/nl/dtls/fairdatapoint/service/user/UserMapper.java index 829f131bf15d972776f26e27cc725e900de62dfe..94107ce2f4bf750e327aa9645d993bc37d35167d 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/user/UserMapper.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/user/UserMapper.java @@ -75,6 +75,16 @@ public class UserMapper { .build(); } + public User fromProfileChangeDTO(UserProfileChangeDTO dto, User user) { + return + user + .toBuilder() + .firstName(dto.getFirstName()) + .lastName(dto.getLastName()) + .email(dto.getEmail()) + .build(); + } + public User fromPasswordDTO(UserPasswordDTO reqDto, User user) { return user diff --git a/src/main/java/nl/dtls/fairdatapoint/service/user/UserService.java b/src/main/java/nl/dtls/fairdatapoint/service/user/UserService.java index 322a1f355d3a2396bfcc83492ce86ae6f8cd6457..97e09d9b0a55d926e1e6298a06517762cab12a17 100755 --- a/src/main/java/nl/dtls/fairdatapoint/service/user/UserService.java +++ b/src/main/java/nl/dtls/fairdatapoint/service/user/UserService.java @@ -22,12 +22,8 @@ */ package nl.dtls.fairdatapoint.service.user; -import nl.dtls.fairdatapoint.api.dto.user.UserChangeDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserCreateDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserDTO; -import nl.dtls.fairdatapoint.api.dto.user.UserPasswordDTO; +import nl.dtls.fairdatapoint.api.dto.user.*; import nl.dtls.fairdatapoint.database.mongo.repository.UserRepository; -import nl.dtls.fairdatapoint.entity.exception.ValidationException; import nl.dtls.fairdatapoint.entity.user.User; import nl.dtls.fairdatapoint.service.member.MemberService; import org.springframework.beans.factory.annotation.Autowired; @@ -39,7 +35,6 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import static java.lang.String.format; import static java.util.Optional.empty; import static java.util.Optional.of; import static java.util.stream.Collectors.toList; @@ -53,6 +48,9 @@ public class UserService { @Autowired private UserMapper userMapper; + @Autowired + private UserValidator userValidator; + @Autowired private MemberService memberService; @@ -87,10 +85,7 @@ public class UserService { @PreAuthorize("hasRole('ADMIN')") public UserDTO createUser(UserCreateDTO reqDto) { - Optional<User> oUser = userRepository.findByEmail(reqDto.getEmail()); - if (oUser.isPresent()) { - throw new ValidationException(format("Email '%s' is already taken", reqDto.getEmail())); - } + userValidator.validateEmail(null, reqDto.getEmail()); String uuid = UUID.randomUUID().toString(); User user = userMapper.fromCreateDTO(reqDto, uuid); userRepository.save(user); @@ -99,20 +94,29 @@ public class UserService { @PreAuthorize("hasRole('ADMIN')") public Optional<UserDTO> updateUser(String uuid, UserChangeDTO reqDto) { - Optional<User> oUserEmail = userRepository.findByEmail(reqDto.getEmail()); - if (oUserEmail.isPresent() && !uuid.equals(oUserEmail.get().getUuid())) { - throw new ValidationException(format("Email '%s' is already taken", reqDto.getEmail())); - } Optional<User> oUser = userRepository.findByUuid(uuid); if (oUser.isEmpty()) { return empty(); } User user = oUser.get(); + userValidator.validateEmail(uuid, reqDto.getEmail()); User updatedUser = userMapper.fromChangeDTO(reqDto, user); userRepository.save(updatedUser); return of(userMapper.toDTO(updatedUser)); } + public Optional<UserDTO> updateCurrentUser(UserProfileChangeDTO reqDto) { + Optional<User> oUser = getCurrentUserUuid().flatMap(uuid -> userRepository.findByUuid(uuid)); + if (oUser.isEmpty()) { + return empty(); + } + User user = oUser.get(); + userValidator.validateEmail(user.getUuid(), reqDto.getEmail()); + User updatedUser = userMapper.fromProfileChangeDTO(reqDto, user); + userRepository.save(updatedUser); + return of(userMapper.toDTO(updatedUser)); + } + @PreAuthorize("hasRole('ADMIN')") public Optional<UserDTO> updatePassword(String uuid, UserPasswordDTO reqDto) { Optional<User> oUser = userRepository.findByUuid(uuid); @@ -125,6 +129,17 @@ public class UserService { return of(userMapper.toDTO(updatedUser)); } + public Optional<UserDTO> updatePasswordForCurrentUser(UserPasswordDTO reqDto) { + Optional<User> oUser = getCurrentUserUuid().flatMap(uuid -> userRepository.findByUuid(uuid)); + if (oUser.isEmpty()) { + return empty(); + } + User user = oUser.get(); + User updatedUser = userMapper.fromPasswordDTO(reqDto, user); + userRepository.save(updatedUser); + return of(userMapper.toDTO(updatedUser)); + } + @PreAuthorize("hasRole('ADMIN')") public boolean deleteUser(String uuid) { Optional<User> oUser = userRepository.findByUuid(uuid); diff --git a/src/main/java/nl/dtls/fairdatapoint/service/user/UserValidator.java b/src/main/java/nl/dtls/fairdatapoint/service/user/UserValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..f904d38bf6f87292f7bca88e07c68155c6086422 --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/service/user/UserValidator.java @@ -0,0 +1,48 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.user; + +import nl.dtls.fairdatapoint.database.mongo.repository.UserRepository; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.user.User; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +import static java.lang.String.format; + +@Service +public class UserValidator { + + @Autowired + private UserRepository userRepository; + + public void validateEmail(String uuid, String email) { + Optional<User> oUserEmail = userRepository.findByEmail(email); + if (oUserEmail.isPresent() && !oUserEmail.get().getUuid().equals(uuid)) { + throw new ValidationException(format("Email '%s' is already taken", email)); + } + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/util/HttpUtil.java b/src/main/java/nl/dtls/fairdatapoint/util/HttpUtil.java index bf0c8ca0b7264edf8089f5c541e8b7317dc27780..03c81ed80a84461f80683cddd21db5eda5c0fff3 100755 --- a/src/main/java/nl/dtls/fairdatapoint/util/HttpUtil.java +++ b/src/main/java/nl/dtls/fairdatapoint/util/HttpUtil.java @@ -26,27 +26,57 @@ import lombok.extern.slf4j.Slf4j; import nl.dtls.fairdatapoint.entity.exception.ValidationException; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.rio.RDFFormat; +import org.springframework.http.HttpHeaders; import javax.servlet.http.HttpServletRequest; import java.net.MalformedURLException; import java.net.URL; import java.util.UUID; +import static java.util.Optional.of; +import static java.util.Optional.ofNullable; import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; @Slf4j public class HttpUtil { + private static final String[] IP_HEADER_CANDIDATES = { + "X-Forwarded-For", + "X-Real-IP", + "Proxy-Client-IP", + "WL-Proxy-Client-IP", + "HTTP_X_FORWARDED_FOR", + "HTTP_X_FORWARDED", + "HTTP_X_CLUSTER_CLIENT_IP", + "HTTP_CLIENT_IP", + "HTTP_FORWARDED_FOR", + "HTTP_FORWARDED", + "HTTP_VIA", + "REMOTE_ADDR" + }; + + public static String getClientIpAddress(HttpServletRequest request, Boolean behindProxy) { + if (behindProxy) { + for (String header : IP_HEADER_CANDIDATES) { + String ipList = request.getHeader(header); + if (ipList != null && ipList.length() != 0 && !"unknown".equalsIgnoreCase(ipList)) { + return ipList.split(",")[0]; + } + } + } + return request.getRemoteAddr(); + } + public static String getRequestURL(HttpServletRequest request, String persistentUrl) { String urlS = request.getRequestURL().toString(); - log.info("Original requesed url {}", urlS); + log.info("Original requested url {}", urlS); try { urlS = removeLastSlash(urlS.replace("/expanded", "")); persistentUrl = removeLastSlash(persistentUrl); URL url = new URL(urlS); String modifiedUrl = persistentUrl + url.getPath(); - log.info("Modified requesed url {}", modifiedUrl); + log.info("Modified requested url {}", modifiedUrl); return modifiedUrl; @@ -65,20 +95,21 @@ public class HttpUtil { if (name == null) { return RDFFormat.TURTLE; } - switch (name) { - case "text/plain": - return RDFFormat.TURTLE; - case "text/turtle": - return RDFFormat.TURTLE; - case "application/ld+json": - return RDFFormat.JSONLD; - case "application/rdf+xml": - return RDFFormat.RDFXML; - case "text/n3": - return RDFFormat.N3; - default: - return RDFFormat.TURTLE; - } + return switch (name) { + case "text/plain" -> RDFFormat.TURTLE; + case "text/turtle" -> RDFFormat.TURTLE; + case "application/ld+json" -> RDFFormat.JSONLD; + case "application/rdf+xml" -> RDFFormat.RDFXML; + case "text/n3" -> RDFFormat.N3; + default -> RDFFormat.TURTLE; + }; + } + + public static String getToken(HttpServletRequest req) { + return ofNullable(req.getHeader(HttpHeaders.AUTHORIZATION)) + .filter(h -> h.startsWith("Bearer ")) + .flatMap(h -> of(h.substring(7))) + .orElse(null); } public static String removeLastSlash(String url) { diff --git a/src/main/java/nl/dtls/fairdatapoint/util/RdfIOUtil.java b/src/main/java/nl/dtls/fairdatapoint/util/RdfIOUtil.java index 6b9f444e151a7837522a741e20f65741fdb5fa67..b0dbcdb8c0ebc5b16f698c8715d664ebb84ada7a 100755 --- a/src/main/java/nl/dtls/fairdatapoint/util/RdfIOUtil.java +++ b/src/main/java/nl/dtls/fairdatapoint/util/RdfIOUtil.java @@ -27,7 +27,12 @@ import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Resource; import org.eclipse.rdf4j.model.Statement; import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.vocabulary.DCAT; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.FOAF; +import org.eclipse.rdf4j.model.vocabulary.LDP; import org.eclipse.rdf4j.model.vocabulary.RDF; +import org.eclipse.rdf4j.model.vocabulary.XMLSchema; import org.eclipse.rdf4j.rio.*; import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings; @@ -58,9 +63,15 @@ public class RdfIOUtil { .orElseThrow(() -> new ValidationException("Validation failed (no rdf:type was provided")); // - sanitize statements List<Statement> sanitizedStatements = - new ArrayList<>(oldModel.filter(oldBaseUri, null, null)) + new ArrayList<>(oldModel) .stream() - .map(oldStatement -> s(i(newBaseUri), oldStatement.getPredicate(), oldStatement.getObject())) + .map(oldStatement -> { + if (oldStatement.getSubject().stringValue().equals(oldBaseUri.stringValue())) { + return s(i(newBaseUri), oldStatement.getPredicate(), oldStatement.getObject()); + } else { + return oldStatement; + } + }) .collect(Collectors.toList()); Model model = new LinkedHashModel(); model.addAll(sanitizedStatements); @@ -105,6 +116,12 @@ public class RdfIOUtil { } public static String write(Model model, RDFFormat format) { + model.setNamespace(DCTERMS.NS); + model.setNamespace(DCAT.NS); + model.setNamespace(FOAF.NS); + model.setNamespace(XMLSchema.NS); + model.setNamespace(LDP.NS); + try (StringWriter out = new StringWriter()) { Rio.write(model, out, format, getWriterConfig()); return out.toString(); diff --git a/src/main/java/nl/dtls/fairdatapoint/util/RdfUtil.java b/src/main/java/nl/dtls/fairdatapoint/util/RdfUtil.java index 23281f2b7878b59525a8d4836f54c2d54fe13e07..706eacff0b438a12c3b6b8849f5d31c18e75526c 100755 --- a/src/main/java/nl/dtls/fairdatapoint/util/RdfUtil.java +++ b/src/main/java/nl/dtls/fairdatapoint/util/RdfUtil.java @@ -77,18 +77,20 @@ public class RdfUtil { /**************************************************** *** Update ****************************************************/ - public static void update(Model m, Resource subj, IRI pred, Value obj, Resource... contexts) { - m.remove(subj, pred, null, contexts); + public static void update(Model m, Resource subj, IRI pred, Value obj) { + m.remove(subj, pred, null); if (subj != null && pred != null && obj != null) { - m.add(subj, pred, obj, contexts); + m.add(subj, pred, obj); } } - public static <T extends Value> void update(Model m, Resource subj, IRI pred, List<T> list, Resource... contexts) { - m.remove(subj, pred, null, contexts); - list.forEach(obj -> { - m.add(subj, pred, obj, contexts); - }); + public static <T extends Value> void update(Model m, Resource subj, IRI pred, List<T> list) { + m.remove(subj, pred, null); + if (list != null) { + list.forEach(obj -> { + m.add(subj, pred, obj); + }); + } } /**************************************************** diff --git a/src/main/java/nl/dtls/fairdatapoint/util/ValidationUtil.java b/src/main/java/nl/dtls/fairdatapoint/util/ValidationUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..b55c7db5fdaa99c22fe51fcc62d9494967a8811c --- /dev/null +++ b/src/main/java/nl/dtls/fairdatapoint/util/ValidationUtil.java @@ -0,0 +1,42 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.util; + +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.BindException; + +public class ValidationUtil { + + public static <T> void validationFailed(String field, String code, String defaultMessage, T reqDto) throws BindException { + BeanPropertyBindingResult error = new BeanPropertyBindingResult(reqDto, reqDto.getClass().getName()); + error.rejectValue(field, code, defaultMessage); + throw new BindException(error); + } + + public static <T> void uniquenessValidationFailed(String field, T reqDto) throws BindException { + BeanPropertyBindingResult error = new BeanPropertyBindingResult(reqDto, reqDto.getClass().getName()); + error.rejectValue(field, "Uniqueness", "must be unique"); + throw new BindException(error); + } + +} diff --git a/src/main/java/nl/dtls/fairdatapoint/util/ValueFactoryHelper.java b/src/main/java/nl/dtls/fairdatapoint/util/ValueFactoryHelper.java index 5baa1e2cb6fe73773ee2cd17de844d03d6911e6a..eae3d1b9f83fdcabd945b5f527422a02b777f66d 100755 --- a/src/main/java/nl/dtls/fairdatapoint/util/ValueFactoryHelper.java +++ b/src/main/java/nl/dtls/fairdatapoint/util/ValueFactoryHelper.java @@ -24,8 +24,9 @@ package nl.dtls.fairdatapoint.util; import org.eclipse.rdf4j.model.*; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import org.eclipse.rdf4j.model.vocabulary.XMLSchema; -import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.util.Optional; @@ -98,8 +99,11 @@ public class ValueFactoryHelper { return VF.createLiteral(literal); } - public static Literal l(LocalDateTime literal) { - return VF.createLiteral(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(literal)); + public static Literal l(OffsetDateTime literal) { + if (literal == null) { + return null; + } + return VF.createLiteral(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(literal), XMLSchema.DATETIME); } public static Literal l(Value value) { @@ -116,4 +120,8 @@ public class ValueFactoryHelper { public static Statement s(Resource subject, IRI predicate, Value object, Resource context) { return VF.createStatement(subject, predicate, object, context); } + + public static Resource bn() { + return VF.createBNode(); + } } diff --git a/src/test/java/nl/dtls/fairdatapoint/WebIntegrationTest.java b/src/test/java/nl/dtls/fairdatapoint/WebIntegrationTest.java index b348b92dbe4de9d58d803a7dda4dce7984133fbd..fc47bde4890b0f7fdce1cab4cd3ba172392bc746 100755 --- a/src/test/java/nl/dtls/fairdatapoint/WebIntegrationTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/WebIntegrationTest.java @@ -23,37 +23,35 @@ package nl.dtls.fairdatapoint; import nl.dtls.fairdatapoint.database.mongo.migration.development.MigrationRunner; +import nl.dtls.fairdatapoint.database.rdf.migration.development.RdfDevelopmentMigrationRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit.jupiter.SpringExtension; @ExtendWith(SpringExtension.class) @ActiveProfiles(Profiles.TESTING) -// TODO Remove @DirtiesContext annotation -@DirtiesContext @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"spring.main.allow-bean-definition-overriding=true"}) @AutoConfigureMockMvc public abstract class WebIntegrationTest { - public static final String ADMIN_TOKEN = "Bearer eyJhbGciOiJIUzI1NiJ9" + - ".eyJzdWIiOiI5NTU4OWU1MC1kMjYxLTQ5MmItODg1Mi05MzI0ZTlhNjZhNDIiLCJpYXQiOjE1NzQyNTE5OTAsImV4cCI6MjQzODE2NTU5MH0" + - ".KHcGQqqTOzC9Xqzj07PRuTDa__c1BDC9obb-DKsSaQo"; + public static final String ADMIN_TOKEN = "Bearer eyJhbGciOiJIUzUxMiJ9" + + ".eyJzdWIiOiI5NTU4OWU1MC1kMjYxLTQ5MmItODg1Mi05MzI0ZTlhNjZhNDIiLCJpYXQiOjE2MjA4Mzg3NjUsImV4cCI6MjUzMzcwNzY4NDYxfQ" + + ".hF8SnFH_1m00bjQOja77OzPgpPbX-wJH8RUdcOOR7F-QrTRCqwOdrqDfgN1lFW0XrrIljIvYqCo20pcYTvh2Dw"; - public static final String ALBERT_TOKEN = "Bearer eyJhbGciOiJIUzI1NiJ9" + - ".eyJzdWIiOiI3ZTY0ODE4ZC02Mjc2LTQ2ZmItOGJiMS03MzJlNmUwOWY3ZTkiLCJpYXQiOjE1NzI0NDczNTksImV4cCI6MjQzNjM2MDk1OX0" + - ".yGZthRlVezhbKk1gDymW6pZfbCoxxqJda6md9btp00w"; + public static final String ALBERT_TOKEN = "Bearer eyJhbGciOiJIUzUxMiJ9" + + ".eyJzdWIiOiI3ZTY0ODE4ZC02Mjc2LTQ2ZmItOGJiMS03MzJlNmUwOWY3ZTkiLCJpYXQiOjE2MjA4Mzg3NDUsImV4cCI6MjUzMzcwNzY4NDYxfQ" + + ".jLq89vH-YVPzKDSe44dV8CA2jpb8Or_xPf2gboiwaMTZwF_riNaVGJaziw8uYHRAIMb4bFBBd6MHbDiwrLlZZg"; - public static final String NIKOLA_TOKEN = "Bearer eyJhbGciOiJIUzI1NiJ9" + - ".eyJzdWIiOiJiNWI5MmM2OS01ZWQ5LTQwNTQtOTU0ZC0wMTIxYzI5YjY4MDAiLCJpYXQiOjE1NzI5NjU2NTksImV4cCI6MjQzNjg3OTI1OX0" + - ".f-nAX35Ob392xzerVqN9j34kCorZ0Lu6I18OgflHROs"; + public static final String NIKOLA_TOKEN = "Bearer eyJhbGciOiJIUzUxMiJ9" + + ".eyJzdWIiOiJiNWI5MmM2OS01ZWQ5LTQwNTQtOTU0ZC0wMTIxYzI5YjY4MDAiLCJpYXQiOjE2MjA4Mzg3MDgsImV4cCI6MjUzMzcwNzY4NDYxfQ" + + ".U3mPUE0fREeVlresvl6uHR-aTj3ATFYn7CsAJ0cyOhqvaICTvURewF8QPfw2WVZ4GGc8Ej46BqHI9rpwKqRxpQ"; @Autowired protected TestRestTemplate client; @@ -61,9 +59,13 @@ public abstract class WebIntegrationTest { @Autowired protected MigrationRunner migrationRunner; + @Autowired + protected RdfDevelopmentMigrationRunner rdfDevelopmentMigrationRunner; + @BeforeEach public void setup() { migrationRunner.run(); + rdfDevelopmentMigrationRunner.run(); } } \ No newline at end of file diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/ActuatorInfoDTO.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/ActuatorInfoDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..a595bc9f6ffcedba191b344c94c77a579adafedb --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/ActuatorInfoDTO.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.actuator; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@NoArgsConstructor +@AllArgsConstructor +@Getter +@Setter +@JsonIgnoreProperties(ignoreUnknown = true) +public class ActuatorInfoDTO { + @NotNull + @NotBlank + private String name; + + @NotNull + @NotBlank + private String version; + + @NotNull + @NotBlank + private String builtAt; +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/List_Info_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/List_Info_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..2b17817ed42649f6499da54924e4fdab971ee11f --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/actuator/List_Info_GET.java @@ -0,0 +1,82 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.actuator; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +public class List_Info_GET extends WebIntegrationTest { + + @Value("${git.branch}") + private String branch; + + @Value("${git.commit.id.abbrev}") + private String commitShort; + + @Value("${git.tags}") + private String tag; + + @Value("${build.time}") + private String buildTime; + + private URI url() { + return URI.create("/actuator/info"); + } + + @Test + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference<ActuatorInfoDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ActuatorInfoDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(notNullValue())); + if (tag == null || tag.isEmpty()) { + assertThat(result.getBody().getVersion(), is(equalTo((format("%s~%s", branch, commitShort))))); + } else { + assertThat(result.getBody().getVersion(), is(equalTo((format("%s~%s", tag, commitShort))))); + } + assertThat(result.getBody().getBuiltAt(), is(equalTo(buildTime))); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/Detail_DELETE.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/Detail_DELETE.java new file mode 100644 index 0000000000000000000000000000000000000000..a703089c238380739956afb79895690c1b972df2 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/Detail_DELETE.java @@ -0,0 +1,96 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.apikey; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.data.ApiKeyFixtures; +import nl.dtls.fairdatapoint.entity.apikey.ApiKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestDelete; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createUserForbiddenTestDelete; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createAdminNotFoundTestDelete; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("DELETE /api-keys/:apikeyUuid") +public class Detail_DELETE extends WebIntegrationTest { + + private URI url(String uuid) { + return URI.create(format("/api-keys/%s", uuid)); + } + + @Autowired + private ApiKeyFixtures apikeyFixtures; + + @Test + @DisplayName("HTTP 204") + public void res204() { + // GIVEN: + ApiKey apikey = apikeyFixtures.albertApiKey(); + RequestEntity<Void> request = RequestEntity + .delete(url(apikey.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .build(); + ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + ApiKey apikey = apikeyFixtures.albertApiKey(); + createNoUserForbiddenTestDelete(client, url(apikey.getUuid())); + } + + @Test + @DisplayName("HTTP 403: User is not an owner") + public void res403_apikey() { + ApiKey apikey = apikeyFixtures.nikolaApiKey(); + createUserForbiddenTestDelete(client, url(apikey.getUuid())); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createAdminNotFoundTestDelete(client, url("nonExisting")); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Member_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_GET.java old mode 100755 new mode 100644 similarity index 63% rename from src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Member_GET.java rename to src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_GET.java index c3d35fceef3c287e7e48cb773b8461b8ed6d1707..e775328d20807a8f0378882063975d8a60486e30 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Member_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_GET.java @@ -20,12 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package nl.dtls.fairdatapoint.acceptance.metadata.repository; +package nl.dtls.fairdatapoint.acceptance.apikey; import nl.dtls.fairdatapoint.WebIntegrationTest; -import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.apikey.ApiKeyDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.data.ApiKeyFixtures; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -33,19 +35,23 @@ import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import java.net.URI; +import java.util.List; -import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyMember; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestGet; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -@DisplayName("GET /member") -public class Detail_Member_GET extends WebIntegrationTest { +@DisplayName("GET /api-keys") +public class List_GET extends WebIntegrationTest { private URI url() { - return URI.create("/member"); + return URI.create("/api-keys"); } + @Autowired + private ApiKeyFixtures apikeyFixtures; + @Test @DisplayName("HTTP 200") public void res200() { @@ -53,36 +59,24 @@ public class Detail_Member_GET extends WebIntegrationTest { RequestEntity<Void> request = RequestEntity .get(url()) .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) - .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<List<ApiKeyDTO>> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<List<ApiKeyDTO>> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertEmptyMember(result.getBody()); + List<ApiKeyDTO> body = result.getBody(); + assertThat(body.size(), is(equalTo(1))); + body.get(0).equals(apikeyFixtures.albertApiKey()); } @Test - @DisplayName("HTTP 200: No user") - public void res200_no_user() { - // GIVEN: - RequestEntity<Void> request = RequestEntity - .get(url()) - .header(HttpHeaders.ACCEPT, "application/json") - .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { - }; - - // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); - - // THEN: - assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertEmptyMember(result.getBody()); + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestGet(client, url()); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..c313892afeb47ea24fc3aa1becba0c82c74477d8 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/apikey/List_POST.java @@ -0,0 +1,71 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.apikey; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.apikey.ApiKeyDTO; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; + +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPost; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /api-keys") +public class List_POST extends WebIntegrationTest { + + private URI url() { + return URI.create("/api-keys"); + } + + @Test + @DisplayName("HTTP 201") + public void res201() { + // GIVEN: Prepare request + RequestEntity<Void> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(null); + ParameterizedTypeReference<ApiKeyDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ApiKeyDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPost(client, url(), null); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/general/SecurityTest.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/general/SecurityTest.java index 4ec602fe34c5aaecaeaecc69e3dd0d3d70c9d559..52b9566ec505898241142ea0fc8534aaf71a4f50 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/general/SecurityTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/general/SecurityTest.java @@ -23,8 +23,9 @@ package nl.dtls.fairdatapoint.acceptance.general; import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.apikey.data.ApiKeyFixtures; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.rio.RDFFormat; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +37,7 @@ import org.springframework.http.ResponseEntity; import java.net.URI; +import static java.lang.String.format; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; @@ -43,7 +45,10 @@ import static org.hamcrest.core.IsEqual.equalTo; public class SecurityTest extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; + + @Autowired + private ApiKeyFixtures apiKeyFixtures; @Test public void postRequestsAreSecured() { @@ -54,11 +59,11 @@ public class SecurityTest extends WebIntegrationTest { .post(URI.create("/distribution")) .header(HttpHeaders.CONTENT_TYPE, "text/turtle") .body(reqDto); - ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<Void> result = client.exchange(request, responseType); + ResponseEntity<String> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); @@ -83,4 +88,25 @@ public class SecurityTest extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); } + @Test + public void apiKeyIsWorking() { + // GIVEN: Prepare data + String reqDto = RdfIOUtil.write(testMetadataFixtures.c1_d1_distribution1(), RDFFormat.TURTLE); + // AND: Prepare request + RequestEntity<String> request = RequestEntity + .post(URI.create("/distribution")) + .header(HttpHeaders.CONTENT_TYPE, "text/turtle") + .header(HttpHeaders.ACCEPT, "text/turtle") + .header(HttpHeaders.AUTHORIZATION, format("Bearer %s", apiKeyFixtures.ALBERT_API_KEY)) + .body(reqDto); + ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); + } + } \ No newline at end of file diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_TriggerAll_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_TriggerAll_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..307005646eb930788692fa1699b658f1f8c8425b --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_TriggerAll_POST.java @@ -0,0 +1,130 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.admin; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.EventRepository; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.EventType; +import nl.dtls.fairdatapoint.utils.TestIndexEntryFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /index/admin/trigger-all") +public class List_TriggerAll_POST extends WebIntegrationTest { + + @Autowired + private EventRepository eventRepository; + + @Autowired + private IndexEntryRepository indexEntryRepository; + + private final ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/admin/trigger-all"); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN + RequestEntity<Void> request = RequestEntity + .post(url()) + .build(); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: incorrect token") + public void res403_incorrectToken() { + // GIVEN + RequestEntity<Void> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, "mySecretToken") + .build(); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: non-admin token") + public void res403_nonAdminToken() { + // GIVEN + RequestEntity<Void> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .build(); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 204: trigger all") + public void res204_triggerAll() { + // GIVEN: prepare request + RequestEntity<Void> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .build(); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + List<Event> events = eventRepository.getAllByType(EventType.AdminTrigger); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + assertThat("One AdminTrigger event is created", events.size(), is(equalTo(1))); + assertThat("Records correct client URL as null", events.get(0).getAdminTrigger().getClientUrl(), is(equalTo(null))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_Trigger_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_Trigger_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..65103618136adee6f2cff7eab061d392c8fb1249 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/admin/List_Trigger_POST.java @@ -0,0 +1,198 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.admin; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.EventRepository; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.event.Event; +import nl.dtls.fairdatapoint.entity.index.event.EventType; +import nl.dtls.fairdatapoint.utils.TestIndexEntryFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /index/admin/trigger") +public class List_Trigger_POST extends WebIntegrationTest { + + @Autowired + private EventRepository eventRepository; + + @Autowired + private IndexEntryRepository indexEntryRepository; + + private final ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/admin/trigger"); + } + + private PingDTO reqDTO(String clientUrl) { + PingDTO dto = new PingDTO(); + dto.setClientUrl(clientUrl); + return dto; + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN: prepare data + String clientUrl = "http://example.com"; + PingDTO reqDTO = reqDTO(clientUrl); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: incorrect token") + public void res403_incorrectToken() { + // GIVEN: prepare data + String clientUrl = "http://example.com"; + PingDTO reqDTO = reqDTO(clientUrl); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, "mySecretToken") + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: non-admin token") + public void res403_nonAdminToken() { + // GIVEN: prepare data + String clientUrl = "http://example.com"; + PingDTO reqDTO = reqDTO(clientUrl); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 400: malformed URL") + public void res403_malformedUrl() { + // GIVEN: prepare data + String clientUrl = "http://example.com"; + PingDTO reqDTO = reqDTO(clientUrl); + reqDTO.setClientUrl("thisIsNot/Url"); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 204: trigger one") + public void res204_triggerOne() { + // GIVEN: prepare data + IndexEntry entry = TestIndexEntryFixtures.entryExample(); + indexEntryRepository.save(entry); + PingDTO reqDTO = reqDTO(entry.getClientUrl()); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + List<Event> events = eventRepository.getAllByType(EventType.AdminTrigger); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + assertThat("One AdminTrigger event is created", events.size(), is(equalTo(1))); + assertThat("Records correct client URL", events.get(0).getAdminTrigger().getClientUrl(), is(equalTo(entry.getClientUrl()))); + } + + @Test + @DisplayName("HTTP 404: trigger non-existing") + public void res404_triggerOne() { + // GIVEN: prepare data + IndexEntry entry = TestIndexEntryFixtures.entryExample(); + PingDTO reqDTO = reqDTO(entry.getClientUrl()); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTO); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + List<Event> events = eventRepository.getAllByType(EventType.AdminTrigger); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + assertThat("One AdminTrigger event is created", events.size(), is(equalTo(1))); + assertThat("Records correct client URL", events.get(0).getAdminTrigger().getClientUrl(), is(equalTo(entry.getClientUrl()))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_All_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_All_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..06821ff6cbdbdd5d12937a0fe88e29d711565a2a --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_All_GET.java @@ -0,0 +1,137 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.entry; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.utils.TestIndexEntryFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /index/entries/all") +public class List_All_GET extends WebIntegrationTest { + + @Autowired + private IndexEntryRepository indexEntryRepository; + + private final ParameterizedTypeReference<List<IndexEntryDTO>> responseType = new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/entries/all"); + } + + @Test + @DisplayName("HTTP 200: list empty") + public void res200_listEmpty() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN: + ResponseEntity<List<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("There are no entries in the response", result.getBody().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 200: list few") + public void res200_listFew() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + List<IndexEntry> entries = TestIndexEntryFixtures.entriesFew(); + indexEntryRepository.saveAll(entries); + int size = 9; + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<List<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Correct number of entries is in the response", result.getBody().size(), + is(equalTo(entries.size()))); + for (int i = 0; i < entries.size(); i++) { + assertThat("Entry matches: " + entries.get(i).getClientUrl(), result.getBody().get(i).getClientUrl(), + is(equalTo(entries.get(i).getClientUrl()))); + } + } + + @Test + @DisplayName("HTTP 200: list many") + public void res200_listMany() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + List<IndexEntry> entries = TestIndexEntryFixtures.entriesN(300); + indexEntryRepository.saveAll(entries); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<List<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Correct number of entries is in the response", result.getBody().size(), + is(equalTo(entries.size()))); + for (int i = 0; i < entries.size(); i++) { + assertThat("Entry matches: " + entries.get(i).getClientUrl(), result.getBody().get(i).getClientUrl(), + is(equalTo(entries.get(i).getClientUrl()))); + } + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..40e834e7d8147da417973bd3df83f3e39aee7930 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_GET.java @@ -0,0 +1,226 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.entry; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.utils.CustomPageImpl; +import nl.dtls.fairdatapoint.utils.TestIndexEntryFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.web.util.UriComponentsBuilder; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /index/entries") +public class List_GET extends WebIntegrationTest { + + @Autowired + private IndexEntryRepository indexEntryRepository; + + private final ParameterizedTypeReference<CustomPageImpl<IndexEntryDTO>> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/entries"); + } + + private URI urlWithPage(int page) { + return UriComponentsBuilder.fromUri(url()) + .queryParam("page", page) + .build().toUri(); + } + + private URI urlWithPageSize(int page, int size) { + return UriComponentsBuilder.fromUri(url()) + .queryParam("page", page) + .queryParam("size", size) + .build().toUri(); + } + + @Test + @DisplayName("HTTP 200: page empty") + public void res200_pageEmpty() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<CustomPageImpl<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Current page is the first page", result.getBody().isFirst(), is(Boolean.TRUE)); + assertThat("Current page is the last page", result.getBody().isLast(), is(Boolean.TRUE)); + assertThat("Current page is empty", result.getBody().isEmpty(), is(Boolean.TRUE)); + assertThat("Number of pages is 0", result.getBody().getTotalPages(), is(equalTo(0))); + assertThat("Number of elements is 0", result.getBody().getTotalElements(), is(equalTo(0L))); + assertThat("There are no entries in the response", result.getBody().getContent().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 200: out-of-bounds page") + public void res200_outOfBoundsPage() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(urlWithPage(7)) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN: + ResponseEntity<CustomPageImpl<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Current page is not the first page", result.getBody().isFirst(), is(Boolean.FALSE)); + assertThat("Current page is the last page", result.getBody().isLast(), is(Boolean.TRUE)); + assertThat("Current page is empty", result.getBody().isEmpty(), is(Boolean.TRUE)); + assertThat("Number of pages is 0", result.getBody().getTotalPages(), is(equalTo(0))); + assertThat("Number of elements is 0", result.getBody().getTotalElements(), is(equalTo(0L))); + assertThat("There are no entries in the response", result.getBody().getContent().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 200: page few") + public void res200_pageFew() { + // GIVEN: prepare data + indexEntryRepository.deleteAll(); + List<IndexEntry> entries = TestIndexEntryFixtures.entriesFew(); + indexEntryRepository.saveAll(entries); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<CustomPageImpl<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Current page is the first page", result.getBody().isFirst(), is(Boolean.TRUE)); + assertThat("Current page is the last page", result.getBody().isLast(), is(Boolean.TRUE)); + assertThat("Current page is not empty", result.getBody().isEmpty(), is(Boolean.FALSE)); + assertThat("Number of pages is 1", result.getBody().getTotalPages(), is(equalTo(1))); + assertThat("Number of elements is correct", result.getBody().getTotalElements(), + is(equalTo(Integer.toUnsignedLong(entries.size())))); + assertThat("There is correct number of entries in the response", result.getBody().getContent().size(), + is(equalTo(entries.size()))); + for (int i = 0; i < entries.size(); i++) { + assertThat("Entry matches: " + entries.get(i).getClientUrl(), + result.getBody().getContent().get(i).getClientUrl(), is(equalTo(entries.get(i).getClientUrl()))); + } + } + + @Test + @DisplayName("HTTP 200: page many (middle)") + public void res200_pageManyMiddle() { + // GIVEN: prepare data + long items = 300L; + int size = 30; + int page = 3; + indexEntryRepository.deleteAll(); + List<IndexEntry> entries = TestIndexEntryFixtures.entriesN(items); + indexEntryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity<?> request = RequestEntity + .get(urlWithPageSize(page, size)) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<CustomPageImpl<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Current page is the first page", result.getBody().isFirst(), is(Boolean.FALSE)); + assertThat("Current page is the last page", result.getBody().isLast(), is(Boolean.FALSE)); + assertThat("Current page is not empty", result.getBody().isEmpty(), is(Boolean.FALSE)); + assertThat("Number of pages is correct", result.getBody().getTotalPages(), is(equalTo(10))); + assertThat("Number of elements is correct", result.getBody().getTotalElements(), is(equalTo(items))); + assertThat("There is correct number of entries in the response", result.getBody().getContent().size(), + is(equalTo(size))); + } + + @Test + @DisplayName("HTTP 200: page many (last)") + public void res200_pageManyLast() { + // GIVEN (prepare data) + long items = 666; + int size = 300; + int lastSize = 66; + int page = 2; + indexEntryRepository.deleteAll(); + List<IndexEntry> entries = TestIndexEntryFixtures.entriesN(items); + indexEntryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity<?> request = RequestEntity + .get(urlWithPageSize(page, size)) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<CustomPageImpl<IndexEntryDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Current page is the first page", result.getBody().isFirst(), is(Boolean.FALSE)); + assertThat("Current page is the last page", result.getBody().isLast(), is(Boolean.TRUE)); + assertThat("Current page is not empty", result.getBody().isEmpty(), is(Boolean.FALSE)); + assertThat("Number of pages is correct", result.getBody().getTotalPages(), is(equalTo(3))); + assertThat("Number of elements is correct", result.getBody().getTotalElements(), is(equalTo(items))); + assertThat("There is correct number of entries in the response", result.getBody().getContent().size(), + is(equalTo(lastSize))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_Info_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_Info_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..29c2ce0c735bc06af06e72bae342aa307ed24779 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/entry/List_Info_GET.java @@ -0,0 +1,81 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.entry; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryInfoDTO; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.HashMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /index/entries/info") +public class List_Info_GET extends WebIntegrationTest { + + private final ParameterizedTypeReference<IndexEntryInfoDTO> responseType = new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/entries/info"); + } + + @Test + @DisplayName("HTTP 200") + public void res200_listMany() { + // GIVEN: Prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // AND: Prepare expectation + IndexEntryInfoDTO expDto = new IndexEntryInfoDTO(new HashMap<>() {{ + put("ALL", 6L); + put("ACTIVE", 1L); + put("INACTIVE", 2L); + put("UNKNOWN", 1L); + put("INVALID", 1L); + put("UNREACHABLE", 1L); + }}); + + // WHEN: + ResponseEntity<IndexEntryInfoDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Correct number of entries is in the response", result.getBody(), + is(equalTo(expDto))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/ping/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/ping/List_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..c219514424876ce7450424d4531c6574006cf1e8 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/ping/List_POST.java @@ -0,0 +1,173 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.ping; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.ping.PingDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexEntryRepository; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.utils.TestIndexEntryFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.HashMap; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /") +public class List_POST extends WebIntegrationTest { + + @Autowired + private IndexEntryRepository indexEntryRepository; + + private final ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/"); + } + + private PingDTO reqDTO(String clientUrl) { + PingDTO dto = new PingDTO(); + dto.setClientUrl(clientUrl); + return dto; + } + + @Test + @DisplayName("HTTP 204: new entry") + public void res204_newEntry() { + // GIVEN: prepare data + String clientUrl = "http://example.com"; + PingDTO reqDto = reqDTO(clientUrl); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + + // WHEN: + assertThat("Entry does not exist before the ping", + indexEntryRepository.findByClientUrl(clientUrl).isPresent(), is(Boolean.FALSE)); + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + assertThat("Entry exists after the ping", indexEntryRepository.findByClientUrl(clientUrl).isPresent(), + is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 204: existing entry") + public void res204_existingEnty() { + // GIVEN: prepare data + IndexEntry indexEntry = TestIndexEntryFixtures.entryExample(); + String clientUrl = indexEntry.getClientUrl(); + PingDTO reqDto = reqDTO(clientUrl); + + // AND: prepare request + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + + // WHEN: + indexEntryRepository.save(indexEntry); + assertThat("Entry exists before the ping", indexEntryRepository.findByClientUrl(clientUrl).isPresent(), + is(Boolean.TRUE)); + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + assertThat("Entry exists after the ping", indexEntryRepository.findByClientUrl(clientUrl).isPresent(), + is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 400: null client url") + public void res400_nullClientUrl() { + // GIVEN (prepare data) + PingDTO reqDto = reqDTO(null); + + // AND (prepare request) + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 400: non-URL client url") + public void res400_nonUrlClientUrl() { + // GIVEN (prepare data) + PingDTO reqDto = reqDTO("testing"); + + // AND (prepare request) + RequestEntity<PingDTO> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 400: different body") + public void res400_differentBody() { + // GIVEN (prepare data) + HashMap<String, String> dummyData = new HashMap<>(); + dummyData.put("content", "http://test"); + + // AND (prepare request) + RequestEntity<HashMap<String, String>> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(dummyData); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_DELETE.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_DELETE.java new file mode 100644 index 0000000000000000000000000000000000000000..7fd318fa53107897b296134fb179b4ffa4d0892f --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_DELETE.java @@ -0,0 +1,175 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexSettingsRepository; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsPing; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsRetrieval; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.time.Duration; +import java.util.Collections; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("DELETE /index/settings") +public class List_DELETE extends WebIntegrationTest { + + @Autowired + private IndexSettingsRepository indexSettingsRepository; + + private final ParameterizedTypeReference<IndexSettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/settings"); + } + + private IndexSettings customSettings() { + return new IndexSettings() + .toBuilder() + .ping( + new IndexSettingsPing() + .toBuilder() + .denyList(Collections.singletonList("http://localhost.*$")) + .rateLimitDuration(Duration.ofMinutes(17)) + .validDuration(Duration.ofDays(5)) + .rateLimitHits(666) + .build() + ) + .retrieval( + new IndexSettingsRetrieval() + .toBuilder() + .rateLimitWait(Duration.ofHours(16)) + .timeout(Duration.ofSeconds(55)) + .build() + ) + .build(); + } + + @Test + @DisplayName("HTTP 200: default settings") + public void res200_defaultSettings() { + // GIVEN: prepare data + IndexSettings settings = IndexSettings.getDefault(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains default rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains default rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains default deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains default timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains default rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + assertThat("Response indicated default settings", Objects.requireNonNull(result.getBody()).getIsDefault(), is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 200: custom settings") + public void res200_customSettings() { + // GIVEN: prepare data + IndexSettings settings = IndexSettings.getDefault(); + IndexSettings customSettings = customSettings(); + indexSettingsRepository.deleteAll(); + indexSettingsRepository.insert(customSettings); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains default rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains default rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains default deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains default timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains default rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + assertThat("Response indicated default settings", Objects.requireNonNull(result.getBody()).getIsDefault(), is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN + RequestEntity<?> request = RequestEntity + .delete(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..5748308271101daa49f9b92cfa0803fb7d169d88 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_GET.java @@ -0,0 +1,176 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexSettingsRepository; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsPing; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsRetrieval; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.time.Duration; +import java.util.Collections; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /index/settings") +public class List_GET extends WebIntegrationTest { + + @Autowired + private IndexSettingsRepository indexSettingsRepository; + + private final ParameterizedTypeReference<IndexSettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/settings"); + } + + private IndexSettings customSettings() { + return new IndexSettings() + .toBuilder() + .ping( + new IndexSettingsPing() + .toBuilder() + .denyList(Collections.singletonList("http://localhost.*$")) + .rateLimitDuration(Duration.ofMinutes(17)) + .validDuration(Duration.ofDays(5)) + .rateLimitHits(666) + .build() + ) + .retrieval( + new IndexSettingsRetrieval() + .toBuilder() + .rateLimitWait(Duration.ofHours(16)) + .timeout(Duration.ofSeconds(55)) + .build() + ) + .build(); + } + + @Test + @DisplayName("HTTP 200: default settings") + public void res200_defaultSettings() { + // GIVEN: prepare data + IndexSettings settings = IndexSettings.getDefault(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(0))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains default rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains default rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains default deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains default timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains default rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + assertThat("Response indicated default settings", Objects.requireNonNull(result.getBody()).getIsDefault(), is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 200: custom settings") + public void res200_customSettings() { + // GIVEN: prepare data + IndexSettings settings = customSettings(); + indexSettingsRepository.deleteAll(); + indexSettingsRepository.insert(settings); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains custom valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains custom rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains custom rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains custom deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains custom timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains custom rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + assertThat("Response indicated non-default settings", Objects.requireNonNull(result.getBody()).getIsDefault(), is(Boolean.FALSE)); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..b00ce22559d01f7ee20586c62245d304bb384a89 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/index/settings/List_PUT.java @@ -0,0 +1,273 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.index.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsPingDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsRetrievalDTO; +import nl.dtls.fairdatapoint.api.dto.index.settings.IndexSettingsUpdateDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.IndexSettingsRepository; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettings; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsPing; +import nl.dtls.fairdatapoint.entity.index.settings.IndexSettingsRetrieval; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.time.Duration; +import java.util.Collections; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("PUT /index/settings") +public class List_PUT extends WebIntegrationTest { + + @Autowired + private IndexSettingsRepository indexSettingsRepository; + + private final ParameterizedTypeReference<IndexSettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/index/settings"); + } + + private IndexSettings customSettings1() { + return new IndexSettings() + .toBuilder() + .ping( + new IndexSettingsPing() + .toBuilder() + .denyList(Collections.singletonList("http://localhost.*$")) + .rateLimitDuration(Duration.ofMinutes(17)) + .validDuration(Duration.ofDays(5)) + .rateLimitHits(666) + .build() + ) + .retrieval( + new IndexSettingsRetrieval() + .toBuilder() + .rateLimitWait(Duration.ofHours(16)) + .timeout(Duration.ofSeconds(55)) + .build() + ) + .build(); + } + + private IndexSettings customSettings2() { + IndexSettings settings = customSettings1(); + settings.getPing().setValidDuration(Duration.ofDays(14)); + settings.getRetrieval().setTimeout(Duration.ofMinutes(2)); + return settings; + } + + private IndexSettingsUpdateDTO customSettingsUpdateDTO() { + IndexSettings customSettings = customSettings1(); + IndexSettingsUpdateDTO dto = new IndexSettingsUpdateDTO(); + IndexSettingsPingDTO pingDTO = new IndexSettingsPingDTO(); + pingDTO.setDenyList(customSettings.getPing().getDenyList()); + pingDTO.setRateLimitDuration(customSettings.getPing().getRateLimitDuration().toString()); + pingDTO.setValidDuration(customSettings.getPing().getValidDuration().toString()); + pingDTO.setRateLimitHits(customSettings.getPing().getRateLimitHits()); + dto.setPing(pingDTO); + IndexSettingsRetrievalDTO retrievalDTO = new IndexSettingsRetrievalDTO(); + retrievalDTO.setRateLimitWait(customSettings.getRetrieval().getRateLimitWait().toString()); + retrievalDTO.setTimeout(customSettings.getRetrieval().getTimeout().toString()); + dto.setRetrieval(retrievalDTO); + return dto; + } + + private IndexSettingsUpdateDTO invalidUpdateDTO1() { + IndexSettingsUpdateDTO dto = customSettingsUpdateDTO(); + dto.getPing().setValidDuration("666"); + return dto; + } + + private IndexSettingsUpdateDTO invalidUpdateDTO2() { + IndexSettingsUpdateDTO dto = customSettingsUpdateDTO(); + dto.getPing().setDenyList(null); + return dto; + } + + @Test + @DisplayName("HTTP 200: update settings from defaults") + public void res200_updateSettingsFromDefaults() { + // GIVEN: prepare data + IndexSettings settings = customSettings1(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(customSettingsUpdateDTO()); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("Settings are created", indexSettingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains default rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains default rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains default deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains default timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains default rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + } + + @Test + @DisplayName("HTTP 200: update settings from custom") + public void res200_updateSettingsFromCustom() { + // GIVEN: prepare data + IndexSettingsUpdateDTO reqDTO = customSettingsUpdateDTO(); + IndexSettings settings = customSettings1(); + indexSettingsRepository.deleteAll(); + indexSettingsRepository.insert(customSettings2()); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("Settings are created", indexSettingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default valid duration", Objects.requireNonNull(result.getBody()).getPing().getValidDuration(), is(equalTo(settings.getPing().getValidDuration().toString()))); + assertThat("Response contains default rate limit duration", Objects.requireNonNull(result.getBody()).getPing().getRateLimitDuration(), is(equalTo(settings.getPing().getRateLimitDuration().toString()))); + assertThat("Response contains default rate limit hits", Objects.requireNonNull(result.getBody()).getPing().getRateLimitHits(), is(equalTo(settings.getPing().getRateLimitHits()))); + assertThat("Response contains default deny list", Objects.requireNonNull(result.getBody()).getPing().getDenyList(), is(equalTo(settings.getPing().getDenyList()))); + assertThat("Response contains default timeout", Objects.requireNonNull(result.getBody()).getRetrieval().getTimeout(), is(equalTo(settings.getRetrieval().getTimeout().toString()))); + assertThat("Response contains default rate limit wait", Objects.requireNonNull(result.getBody()).getRetrieval().getRateLimitWait(), is(equalTo(settings.getRetrieval().getRateLimitWait().toString()))); + } + + @Test + @DisplayName("HTTP 400: invalid duration format") + public void res400_invalidDurationFormat() { + // GIVEN: prepare data + IndexSettingsUpdateDTO reqDTO = invalidUpdateDTO1(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It indicates bad request", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 400: invalid list") + public void res400_invalidList() { + // GIVEN: prepare data + IndexSettingsUpdateDTO reqDTO = invalidUpdateDTO2(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It indicates bad request", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN: prepare data + IndexSettingsUpdateDTO reqDTO = customSettingsUpdateDTO(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN: prepare data + IndexSettingsUpdateDTO reqDTO = customSettingsUpdateDTO(); + indexSettingsRepository.deleteAll(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<IndexSettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("No settings are created", indexSettingsRepository.findAll().size(), is(equalTo(0))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/Common.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/Common.java index b9a835a1288f907dc4c9c9fc193c2f36c8883212..a9f0deea5ec053cf727494c60a482342dfd529e5 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/Common.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/Common.java @@ -22,9 +22,23 @@ */ package nl.dtls.fairdatapoint.acceptance.metadata; +import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import java.net.URI; + +import static nl.dtls.fairdatapoint.WebIntegrationTest.ALBERT_TOKEN; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; @@ -37,4 +51,45 @@ public class Common { // Assert assertThat(dto, is(equalTo(expDto))); } + + public static void assertEmptyState(MetaStateDTO dto) { + assertThat(dto, is(nullValue())); + } + + public static void createMetadataStateAlreadyPublished(TestRestTemplate client, URI url) { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(new MetaStateChangeDTO(MetadataState.PUBLISHED)); + ParameterizedTypeReference<ErrorDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ErrorDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat(result.getBody().getMessage(), is(equalTo("Metadata is already published"))); + } + + public static void createMetadataStateChangeToDraft(TestRestTemplate client, URI url) { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(new MetaStateChangeDTO(MetadataState.DRAFT)); + ParameterizedTypeReference<ErrorDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ErrorDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat(result.getBody().getMessage(), is(equalTo("You can not change state to DRAFT"))); + } + } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Expanded_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Expanded_GET.java index fa2d463e173e1738dc10df6a00d661c21c0546be..6d06dcd5c2d14c4c86ee74418bd116468050b25b 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Expanded_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Expanded_GET.java @@ -47,7 +47,7 @@ public class Detail_Expanded_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_Expanded_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_GET.java index 08cd61544a21d242285afc083506ab88e222095d..1a402a30d9140b670558aa17b1f57ab6b13157b2 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_GET.java @@ -47,7 +47,7 @@ public class Detail_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_PUT.java index 6f4eac932e91b1613b1b55319d3aa8c5835aca3d..0d7c8c749b0948003d5bfae2f8255260069bf4fb 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_PUT.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_PUT.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.catalog; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; @@ -55,7 +55,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class Detail_PUT extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url(String id) { return URI.create(format("/catalog/%s", id)); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Page_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Page_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..be6da9dd2e3f6320b71cd490fa7848ebbee5b50a --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Page_GET.java @@ -0,0 +1,111 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.catalog; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGetRDF; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /catalog/:catalogId/page/dataset") +public class Detail_Page_GET extends WebIntegrationTest { + + private URI url(String id) { + return URI.create(format("/catalog/%s/page/dataset", id)); + } + + @Test + @DisplayName("HTTP 200: Published") + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-1")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("catalog-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGetRDF(client, url("nonExisting")); + } +} + diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/List_POST.java index c58bff1cc6bfb4db75df2b62c41b8077d6fd4528..73ae3f2b77b0f40d44a51e3e08fca6775440764d 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/List_POST.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/List_POST.java @@ -23,9 +23,9 @@ package nl.dtls.fairdatapoint.acceptance.metadata.catalog; import nl.dtls.fairdatapoint.WebIntegrationTest; -import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.MetadataMigration; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.RdfMetadataMigration; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; import org.junit.jupiter.api.DisplayName; @@ -50,7 +50,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class List_POST extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; @Autowired private AclRepository aclRepository; @@ -59,7 +59,7 @@ public class List_POST extends WebIntegrationTest { private AclCache aclCache; @Autowired - private MetadataMigration metadataMigration; + private RdfMetadataMigration rdfMetadataMigration; private URI url() { return URI.create("/catalog"); @@ -89,36 +89,6 @@ public class List_POST extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); } - @Test - @DisplayName("HTTP 201 (with rerouting)") - public void res201_withRerouting() throws Exception { - // GIVEN: We need to clear all permissions from default FDP fixtures - aclRepository.deleteAll(); - aclCache.clearCache(); - // AND: Prepare fixtures - metadataMigration.importDefaultFixtures(testMetadataFixtures.alternativePersistentUrl); - Model catalog3 = testMetadataFixtures.alternative_catalog3(); - String reqDto = RdfIOUtil.write(catalog3, RDFFormat.TURTLE); - // AND: Prepare request - RequestEntity<String> request = RequestEntity - .post(url()) - .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) - .header(HttpHeaders.CONTENT_TYPE, "text/turtle") - .header(HttpHeaders.ACCEPT, "text/turtle") - .header("x-forwarded-host", "lorentz.fair-dtls.surf-hosted.nl") - .header("x-forwarded-proto", "https") - .header("x-forwarded-port", "443") - .body(reqDto); - ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { - }; - - // WHEN: - ResponseEntity<String> result = client.exchange(request, responseType); - - // THEN: - assertThat(result.getStatusCode(), is(equalTo(HttpStatus.CREATED))); - } - @Test @DisplayName("HTTP 403: Anonymous access") public void res403_anonymous() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Member_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_GET.java old mode 100755 new mode 100644 similarity index 63% rename from src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Member_GET.java rename to src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_GET.java index 934edacbb01cbfedd5890fc973ecd1e720d40978..7e6bf8f4c859fd7962849f8d3846919de02ab118 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/Detail_Member_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_GET.java @@ -20,11 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package nl.dtls.fairdatapoint.acceptance.metadata.catalog; +package nl.dtls.fairdatapoint.acceptance.metadata.catalog.meta; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; import nl.dtls.fairdatapoint.database.mongo.migration.development.membership.data.MembershipFixtures; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; import nl.dtls.fairdatapoint.service.member.MemberMapper; import org.junit.jupiter.api.DisplayName; @@ -37,15 +40,18 @@ import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import java.net.URI; +import java.util.Map; import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGetRDF; import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyMember; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyState; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -@DisplayName("GET /catalog/:catalogId/member") -public class Detail_Member_GET extends WebIntegrationTest { +@DisplayName("GET /catalog/:catalogId/meta") +public class List_GET extends WebIntegrationTest { @Autowired private UserFixtures userFixtures; @@ -56,8 +62,11 @@ public class Detail_Member_GET extends WebIntegrationTest { @Autowired private MemberMapper memberMapper; + @Autowired + private MetadataFixtures metadataFixtures; + private URI url(String id) { - return URI.create(format("/catalog/%s/member", id)); + return URI.create(format("/catalog/%s/meta", id)); } @Test @@ -69,18 +78,25 @@ public class Detail_Member_GET extends WebIntegrationTest { .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; // AND: prepare expectation - MemberDTO expDto = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); + MemberDTO expMember = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertThat(result.getBody(), is(equalTo(expDto))); + assertThat(result.getBody().getMember(), is(equalTo(expMember))); + assertThat(result.getBody().getState(), is(equalTo(new MetaStateDTO( + metadataFixtures.catalog1().getState(), + Map.of( + metadataFixtures.dataset1().getUri(), metadataFixtures.dataset1().getState(), + metadataFixtures.dataset2().getUri(), metadataFixtures.dataset2().getState() + ) + )))); } @Test @@ -91,15 +107,22 @@ public class Detail_Member_GET extends WebIntegrationTest { .get(url("catalog-1")) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertEmptyMember(result.getBody()); + assertEmptyMember(result.getBody().getMember()); + assertEmptyState(result.getBody().getState()); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGetRDF(client, url("nonExisting")); } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_State_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_State_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..7d58754b06f5fec0fbe5bc277fa449462a8291ce --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/catalog/meta/List_State_PUT.java @@ -0,0 +1,110 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.catalog.meta; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateAlreadyPublished; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateChangeToDraft; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /catalog/:catalogId/meta/state") +public class List_State_PUT extends WebIntegrationTest { + + @Autowired + private MetadataFixtures metadataFixtures; + + @Autowired + private MetadataRepository metadataRepository; + + private URI url(String id) { + return URI.create(format("/catalog/%s/meta/state", id)); + } + + private MetaStateChangeDTO reqDto() { + return new MetaStateChangeDTO(MetadataState.PUBLISHED); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url("catalog-1")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(reqDto()); + ParameterizedTypeReference<MetaStateChangeDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: Prepare database + Metadata metadata = metadataRepository.findByUri(metadataFixtures.catalog1().getUri()).get(); + metadata.setState(MetadataState.DRAFT); + metadataRepository.save(metadata); + + // WHEN: + ResponseEntity<MetaStateChangeDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(equalTo(reqDto()))); + } + + @Test + @DisplayName("HTTP 400: Metadata is already published") + public void res400_already_published() { + createMetadataStateAlreadyPublished(client, url("catalog-1")); + } + + @Test + @DisplayName("HTTP 400: You can not change state to DRAFT") + public void res400_change_to_draft() { + createMetadataStateChangeToDraft(client, url("catalog-1")); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url("catalog-1"), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Expanded_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Expanded_GET.java index dcbe52b2afb82e8b4f5522f2b2d8e530d270a465..03c2ec0f84ac005d607e7ca135ec5230d94edd26 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Expanded_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Expanded_GET.java @@ -47,7 +47,7 @@ public class Detail_Expanded_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_Expanded_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_GET.java index 48a815a6d4383184ab11c383a2621c63d2355a1d..97129b1b53668dea07ee1771c5af2c4f82e522b6 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_GET.java @@ -47,7 +47,7 @@ public class Detail_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_PUT.java index 53f58040705b25d4964458cc3e8e3afe12ebc4f0..da9c08ef4a17bac12d233a6e8c4272d28964d42d 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_PUT.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_PUT.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.dataset; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; @@ -55,7 +55,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class Detail_PUT extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url(String id) { return URI.create(format("/dataset/%s", id)); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Page_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Page_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..e61e0ce393a488918c21e6197e610e3914b6943e --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Page_GET.java @@ -0,0 +1,110 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.dataset; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGetRDF; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /dataset/:datasetId/page/distribution") +public class Detail_Page_GET extends WebIntegrationTest { + + private URI url(String id) { + return URI.create(format("/dataset/%s/page/distribution", id)); + } + + @Test + @DisplayName("HTTP 200: Published") + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-1")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGetRDF(client, url("nonExisting")); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/List_POST.java index f9fc3434b58cbcc94395c658383b2073a47f88d1..9d0ce47f6ff3ccd550c1b0199ba3fdb1549e9aaf 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/List_POST.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/List_POST.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.dataset; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.rio.RDFFormat; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -46,7 +46,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class List_POST extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url() { return URI.create("/dataset"); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..e79d05da0787a36e7807f88cd282bd6444f351c8 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_GET.java @@ -0,0 +1,128 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.dataset.meta; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.membership.data.MembershipFixtures; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; +import nl.dtls.fairdatapoint.service.member.MemberMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Map; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGetRDF; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyMember; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyState; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /dataset/:datasetId/meta") +public class List_GET extends WebIntegrationTest { + + @Autowired + private UserFixtures userFixtures; + + @Autowired + private MembershipFixtures membershipFixtures; + + @Autowired + private MemberMapper memberMapper; + + @Autowired + private MetadataFixtures metadataFixtures; + + private URI url(String id) { + return URI.create(format("/dataset/%s/meta", id)); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-1")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .build(); + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: prepare expectation + MemberDTO expMember = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); + + // WHEN: + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody().getMember(), is(equalTo(expMember))); + assertThat(result.getBody().getState(), is(equalTo(new MetaStateDTO( + metadataFixtures.dataset1().getState(), + Map.of( + metadataFixtures.distribution1().getUri(), metadataFixtures.distribution1().getState(), + metadataFixtures.distribution2().getUri(), metadataFixtures.distribution2().getState() + ) + )))); + } + + @Test + @DisplayName("HTTP 200: No user") + public void res200_no_user() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("dataset-1")) + .header(HttpHeaders.ACCEPT, "application/json") + .build(); + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertEmptyMember(result.getBody().getMember()); + assertEmptyState(result.getBody().getState()); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGetRDF(client, url("nonExisting")); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_State_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_State_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..9a958a4bb805c8623320e9268944747dc7690f63 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/meta/List_State_PUT.java @@ -0,0 +1,110 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.dataset.meta; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateAlreadyPublished; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateChangeToDraft; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /dataset/:datasetId/meta/state") +public class List_State_PUT extends WebIntegrationTest { + + @Autowired + private MetadataFixtures metadataFixtures; + + @Autowired + private MetadataRepository metadataRepository; + + private URI url(String id) { + return URI.create(format("/dataset/%s/meta/state", id)); + } + + private MetaStateChangeDTO reqDto() { + return new MetaStateChangeDTO(MetadataState.PUBLISHED); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url("dataset-1")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(reqDto()); + ParameterizedTypeReference<MetaStateChangeDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: Prepare database + Metadata metadata = metadataRepository.findByUri(metadataFixtures.dataset1().getUri()).get(); + metadata.setState(MetadataState.DRAFT); + metadataRepository.save(metadata); + + // WHEN: + ResponseEntity<MetaStateChangeDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(equalTo(reqDto()))); + } + + @Test + @DisplayName("HTTP 400: Metadata is already published") + public void res400_already_published() { + createMetadataStateAlreadyPublished(client, url("dataset-1")); + } + + @Test + @DisplayName("HTTP 400: You can not change state to DRAFT") + public void res400_change_to_draft() { + createMetadataStateChangeToDraft(client, url("dataset-1")); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url("dataset-1"), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Expanded_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Expanded_GET.java index afa45b43f7585f5e124ab9919f8094a5595f6d42..6c9471bdeebc403c66e185b3181cf2e1bef5d787 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Expanded_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Expanded_GET.java @@ -47,7 +47,7 @@ public class Detail_Expanded_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_Expanded_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("distribution-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("distribution-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_GET.java index 8f2129af0fe80c8ef1e7e4eb098cd9f15ba1434c..3057134f51b8c53e3d0bc1bf5b859f278215c215 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_GET.java @@ -47,7 +47,7 @@ public class Detail_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity @@ -64,6 +64,44 @@ public class Detail_GET extends WebIntegrationTest { assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); } + @Test + @DisplayName("HTTP 200: Draft (User is logged in)") + public void res200_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("distribution-2")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } + + @Test + @DisplayName("HTTP 403: Draft (User is not logged in)") + public void res403_draft() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url("distribution-2")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat(result.getBody(), is(equalTo("You are not allow to view this record in state DRAFT"))); + } + @Test @DisplayName("HTTP 404") public void res404() { diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_PUT.java index 87367d73708ae748dfe05f11fbd898044c7da995..138c1ab050df9b3d5fbe39471d03c4274297b227 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_PUT.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_PUT.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.distribution; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; @@ -54,7 +54,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class Detail_PUT extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url(String id) { return URI.create(format("/distribution/%s", id)); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/List_POST.java index a4497e26d46222bfe12ff3e4af6cb25f5d35393a..52f9b8c1b054312b5afe539116ca6d539b276b5f 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/List_POST.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/List_POST.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.distribution; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.rio.RDFFormat; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -46,7 +46,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class List_POST extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url() { return URI.create("/distribution"); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Member_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_GET.java old mode 100755 new mode 100644 similarity index 66% rename from src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Member_GET.java rename to src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_GET.java index 7ae8cceb7793f82ce529a7ab6e53c25cdafcfa64..1186c91acb32d3dc9f8ceab7975c2d5919faafff --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/Detail_Member_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_GET.java @@ -20,11 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package nl.dtls.fairdatapoint.acceptance.metadata.distribution; +package nl.dtls.fairdatapoint.acceptance.metadata.distribution.meta; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; import nl.dtls.fairdatapoint.database.mongo.migration.development.membership.data.MembershipFixtures; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; import nl.dtls.fairdatapoint.service.member.MemberMapper; import org.junit.jupiter.api.DisplayName; @@ -37,15 +40,18 @@ import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import java.net.URI; +import java.util.Map; import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGetRDF; import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyMember; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyState; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -@DisplayName("GET /distribution/:distributionId/member") -public class Detail_Member_GET extends WebIntegrationTest { +@DisplayName("GET /distribution/:distributionId/meta") +public class List_GET extends WebIntegrationTest { @Autowired private UserFixtures userFixtures; @@ -56,8 +62,11 @@ public class Detail_Member_GET extends WebIntegrationTest { @Autowired private MemberMapper memberMapper; + @Autowired + private MetadataFixtures metadataFixtures; + private URI url(String id) { - return URI.create(format("/distribution/%s/member", id)); + return URI.create(format("/distribution/%s/meta", id)); } @Test @@ -69,18 +78,22 @@ public class Detail_Member_GET extends WebIntegrationTest { .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; // AND: prepare expectation - MemberDTO expDto = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); + MemberDTO expMember = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertThat(result.getBody(), is(equalTo(expDto))); + assertThat(result.getBody().getMember(), is(equalTo(expMember))); + assertThat(result.getBody().getState(), is(equalTo(new MetaStateDTO( + metadataFixtures.distribution1().getState(), + Map.of() + )))); } @Test @@ -91,15 +104,22 @@ public class Detail_Member_GET extends WebIntegrationTest { .get(url("distribution-1")) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertEmptyMember(result.getBody()); + assertEmptyMember(result.getBody().getMember()); + assertEmptyState(result.getBody().getState()); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGetRDF(client, url("nonExisting")); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_State_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_State_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..6bd2748a2e702f1290d637e7bc809a16d288c357 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/distribution/meta/List_State_PUT.java @@ -0,0 +1,110 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.distribution.meta; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateAlreadyPublished; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateChangeToDraft; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /distribution/:distributionId/meta/state") +public class List_State_PUT extends WebIntegrationTest { + + @Autowired + private MetadataFixtures metadataFixtures; + + @Autowired + private MetadataRepository metadataRepository; + + private URI url(String id) { + return URI.create(format("/distribution/%s/meta/state", id)); + } + + private MetaStateChangeDTO reqDto() { + return new MetaStateChangeDTO(MetadataState.PUBLISHED); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url("distribution-1")) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(reqDto()); + ParameterizedTypeReference<MetaStateChangeDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: Prepare database + Metadata metadata = metadataRepository.findByUri(metadataFixtures.distribution1().getUri()).get(); + metadata.setState(MetadataState.DRAFT); + metadataRepository.save(metadata); + + // WHEN: + ResponseEntity<MetaStateChangeDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(equalTo(reqDto()))); + } + + @Test + @DisplayName("HTTP 400: Metadata is already published") + public void res400_already_published() { + createMetadataStateAlreadyPublished(client, url("distribution-1")); + } + + @Test + @DisplayName("HTTP 400: You can not change state to DRAFT") + public void res400_change_to_draft() { + createMetadataStateChangeToDraft(client, url("distribution-1")); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url("distribution-1"), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Expanded_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Expanded_GET.java index a9e39b0af93738c0f541e59cecc0b7ba327d96b0..57a7fbe0adc95df1e4d6d207ab3eb8887db9daa3 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Expanded_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Expanded_GET.java @@ -45,7 +45,7 @@ public class Detail_Expanded_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_GET.java index 5e5f91a5717287409e934a26f9aed06e6ed34df9..b9a4a3b22627d1f69b54a81aecc6d8854c054ceb 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_GET.java @@ -45,7 +45,7 @@ public class Detail_GET extends WebIntegrationTest { } @Test - @DisplayName("HTTP 200") + @DisplayName("HTTP 200: Published") public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_PUT.java index 06ae21b1c75143f0703020b0971dd728eabb4261..beeb8586378bbaaa40b5c71f1518bf894ac5799f 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_PUT.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_PUT.java @@ -24,7 +24,7 @@ package nl.dtls.fairdatapoint.acceptance.metadata.repository; import nl.dtls.fairdatapoint.WebIntegrationTest; import nl.dtls.fairdatapoint.util.RdfIOUtil; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.rio.RDFFormat; @@ -52,7 +52,7 @@ import static org.hamcrest.core.IsEqual.equalTo; public class Detail_PUT extends WebIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; private URI url() { return URI.create("/"); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Page_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Page_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..c2bf9e90be93cdd141659e34705cbb08b471ebab --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/Detail_Page_GET.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.repository; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +public class Detail_Page_GET extends WebIntegrationTest { + private URI url() { + return URI.create("/page/catalog"); + } + + @Test + @DisplayName("HTTP 200: Published") + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url()) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<String> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Member_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_GET.java old mode 100755 new mode 100644 similarity index 64% rename from src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Member_GET.java rename to src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_GET.java index c9c3bbb70917243696f5be5332074c6a69c61757..ece3a1695b49352a13d2c9628a16cf410f378201 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/dataset/Detail_Member_GET.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_GET.java @@ -20,13 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package nl.dtls.fairdatapoint.acceptance.metadata.dataset; +package nl.dtls.fairdatapoint.acceptance.metadata.repository.meta; import nl.dtls.fairdatapoint.WebIntegrationTest; -import nl.dtls.fairdatapoint.api.dto.member.MemberDTO; -import nl.dtls.fairdatapoint.database.mongo.migration.development.membership.data.MembershipFixtures; -import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; -import nl.dtls.fairdatapoint.service.member.MemberMapper; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaDTO; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -37,27 +36,22 @@ import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import java.net.URI; +import java.util.Map; -import static java.lang.String.format; import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyMember; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.assertEmptyState; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -@DisplayName("GET /dataset/:datasetId/member") -public class Detail_Member_GET extends WebIntegrationTest { +@DisplayName("GET /meta") +public class List_GET extends WebIntegrationTest { @Autowired - private UserFixtures userFixtures; + private MetadataFixtures metadataFixtures; - @Autowired - private MembershipFixtures membershipFixtures; - - @Autowired - private MemberMapper memberMapper; - - private URI url(String id) { - return URI.create(format("/dataset/%s/member", id)); + private URI url() { + return URI.create("/meta"); } @Test @@ -65,22 +59,26 @@ public class Detail_Member_GET extends WebIntegrationTest { public void res200() { // GIVEN: RequestEntity<Void> request = RequestEntity - .get(url("dataset-1")) + .get(url()) .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; - // AND: prepare expectation - MemberDTO expDto = memberMapper.toDTO(userFixtures.albert(), membershipFixtures.owner()); - // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertThat(result.getBody(), is(equalTo(expDto))); + assertEmptyMember(result.getBody().getMember()); + assertThat(result.getBody().getState(), is(equalTo(new MetaStateDTO( + metadataFixtures.repositoryMetadata().getState(), + Map.of( + metadataFixtures.catalog1().getUri(), metadataFixtures.catalog1().getState(), + metadataFixtures.catalog2().getUri(), metadataFixtures.catalog2().getState() + ) + )))); } @Test @@ -88,18 +86,19 @@ public class Detail_Member_GET extends WebIntegrationTest { public void res200_no_user() { // GIVEN: RequestEntity<Void> request = RequestEntity - .get(url("dataset-1")) + .get(url()) .header(HttpHeaders.ACCEPT, "application/json") .build(); - ParameterizedTypeReference<MemberDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<MetaDTO> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<MemberDTO> result = client.exchange(request, responseType); + ResponseEntity<MetaDTO> result = client.exchange(request, responseType); // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); - assertEmptyMember(result.getBody()); + assertEmptyMember(result.getBody().getMember()); + assertEmptyState(result.getBody().getState()); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_State_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_State_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..a35767a03e6a38d2c55490d874550401f4f639e9 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/repository/meta/List_State_PUT.java @@ -0,0 +1,109 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata.repository.meta; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.metadata.MetaStateChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.MetadataRepository; +import nl.dtls.fairdatapoint.entity.metadata.Metadata; +import nl.dtls.fairdatapoint.entity.metadata.MetadataState; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateAlreadyPublished; +import static nl.dtls.fairdatapoint.acceptance.metadata.Common.createMetadataStateChangeToDraft; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /meta/state") +public class List_State_PUT extends WebIntegrationTest { + + @Autowired + private MetadataFixtures metadataFixtures; + + @Autowired + private MetadataRepository metadataRepository; + + private URI url() { + return URI.create("/meta/state"); + } + + private MetaStateChangeDTO reqDto() { + return new MetaStateChangeDTO(MetadataState.PUBLISHED); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<MetaStateChangeDTO> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .header(HttpHeaders.ACCEPT, "application/json") + .body(reqDto()); + ParameterizedTypeReference<MetaStateChangeDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: Prepare database + Metadata metadata = metadataRepository.findByUri(metadataFixtures.repositoryMetadata().getUri()).get(); + metadata.setState(MetadataState.DRAFT); + metadataRepository.save(metadata); + + // WHEN: + ResponseEntity<MetaStateChangeDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(equalTo(reqDto()))); + } + + @Test + @DisplayName("HTTP 400: Metadata is already published") + public void res400_already_published() { + createMetadataStateAlreadyPublished(client, url()); + } + + @Test + @DisplayName("HTTP 400: You can not change state to DRAFT") + public void res400_change_to_draft() { + createMetadataStateChangeToDraft(client, url()); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url(), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/OpenApiDocs_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/OpenApiDocs_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..220f80049877c1f28b57e3947f6de4e30b01614d --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/OpenApiDocs_GET.java @@ -0,0 +1,63 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.openapi; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /v3/api-docs") +public class OpenApiDocs_GET extends WebIntegrationTest { + + private URI url() { + return URI.create("/v3/api-docs"); + } + + @Test + @DisplayName("HTTP 200: API Docs") + public void res200_apiDocs() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<String> result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is OK", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response is JSON", result.getHeaders().getContentType(), is(equalTo(MediaType.APPLICATION_JSON))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/SwaggerUI_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/SwaggerUI_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..7a3791ce4fc9d4b4ba86b78e195a908e7de7778a --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/openapi/SwaggerUI_GET.java @@ -0,0 +1,88 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.openapi; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.index.entry.IndexEntryDTO; +import nl.dtls.fairdatapoint.utils.CustomPageImpl; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /swagger-ui.html") +public class SwaggerUI_GET extends WebIntegrationTest { + + private URI baseUrl() { + return URI.create("/swagger-ui.html"); + } + + private URI redirectedUrl() { + return URI.create("/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config"); + } + + @Test + @DisplayName("HTTP 302: Redirects to Swagger UI") + public void res302_redirectsToSwaggerUI() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(baseUrl()) + .accept(MediaType.TEXT_HTML) + .build(); + + // WHEN + ResponseEntity<String> result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is FOUND", result.getStatusCode(), is(equalTo(HttpStatus.FOUND))); + assertThat("Contains Location header", result.getHeaders().getLocation(), is(notNullValue())); + assertThat("Contains correct Location header", result.getHeaders().getLocation().toString().endsWith(redirectedUrl().toString()), is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 200: Swagger UI") + public void res200_swaggerUI() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(redirectedUrl()) + .accept(MediaType.TEXT_HTML) + .build(); + + // WHEN + ResponseEntity<String> result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN + assertThat("Response code is OK", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response is Swagger UI in HTML", result.getHeaders().getContentType(), is(equalTo(MediaType.TEXT_HTML))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_DELETE.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_DELETE.java new file mode 100644 index 0000000000000000000000000000000000000000..e97158b2c241197e2a4d233755b2831bb6384a30 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_DELETE.java @@ -0,0 +1,95 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.resource; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createUserForbiddenTestDelete; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createAdminNotFoundTestDelete; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("DELETE /resource-definitions/:resourceDefinitionUuid") +public class Detail_DELETE extends WebIntegrationTest { + + private URI url(String uuid) { + return URI.create(format("/resource-definitions/%s", uuid)); + } + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Test + @DisplayName("HTTP 204") + public void res204() { + // GIVEN: + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.repositoryDefinition(); + RequestEntity<Void> request = RequestEntity + .delete(url(resourceDefinition.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .build(); + ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.NO_CONTENT))); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.repositoryDefinition(); + createUserForbiddenTestDelete(client, url(resourceDefinition.getUuid())); + } + + @Test + @DisplayName("HTTP 403: User is not an admin") + public void res403_resourceDefinition() { + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.repositoryDefinition(); + createUserForbiddenTestDelete(client, url(resourceDefinition.getUuid())); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createAdminNotFoundTestDelete(client, url("nonExisting")); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..7e4686e1966435b5c09af68734870a004fc42181 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_GET.java @@ -0,0 +1,79 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.resource; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createUserNotFoundTestGet; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /resource-definitions/:resourceDefinitionUuid") +public class Detail_GET extends WebIntegrationTest { + + private URI url(String uuid) { + return URI.create(format("/resource-definitions/%s", uuid)); + } + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.repositoryDefinition(); + RequestEntity<Void> request = RequestEntity + .get(url(resourceDefinition.getUuid())) + .build(); + ParameterizedTypeReference<ResourceDefinition> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ResourceDefinition> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(equalTo(resourceDefinition))); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createUserNotFoundTestGet(client, url("nonExisting")); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..576db354ffdb37fa1341aee4542ae518b482956c --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/Detail_PUT.java @@ -0,0 +1,115 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.resource; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createUserForbiddenTestPut; +import static nl.dtls.fairdatapoint.acceptance.common.NotFoundTest.createAdminNotFoundTestPut; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /resource-definitions/:resourceDefinitionUuid") +public class Detail_PUT extends WebIntegrationTest { + + @Autowired + private ResourceDefinitionMapper resourceDefinitionMapper; + + private URI url(String uuid) { + return URI.create(format("/resource-definitions/%s", uuid)); + } + + private ResourceDefinitionChangeDTO reqDto(ResourceDefinition rd) { + rd.setName(format("EDITED: %s", rd.getName())); + rd.setUrlPrefix(format("%s-edited", rd.getName())); + return resourceDefinitionMapper.toChangeDTO(rd); + } + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: Prepare data + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.catalogDefinition(); + ResourceDefinitionChangeDTO reqDto = reqDto(resourceDefinition); + + // AND: Prepare request + RequestEntity<ResourceDefinitionChangeDTO> request = RequestEntity + .put(url(resourceDefinition.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<ResourceDefinition> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ResourceDefinition> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody().getName(), is(equalTo(reqDto.getName()))); + assertThat(result.getBody().getUrlPrefix(), is(equalTo(reqDto.getUrlPrefix()))); + } + + @Test + @DisplayName("HTTP 403: ResourceDefinition is not authenticated") + public void res403_notAuthenticated() { + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.catalogDefinition(); + createNoUserForbiddenTestPut(client, url(resourceDefinition.getUuid()), reqDto(resourceDefinition)); + } + + @Test + @DisplayName("HTTP 403: ResourceDefinition is not an admin") + public void res403_resourceDefinition() { + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.catalogDefinition(); + createUserForbiddenTestPut(client, url(resourceDefinition.getUuid()), reqDto(resourceDefinition)); + } + + @Test + @DisplayName("HTTP 404") + public void res404() { + createAdminNotFoundTestPut(client, url("nonExisting"), + reqDto(resourceDefinitionFixtures.catalogDefinition())); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..36f7b229910ffe0ee860f143a65fde1705a5af0f --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_GET.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.resource; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("GET /resource-definitions") +public class List_GET extends WebIntegrationTest { + + private URI url() { + return URI.create("/resource-definitions"); + } + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<Void> request = RequestEntity + .get(url()) + .build(); + ParameterizedTypeReference<List<ResourceDefinition>> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<List<ResourceDefinition>> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + List<ResourceDefinition> body = result.getBody(); + assertThat(body, is(equalTo(List.of( + resourceDefinitionFixtures.repositoryDefinition(), + resourceDefinitionFixtures.catalogDefinition(), + resourceDefinitionFixtures.datasetDefinition(), + resourceDefinitionFixtures.distributionDefinition() + )))); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..46dbfb8d32e2bf050c485da4abbcc2a26dbda096 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/resource/List_POST.java @@ -0,0 +1,97 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.resource; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.resource.ResourceDefinitionChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionMapper; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; + +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPost; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createUserForbiddenTestPost; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /resource-definitions") +public class List_POST extends WebIntegrationTest { + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Autowired + private ResourceDefinitionMapper resourceDefinitionMapper; + + private URI url() { + return URI.create("/resource-definitions"); + } + + private ResourceDefinitionChangeDTO reqDto(ResourceDefinition resourceDefinition) { + return resourceDefinitionMapper.toChangeDTO(resourceDefinition); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: Prepare data + ResourceDefinition resourceDefinition = resourceDefinitionFixtures.ontologyDefinition(); + ResourceDefinitionChangeDTO reqDto = reqDto(resourceDefinition); + + // AND: Prepare request + RequestEntity<ResourceDefinitionChangeDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<ResourceDefinition> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ResourceDefinition> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody().getName(), is(equalTo(reqDto.getName()))); + } + + @Test + @DisplayName("HTTP 403: ResourceDefinition is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPost(client, url(), reqDto(resourceDefinitionFixtures.ontologyDefinition())); + } + + @Test + @DisplayName("HTTP 403: ResourceDefinition is not an admin") + public void res403_resourceDefinition() { + createUserForbiddenTestPost(client, url(), reqDto(resourceDefinitionFixtures.ontologyDefinition())); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/search/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/search/List_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..f6616f3f0e9b3f469a537271c0e3034cd6d330eb --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/search/List_POST.java @@ -0,0 +1,74 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.search; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.search.SearchQueryDTO; +import nl.dtls.fairdatapoint.api.dto.search.SearchResultDTO; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("POST /search") +public class List_POST extends WebIntegrationTest { + + private URI url() { + return URI.create("/search"); + } + + private SearchQueryDTO reqDto(String query) { + return new SearchQueryDTO(query); + } + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: Prepare data + SearchQueryDTO reqDto = reqDto("catalog"); + + // AND: Prepare request + RequestEntity<SearchQueryDTO> request = RequestEntity + .post(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<List<SearchResultDTO>> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<List<SearchResultDTO>> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody().size(), is(equalTo(1))); + } + +} \ No newline at end of file diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_DELETE.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_DELETE.java new file mode 100644 index 0000000000000000000000000000000000000000..04d652b2a2b29832ef1f545be759578165aa5f7e --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_DELETE.java @@ -0,0 +1,177 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.entity.settings.SettingsMetricsEntry; +import nl.dtls.fairdatapoint.entity.settings.SettingsPing; +import nl.dtls.fairdatapoint.service.settings.SettingsCache; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.util.List; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("DELETE /settings") +public class List_DELETE extends WebIntegrationTest { + + @Autowired + private SettingsRepository settingsRepository; + + @Autowired + private SettingsCache settingsCache; + + private final ParameterizedTypeReference<SettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/settings"); + } + + private Settings customSettings() { + return Settings.builder() + .metadataMetrics( + List.of(new SettingsMetricsEntry( + "http://example.com/metric", + "http://example.com/resource" + )) + ) + .ping(SettingsPing.builder() + .enabled(false) + .endpoints(List.of( + "https://home.fairdatapoint.org", + "https://example.com/index" + )) + .build() + ) + .build(); + } + + @Test + @DisplayName("HTTP 200: default settings") + public void res200_defaultSettings() { + // GIVEN: prepare data + Settings defaultSettings = Settings.getDefault(); + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default metrics", Objects.requireNonNull(result.getBody()).getMetadataMetrics(), is(equalTo(defaultSettings.getMetadataMetrics()))); + assertThat("Response contains default ping enabled", Objects.requireNonNull(result.getBody()).getPing().getEnabled(), is(equalTo(defaultSettings.getPing().isEnabled()))); + assertThat("Response contains default ping endpoints", Objects.requireNonNull(result.getBody()).getPing().getEndpoints(), is(equalTo(defaultSettings.getPing().getEndpoints()))); + } + + @Test + @DisplayName("HTTP 200: custom settings") + public void res200_customSettings() { + // GIVEN: prepare data + Settings defaultSettings = Settings.getDefault(); + Settings customSettings = customSettings(); + settingsRepository.deleteAll(); + settingsRepository.insert(customSettings); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default metrics", Objects.requireNonNull(result.getBody()).getMetadataMetrics(), is(equalTo(defaultSettings.getMetadataMetrics()))); + assertThat("Response contains default ping enabled", Objects.requireNonNull(result.getBody()).getPing().getEnabled(), is(equalTo(defaultSettings.getPing().isEnabled()))); + assertThat("Response contains default ping endpoints", Objects.requireNonNull(result.getBody()).getPing().getEndpoints(), is(equalTo(defaultSettings.getPing().getEndpoints()))); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN + RequestEntity<?> request = RequestEntity + .delete(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN + RequestEntity<?> request = RequestEntity + .delete(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @AfterEach + public void teardown() { + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..6a54fe6457504201ae106395bc668ea053383989 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_GET.java @@ -0,0 +1,178 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.entity.settings.SettingsMetricsEntry; +import nl.dtls.fairdatapoint.entity.settings.SettingsPing; +import nl.dtls.fairdatapoint.service.settings.SettingsCache; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.util.List; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /settings") +public class List_GET extends WebIntegrationTest { + + @Autowired + private SettingsRepository settingsRepository; + + @Autowired + private SettingsCache settingsCache; + + private final ParameterizedTypeReference<SettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/settings"); + } + + private Settings customSettings() { + return Settings.builder() + .metadataMetrics( + List.of(new SettingsMetricsEntry( + "http://example.com/metric", + "http://example.com/resource" + )) + ) + .ping(SettingsPing.builder() + .enabled(false) + .endpoints(List.of( + "https://home.fairdatapoint.org", + "https://example.com/index" + )) + .build() + ) + .build(); + } + + @Test + @DisplayName("HTTP 200: default settings") + public void res200_defaultSettings() { + // GIVEN: prepare data + Settings settings = Settings.getDefault(); + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(0))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains default metrics", Objects.requireNonNull(result.getBody()).getMetadataMetrics(), is(equalTo(settings.getMetadataMetrics()))); + assertThat("Response contains default ping enabled", Objects.requireNonNull(result.getBody()).getPing().getEnabled(), is(equalTo(settings.getPing().isEnabled()))); + assertThat("Response contains default ping endpoints", Objects.requireNonNull(result.getBody()).getPing().getEndpoints(), is(equalTo(settings.getPing().getEndpoints()))); + } + + @Test + @DisplayName("HTTP 200: custom settings") + public void res200_customSettings() { + // GIVEN: prepare data + Settings settings = customSettings(); + settingsRepository.deleteAll(); + settingsRepository.insert(settings); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains custom metrics", Objects.requireNonNull(result.getBody()).getMetadataMetrics(), is(equalTo(settings.getMetadataMetrics()))); + assertThat("Response contains custom ping enabled", Objects.requireNonNull(result.getBody()).getPing().getEnabled(), is(equalTo(settings.getPing().isEnabled()))); + assertThat("Response contains custom ping endpoints", Objects.requireNonNull(result.getBody()).getPing().getEndpoints(), is(equalTo(settings.getPing().getEndpoints()))); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN + RequestEntity<?> request = RequestEntity + .get(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + } + + @AfterEach + public void teardown() { + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..60dc292c3718a8405b5d0cc963c88f73b436cf14 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/settings/List_PUT.java @@ -0,0 +1,213 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.settings; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsDTO; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsPingUpdateDTO; +import nl.dtls.fairdatapoint.api.dto.settings.SettingsUpdateDTO; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; +import nl.dtls.fairdatapoint.entity.settings.Settings; +import nl.dtls.fairdatapoint.entity.settings.SettingsMetricsEntry; +import nl.dtls.fairdatapoint.entity.settings.SettingsPing; +import nl.dtls.fairdatapoint.service.settings.SettingsCache; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.util.List; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("PUT /settings") +public class List_PUT extends WebIntegrationTest { + + @Autowired + private SettingsRepository settingsRepository; + + @Autowired + private SettingsCache settingsCache; + + private final ParameterizedTypeReference<SettingsDTO> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/settings"); + } + + private Settings customSettings() { + return Settings.builder() + .metadataMetrics( + List.of(new SettingsMetricsEntry( + "http://example.com/metric", + "http://example.com/resource" + )) + ) + .ping(SettingsPing.builder() + .enabled(false) + .endpoints(List.of( + "https://home.fairdatapoint.org", + "https://example.com/index" + )) + .build() + ) + .build(); + } + + private SettingsUpdateDTO customSettingsUpdateDTO() { + Settings customSettings = customSettings(); + return new SettingsUpdateDTO( + customSettings.getMetadataMetrics(), + new SettingsPingUpdateDTO( + customSettings.getPing().isEnabled(), + customSettings.getPing().getEndpoints() + ) + ); + } + + private SettingsUpdateDTO invalidUpdateDTO() { + Settings customSettings = customSettings(); + return new SettingsUpdateDTO( + null, + new SettingsPingUpdateDTO( + customSettings.getPing().isEnabled(), + customSettings.getPing().getEndpoints() + ) + ); + } + + @Test + @DisplayName("HTTP 200: update settings") + public void res200_updateSettings() { + // GIVEN: prepare data + Settings settings = customSettings(); + settingsRepository.deleteAll(); + settingsRepository.insert(settings); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(customSettingsUpdateDTO()); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(1))); + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Response contains custom metrics", Objects.requireNonNull(result.getBody()).getMetadataMetrics(), is(equalTo(settings.getMetadataMetrics()))); + assertThat("Response contains custom ping enabled", Objects.requireNonNull(result.getBody()).getPing().getEnabled(), is(equalTo(settings.getPing().isEnabled()))); + assertThat("Response contains custom ping endpoints", Objects.requireNonNull(result.getBody()).getPing().getEndpoints(), is(equalTo(settings.getPing().getEndpoints()))); + } + + @Test + @DisplayName("HTTP 400: invalid metrics") + public void res400_invalidList() { + // GIVEN: prepare data + SettingsUpdateDTO reqDTO = invalidUpdateDTO(); + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It indicates bad request", result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN: prepare data + SettingsUpdateDTO reqDTO = customSettingsUpdateDTO(); + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden without auth", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 403: not admin") + public void res403_notAdmin() { + // GIVEN: prepare data + SettingsUpdateDTO reqDTO = customSettingsUpdateDTO(); + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, NIKOLA_TOKEN) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTO); + + // WHEN + ResponseEntity<SettingsDTO> result = client.exchange(request, responseType); + + // THEN + assertThat("It is forbidden for non-admin users", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("No settings are created", settingsRepository.findAll().size(), is(equalTo(0))); + } + + @AfterEach + public void teardown() { + settingsRepository.deleteAll(); + settingsCache.updateCachedSettings(); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_DELETE.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_DELETE.java index 5256f52f9388e11b870d2b21bcface8cdc396a71..803e6b8980aa1e930ef97f941e822058b851c5c4 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_DELETE.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_DELETE.java @@ -23,7 +23,9 @@ package nl.dtls.fairdatapoint.acceptance.shape; import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; import nl.dtls.fairdatapoint.database.mongo.migration.development.shape.data.ShapeFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; import nl.dtls.fairdatapoint.entity.shape.Shape; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -53,11 +55,15 @@ public class Detail_DELETE extends WebIntegrationTest { @Autowired private ShapeFixtures shapeFixtures; + @Autowired + private ShapeRepository shapeRepository; + @Test @DisplayName("HTTP 204") public void res204() { // GIVEN: - Shape shape = shapeFixtures.repositoryShape(); + Shape shape = shapeFixtures.customShape(); + shapeRepository.save(shape); RequestEntity<Void> request = RequestEntity .delete(url(shape.getUuid())) .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) @@ -73,16 +79,54 @@ public class Detail_DELETE extends WebIntegrationTest { } @Test - @DisplayName("HTTP 403: Shape is not authenticated") - public void res403_notAuthenticated() { + @DisplayName("HTTP 400") + public void res400_used() { + // GIVEN: + Shape shape = shapeFixtures.datasetShape(); + RequestEntity<Void> request = RequestEntity + .delete(url(shape.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .build(); + ParameterizedTypeReference<Void> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<Void> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 400: Delete INTERNAL shape") + public void res400_internal() { + // GIVEN: Shape shape = shapeFixtures.repositoryShape(); + RequestEntity<Void> request = RequestEntity + .delete(url(shape.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .build(); + ParameterizedTypeReference<ErrorDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ErrorDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + Shape shape = shapeFixtures.datasetShape(); createUserForbiddenTestDelete(client, url(shape.getUuid())); } @Test - @DisplayName("HTTP 403: Shape is not an admin") + @DisplayName("HTTP 403: User is not an admin") public void res403_shape() { - Shape shape = shapeFixtures.repositoryShape(); + Shape shape = shapeFixtures.datasetShape(); createUserForbiddenTestDelete(client, url(shape.getUuid())); } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_PUT.java index ffd7e7dce87e2bc5ab38834828322027e64cd5c7..c4ea8d004b389315b3bf1fd91a4c5c92bc231086 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_PUT.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Detail_PUT.java @@ -53,7 +53,7 @@ public class Detail_PUT extends WebIntegrationTest { } private ShapeChangeDTO reqDto(Shape shape) { - return new ShapeChangeDTO(format("EDITED: %s", shape.getName()), shape.getDefinition()); + return new ShapeChangeDTO(format("EDITED: %s", shape.getName()), false, shape.getDefinition()); } @Autowired @@ -89,6 +89,34 @@ public class Detail_PUT extends WebIntegrationTest { Common.compare(reqDto, result.getBody()); } + @Test + @DisplayName("HTTP 200: Published") + public void res200_published() { + // GIVEN: Prepare data + Shape shape = shapeFixtures.customShapeEdited(); + ShapeChangeDTO reqDto = reqDto(shape); + reqDto.setPublished(true); + + // AND: Prepare request + RequestEntity<ShapeChangeDTO> request = RequestEntity + .put(url(shape.getUuid())) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<ShapeDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // AND: Prepare DB + shapeRepository.save(shape); + + // WHEN: + ResponseEntity<ShapeDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + Common.compare(reqDto, result.getBody()); + } + @Test @DisplayName("HTTP 400: Invalid SHACL Definition") public void res400_invalidShacl() { @@ -118,8 +146,8 @@ public class Detail_PUT extends WebIntegrationTest { } @Test - @DisplayName("HTTP 400: Edit INTERNAL shape") - public void res400() { + @DisplayName("HTTP 200: Edit INTERNAL shape") + public void res200_internal() { // GIVEN: Shape shape = shapeFixtures.repositoryShape(); ShapeChangeDTO reqDto = reqDto(shape); @@ -128,25 +156,26 @@ public class Detail_PUT extends WebIntegrationTest { .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) .accept(MediaType.APPLICATION_JSON) .body(reqDto); - ParameterizedTypeReference<ErrorDTO> responseType = new ParameterizedTypeReference<>() { + ParameterizedTypeReference<ShapeDTO> responseType = new ParameterizedTypeReference<>() { }; // WHEN: - ResponseEntity<ErrorDTO> result = client.exchange(request, responseType); + ResponseEntity<ShapeDTO> result = client.exchange(request, responseType); // THEN: - assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + Common.compare(reqDto, result.getBody()); } @Test - @DisplayName("HTTP 403: Shape is not authenticated") + @DisplayName("HTTP 403: User is not authenticated") public void res403_notAuthenticated() { Shape shape = shapeFixtures.repositoryShape(); createNoUserForbiddenTestPut(client, url(shape.getUuid()), reqDto(shape)); } @Test - @DisplayName("HTTP 403: Shape is not an admin") + @DisplayName("HTTP 403: User is not an admin") public void res403_shape() { Shape shape = shapeFixtures.repositoryShape(); createUserForbiddenTestPut(client, url(shape.getUuid()), reqDto(shape)); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Import_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Import_POST.java new file mode 100644 index 0000000000000000000000000000000000000000..b5998516e96c31b5bbcc5cfdb7072dc804be0ac1 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Import_POST.java @@ -0,0 +1,202 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.shape; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeRemoteDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.shape.data.ShapeFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /shapes/import") +public class Import_POST extends WebIntegrationTest { + + @Autowired + private ShapeRepository shapeRepository; + + @Autowired + private ShapeFixtures shapeFixtures; + + private final ParameterizedTypeReference<List<ShapeDTO>> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/shapes/import"); + } + + private ShapeRemoteDTO shapeRemoteDTO1() { + return new ShapeRemoteDTO( + "http://example.com", + UUID.randomUUID().toString(), + shapeFixtures.customShape().getName(), + shapeFixtures.customShape().getDefinition() + ); + } + + private ShapeRemoteDTO shapeRemoteDTO2() { + return new ShapeRemoteDTO( + "http://example.com", + UUID.randomUUID().toString(), + shapeFixtures.customShapeEdited().getName(), + shapeFixtures.customShapeEdited().getDefinition() + ); + } + + @Test + @DisplayName("HTTP 200: empty import") + public void res200_emptyImport() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + List<ShapeRemoteDTO> reqDTOs = Collections.emptyList(); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTOs); + + // WHEN: + ResponseEntity<List<ShapeDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Result is an empty list", result.getBody().size(), is(equalTo(0))); + assertThat("Shape repository is empty", shapeRepository.count(), is(equalTo(0L))); + } + + @Test + @DisplayName("HTTP 200: single import") + public void res200_singleImport() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + ShapeRemoteDTO shape = shapeRemoteDTO1(); + List<ShapeRemoteDTO> reqDTOs = Collections.singletonList(shape); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTOs); + + // WHEN: + ResponseEntity<List<ShapeDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Result contains one shape", result.getBody().size(), is(equalTo(1))); + assertThat("Shape is in the shape repository", shapeRepository.count(), is(equalTo(1L))); + } + + @Test + @DisplayName("HTTP 200: multiple import") + public void res200_multipleImport() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + ShapeRemoteDTO shape1 = shapeRemoteDTO1(); + ShapeRemoteDTO shape2 = shapeRemoteDTO2(); + List<ShapeRemoteDTO> reqDTOs = Arrays.asList(shape1, shape2); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, ADMIN_TOKEN) + .body(reqDTOs); + + // WHEN: + ResponseEntity<List<ShapeDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Result contains one shape", result.getBody().size(), is(equalTo(2))); + assertThat("Shape is in the shape repository", shapeRepository.count(), is(equalTo(2L))); + } + + @Test + @DisplayName("HTTP 403: no token") + public void res403_noToken() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + ShapeRemoteDTO shape = shapeRemoteDTO1(); + List<ShapeRemoteDTO> reqDTOs = Collections.singletonList(shape); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDTOs); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("Shape repository stays empty", shapeRepository.count(), is(equalTo(0L))); + } + + @Test + @DisplayName("HTTP 403: non-admin token") + public void res403_nonAdminToken() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + ShapeRemoteDTO shape1 = shapeRemoteDTO1(); + ShapeRemoteDTO shape2 = shapeRemoteDTO2(); + List<ShapeRemoteDTO> reqDTOs = Arrays.asList(shape1, shape2); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .body(reqDTOs); + + // WHEN + ResponseEntity<Void> result = client.exchange(request, new ParameterizedTypeReference<>() {}); + + // THEN: + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.FORBIDDEN))); + assertThat("Shape repository stays empty", shapeRepository.count(), is(equalTo(0L))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/List_POST.java index faacaacc2ae6dd1d415db732a78b144810c9a6bc..4da914265c8c9044de72435974b404b3ce96238c 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/List_POST.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/List_POST.java @@ -53,7 +53,7 @@ public class List_POST extends WebIntegrationTest { } private ShapeChangeDTO reqDto(Shape shape) { - return new ShapeChangeDTO(shape.getName(), shape.getDefinition()); + return new ShapeChangeDTO(shape.getName(), false, shape.getDefinition()); } @Test @@ -106,13 +106,13 @@ public class List_POST extends WebIntegrationTest { } @Test - @DisplayName("HTTP 403: Shape is not authenticated") + @DisplayName("HTTP 403: User is not authenticated") public void res403_notAuthenticated() { createNoUserForbiddenTestPost(client, url(), reqDto(shapeFixtures.customShape())); } @Test - @DisplayName("HTTP 403: Shape is not an admin") + @DisplayName("HTTP 403: User is not an admin") public void res403_shape() { createUserForbiddenTestPost(client, url(), reqDto(shapeFixtures.customShape())); } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Public_GET.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Public_GET.java new file mode 100644 index 0000000000000000000000000000000000000000..e61bc63e2f7b72aeb24ebb0ac23d2c2c3b43506b --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/shape/Public_GET.java @@ -0,0 +1,124 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.shape; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.shape.ShapeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.shape.data.ShapeFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ShapeRepository; +import nl.dtls.fairdatapoint.entity.shape.Shape; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; + +@DisplayName("GET /shapes/public") +public class Public_GET extends WebIntegrationTest { + + @Autowired + private ShapeRepository shapeRepository; + + @Autowired + private ShapeFixtures shapeFixtures; + + private final ParameterizedTypeReference<List<ShapeDTO>> responseType = + new ParameterizedTypeReference<>() { + }; + + private URI url() { + return URI.create("/shapes/public"); + } + + private Shape makeShape(Boolean published) { + return new Shape().toBuilder() + .uuid(UUID.randomUUID().toString()) + .name(shapeFixtures.customShape().getName()) + .definition(shapeFixtures.customShape().getDefinition()) + .published(published) + .targetClasses(Set.of()) + .build(); + } + + @Test + @DisplayName("HTTP 200: no published") + public void res200_noPublished() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + Shape shape = makeShape(false); + shapeRepository.insert(shape); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN: + ResponseEntity<List<ShapeDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Result is an empty list", result.getBody().size(), is(equalTo(0))); + } + + @Test + @DisplayName("HTTP 200: published") + public void res200_published() { + // GIVEN: prepare data + shapeRepository.deleteAll(); + Shape shapeNotPublished = makeShape(false); + Shape shapePublished = makeShape(true); + shapeRepository.insert(shapeNotPublished); + shapeRepository.insert(shapePublished); + + // AND: prepare request + RequestEntity<?> request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + + // WHEN: + ResponseEntity<List<ShapeDTO>> result = client.exchange(request, responseType); + + // THEN + assertThat("Correct response code is received", result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat("Response body is not null", result.getBody(), is(notNullValue())); + assertThat("Result is an empty list", result.getBody().size(), is(equalTo(1))); + assertThat("UUID matches the published shape", result.getBody().get(0).getUuid(), is(equalTo(shapePublished.getUuid()))); + } +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/token/List_POST.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/token/List_POST.java index 85c7b7dbe8cf6cb3a45c96503949cf4a8e6a86be..2f53ffb487bad9d849a20e7118a618140632a53b 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/token/List_POST.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/token/List_POST.java @@ -23,21 +23,22 @@ package nl.dtls.fairdatapoint.acceptance.token; import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.acceptance.user.Common; import nl.dtls.fairdatapoint.api.dto.auth.AuthDTO; import nl.dtls.fairdatapoint.api.dto.auth.TokenDTO; import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; +import nl.dtls.fairdatapoint.api.dto.user.UserDTO; +import nl.dtls.fairdatapoint.entity.user.User; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import java.net.URI; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.anything; +import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; @@ -45,8 +46,8 @@ import static org.hamcrest.core.IsEqual.equalTo; public class List_POST extends WebIntegrationTest { @Test - @DisplayName("HTTP 200") - public void res200() { + @DisplayName("HTTP 200: login") + public void res200_login() { // GIVEN: AuthDTO reqDto = new AuthDTO("albert.einstein@example.com", "password"); RequestEntity<AuthDTO> request = RequestEntity @@ -61,6 +62,7 @@ public class List_POST extends WebIntegrationTest { // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result.getBody(), is(notNullValue())); assertThat(result.getBody().getToken(), is(anything())); } @@ -81,7 +83,44 @@ public class List_POST extends WebIntegrationTest { // THEN: assertThat(result.getStatusCode(), is(equalTo(HttpStatus.UNAUTHORIZED))); + assertThat(result.getBody(), is(notNullValue())); assertThat(result.getBody().getMessage(), is("Invalid username/password supplied")); } + @Test + @DisplayName("HTTP 200: login and get current") + public void res200() { + //= Login (get token) + // GIVEN: + AuthDTO reqDto = new AuthDTO("albert.einstein@example.com", "password"); + RequestEntity<AuthDTO> request1 = RequestEntity + .post(URI.create("/tokens")) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<TokenDTO> responseType1 = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<TokenDTO> result1 = client.exchange(request1, responseType1); + + // THEN: + assertThat(result1.getStatusCode(), is(equalTo(HttpStatus.OK))); + assertThat(result1.getBody(), is(notNullValue())); + assertThat(result1.getBody().getToken(), is(anything())); + + //= Get current user with the token + // GIVEN: + RequestEntity<Void> request2 = RequestEntity + .get(URI.create("/users/current")) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + result1.getBody().getToken()) + .build(); + ParameterizedTypeReference<UserDTO> responseType2 = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<UserDTO> result2 = client.exchange(request2, responseType2); + + // THEN: + assertThat(result2.getStatusCode(), is(equalTo(HttpStatus.OK))); + } } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Common.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Common.java index df2fabfd7347354c960db3d049eb1b9ff857c603..0218fc27f8ecdcd353e0aa934789b6081518a1ee 100755 --- a/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Common.java +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Common.java @@ -25,6 +25,7 @@ package nl.dtls.fairdatapoint.acceptance.user; import nl.dtls.fairdatapoint.api.dto.user.UserChangeDTO; import nl.dtls.fairdatapoint.api.dto.user.UserCreateDTO; import nl.dtls.fairdatapoint.api.dto.user.UserDTO; +import nl.dtls.fairdatapoint.api.dto.user.UserProfileChangeDTO; import nl.dtls.fairdatapoint.entity.user.User; import static org.hamcrest.MatcherAssert.assertThat; @@ -45,6 +46,12 @@ public class Common { assertThat(dto.getEmail(), is(equalTo(entity.getEmail()))); } + public static void compare(UserProfileChangeDTO entity, UserDTO dto) { + assertThat(dto.getFirstName(), is(equalTo(entity.getFirstName()))); + assertThat(dto.getLastName(), is(equalTo(entity.getLastName()))); + assertThat(dto.getEmail(), is(equalTo(entity.getEmail()))); + } + public static void compare(User entity, UserDTO dto) { assertThat(dto.getUuid(), is(equalTo(entity.getUuid()))); assertThat(dto.getFirstName(), is(equalTo(entity.getFirstName()))); diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..2dbba395a68a650c49ad5a4d5a32c78c65cf7040 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_PUT.java @@ -0,0 +1,108 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.user; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.error.ErrorDTO; +import nl.dtls.fairdatapoint.api.dto.user.UserDTO; +import nl.dtls.fairdatapoint.api.dto.user.UserProfileChangeDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.*; + +import java.net.URI; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /users/:userUuid") +public class Detail_Current_PUT extends WebIntegrationTest { + + private URI url() { + return URI.create("/users/current"); + } + + private UserProfileChangeDTO reqDto() { + return new UserProfileChangeDTO("EDITED: Albert", "EDITED: Einstein", "albert.einstein.edited@example.com"); + } + + @Autowired + private UserFixtures userFixtures; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + RequestEntity<UserProfileChangeDTO> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto()); + ParameterizedTypeReference<UserDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<UserDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + Common.compare(reqDto(), result.getBody()); + } + + @Test + @DisplayName("HTTP 400: Email Already Exists") + public void res400_emailAlreadyExists() { + // GIVEN: + UserProfileChangeDTO reqDto = new UserProfileChangeDTO( + "EDITED: Albert", + "EDITED: Einstein", + "nikola.tesla@example.com"); + RequestEntity<UserProfileChangeDTO> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference<ErrorDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<ErrorDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.BAD_REQUEST))); + assertThat(result.getBody().getMessage(), is(format("Email '%s' is already taken", reqDto.getEmail()))); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url(), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_Password_PUT.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_Password_PUT.java new file mode 100644 index 0000000000000000000000000000000000000000..1061af9bf30cf5da1950424244c72b239aa32532 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/user/Detail_Current_Password_PUT.java @@ -0,0 +1,86 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.user; + +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.api.dto.user.UserDTO; +import nl.dtls.fairdatapoint.api.dto.user.UserPasswordDTO; +import nl.dtls.fairdatapoint.database.mongo.migration.development.user.data.UserFixtures; +import nl.dtls.fairdatapoint.entity.user.User; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; + +import java.net.URI; + +import static nl.dtls.fairdatapoint.acceptance.common.ForbiddenTest.createNoUserForbiddenTestPut; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +@DisplayName("PUT /users/current/password") +public class Detail_Current_Password_PUT extends WebIntegrationTest { + + private URI url() { + return URI.create("/users/current/password"); + } + + private UserPasswordDTO reqDto() { + return new UserPasswordDTO("newPassword"); + } + + @Autowired + private UserFixtures userFixtures; + + @Test + @DisplayName("HTTP 200") + public void res200() { + // GIVEN: + User user = userFixtures.albert(); + RequestEntity<UserPasswordDTO> request = RequestEntity + .put(url()) + .header(HttpHeaders.AUTHORIZATION, ALBERT_TOKEN) + .body(reqDto()); + ParameterizedTypeReference<UserDTO> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN: + ResponseEntity<UserDTO> result = client.exchange(request, responseType); + + // THEN: + assertThat(result.getStatusCode(), is(equalTo(HttpStatus.OK))); + Common.compare(user, result.getBody()); + } + + @Test + @DisplayName("HTTP 403: User is not authenticated") + public void res403_notAuthenticated() { + createNoUserForbiddenTestPut(client, url(), reqDto()); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/config/MetadataTestConfig.java b/src/test/java/nl/dtls/fairdatapoint/config/MetadataTestConfig.java index f1f3a0dcf6c35f13e00ae0f729abda215c9c2f0f..446e33242c30e5431c38f8d1536467648d4e358a 100755 --- a/src/test/java/nl/dtls/fairdatapoint/config/MetadataTestConfig.java +++ b/src/test/java/nl/dtls/fairdatapoint/config/MetadataTestConfig.java @@ -22,7 +22,6 @@ */ package nl.dtls.fairdatapoint.config; -import nl.dtls.fairdatapoint.entity.metadata.Agent; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.impl.SimpleValueFactory; @@ -34,14 +33,6 @@ public class MetadataTestConfig { private final ValueFactory VF = SimpleValueFactory.getInstance(); - @Bean(name = "publisher") - public Agent publisher() { - Agent publisher = new Agent(); - publisher.setUri(VF.createIRI("https://www.dtls.nl")); - publisher.setName(VF.createLiteral("DTLS")); - return publisher; - } - @Bean(name = "language") public IRI language() { return VF.createIRI("http://id.loc.gov/vocabulary/iso639-1/en"); diff --git a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/catalog/CatalogMetadataRepositoryTest.java b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/catalog/CatalogMetadataRepositoryTest.java index b88fba2bde9e0d867099e1494a972a2f1661d163..a67e2b6941d188631cd6b8a2b0ad4f3326439048 100755 --- a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/catalog/CatalogMetadataRepositoryTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/catalog/CatalogMetadataRepositoryTest.java @@ -48,7 +48,7 @@ import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class CatalogMetadataRepositoryTest { - private IRI catalogUri = i("http://localhost/textmining"); + private final IRI catalogUri = i("http://localhost/textmining"); @Mock private Cache cache; diff --git a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepositoryTest.java b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepositoryTest.java index d6366632b310524de5b5cd01bc0445016beb70c7..e7a4c938ac6597e326cd6753787bfffaafb0e7a9 100755 --- a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepositoryTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/common/MetadataRepositoryTest.java @@ -28,256 +28,113 @@ package nl.dtls.fairdatapoint.database.rdf.repository.common; import nl.dtls.fairdatapoint.WebIntegrationTest; -import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; -import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepositoryImpl; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Statement; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; -import org.eclipse.rdf4j.model.vocabulary.RDF; -import org.eclipse.rdf4j.repository.Repository; -import org.eclipse.rdf4j.repository.RepositoryException; -import org.junit.jupiter.api.BeforeEach; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.test.annotation.DirtiesContext; import java.util.ArrayList; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.Mockito.when; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getLanguage; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; -// TODO Get rid of DirtiesContext -@DirtiesContext public class MetadataRepositoryTest extends WebIntegrationTest { - @Autowired - @Qualifier("persistentUrl") - private String persistentUrl; - - private final ValueFactory f = SimpleValueFactory.getInstance(); - - private List<Statement> STATEMENTS; - - private final IRI TESTSUB = f.createIRI("http://www.dtls.nl/testSub"); - - private final IRI TESTOBJ = f.createIRI("http://www.dtls.nl/testObj"); - - private final Statement TESTSTMT = f.createStatement(TESTSUB, RDF.TYPE, TESTOBJ); - @Autowired private GenericMetadataRepository metadataRepository; - @Mock - private Repository repository; - - @InjectMocks - private GenericMetadataRepositoryImpl mockMetadataRepository; - @Autowired - private TestMetadataFixtures testMetadataFixtures; - - @BeforeEach - public void storeExampleFile() throws MetadataRepositoryException { - STATEMENTS = new ArrayList<>(testMetadataFixtures.repositoryMetadata()); - - metadataRepository.storeStatements(STATEMENTS, f.createIRI(persistentUrl)); - MockitoAnnotations.initMocks(this); - } + private TestRdfMetadataFixtures testMetadataFixtures; - /** - * The URI of a RDF resource can't be NULL, this test is excepted to throw - * IllegalArgumentException - */ - @DirtiesContext @Test - public void nullURI() throws MetadataRepositoryException { - assertThrows(NullPointerException.class, () -> { - metadataRepository.retrieveResource(null); - }); - } + public void findWorks() throws Exception { + // GIVEN: + IRI context = getUri(testMetadataFixtures.catalog1()); - /** - * The URI of a RDF resource can't be EMPTY, this test is excepted to throw - * IllegalArgumentException - */ - @DirtiesContext - @Test - public void emptyURI() throws MetadataRepositoryException { - assertThrows(IllegalArgumentException.class, () -> { + // WHEN: + List<Statement> result = metadataRepository.find(context); - String uri = ""; - metadataRepository.retrieveResource(f.createIRI(uri)); - }); + // THEN: + assertThat(result.size(), is(equalTo(30))); } - /** - * This test is excepted to throw execption - */ - @DirtiesContext @Test - public void emptyInvalidURI() throws MetadataRepositoryException { - assertThrows(IllegalArgumentException.class, () -> { - String uri = "..."; - metadataRepository.retrieveResource(f.createIRI(uri)); - }); - } + public void findNonExistingResource() throws Exception { + // GIVEN: + IRI context = i("http://localhost/non-existing"); - /** - * The test is excepted to retrieve ZERO statements - */ - @DirtiesContext - @Test - public void retrieveNonExitingResource() throws Exception { + // WHEN: + List<Statement> result = metadataRepository.find(context); - String uri = "http://localhost/dummy"; - List<Statement> statements = metadataRepository.retrieveResource(f.createIRI(uri)); - assertTrue(statements.isEmpty()); + // THEN: + assertThat(result.size(), is(equalTo(0))); } - /** - * The test is excepted retrieve to retrieve one or more statements - */ - @DirtiesContext @Test - public void retrieveExitingResource() throws Exception { + public void checkExistenceWorks() throws Exception { + // GIVEN: + Model metadata = testMetadataFixtures.catalog1(); - List<Statement> statements = metadataRepository.retrieveResource( - f.createIRI(persistentUrl)); - assertTrue(statements.size() > 0); + // WHEN: + boolean result = metadataRepository.checkExistence(getUri(metadata), DCTERMS.LANGUAGE, getLanguage(metadata)); + + // THEN: + assertThat(result, is(equalTo(true))); } - /** - * The test is excepted to throw error - */ - @DirtiesContext @Test - public void retrieveResourceCatchBlock() throws Exception { - assertThrows(MetadataRepositoryException.class, () -> { + public void saveWorks() throws Exception { + // GIVEN: + Model metadata = testMetadataFixtures.c1_d2_distribution3(); + IRI context = getUri(metadata); + ArrayList<Statement> statements = new ArrayList<>(metadata); - when(repository.getConnection()).thenThrow(RepositoryException.class); - mockMetadataRepository.retrieveResource(f.createIRI(persistentUrl)); - }); - } + // WHEN: + metadataRepository.save(statements, context); - /** - * The test is excepted to pass - */ - @DirtiesContext - @Test - public void storeResource() { - try { - metadataRepository.storeStatements(STATEMENTS); - } catch (MetadataRepositoryException ex) { - fail("The test is not excepted to throw MetadataRepositoryException"); - } + // THEN: + assertThat(metadataRepository.find(context).size(), is(equalTo(28))); } - /** - * The test is excepted to pass - */ - @DirtiesContext @Test - public void deleteRource() { - try { - List<Statement> sts = new ArrayList<>(); - sts.add(TESTSTMT); - metadataRepository.storeStatements(sts); - metadataRepository.removeStatement(TESTSUB, RDF.TYPE, null); - } catch (MetadataRepositoryException ex) { - fail("The test is not excepted to throw MetadataRepositoryException"); - } - } + public void removeWorks() throws Exception { + // GIVEN: + Model metadata = testMetadataFixtures.catalog1(); + IRI context = getUri(metadata); - /** - * The test is excepted to pass - */ - @DirtiesContext - @Test - public void storeStatement() { - try { - metadataRepository.storeStatements(STATEMENTS, TESTSUB); - } catch (MetadataRepositoryException ex) { - fail("The test is not excepted to throw MetadataRepositoryException"); - } - } + // AND: Check existence before delete + assertThat(metadataRepository.find(context).size(), is(equalTo(30))); - /** - * The test is excepted to retrieve return false - */ - @DirtiesContext - @Test - public void checkNonExitingResource() throws Exception { - String uri = "http://localhost/dummy"; - boolean isStatementExist = metadataRepository.isStatementExist(f.createIRI(uri), null, null); - assertFalse(isStatementExist); - } + // WHEN: + metadataRepository.remove(context); - /** - * The test is excepted to retrieve return true - */ - @DirtiesContext - @Test - public void checkExitingResource() throws Exception { - boolean isStatementExist = metadataRepository.isStatementExist( - f.createIRI(persistentUrl), null, null); - assertTrue(isStatementExist); + // THEN: + assertThat(metadataRepository.find(context).size(), is(equalTo(0))); } - /** - * Check exception handling of delete resource method - */ - @DirtiesContext @Test - public void checkExceptionsDeleteResourceMethod() throws Exception { - assertThrows(MetadataRepositoryException.class, () -> { - when(repository.getConnection()).thenThrow(RepositoryException.class); - mockMetadataRepository.removeResource(null); - }); - } + public void removeStatementWorks() throws Exception { + // GIVEN: + Model metadata = testMetadataFixtures.catalog1(); + IRI context = getUri(metadata); - /** - * Check exception handling of remove statement method - */ - @DirtiesContext - @Test - public void checkExceptionsRemoveStatementMethod() throws Exception { - assertThrows(MetadataRepositoryException.class, () -> { - when(repository.getConnection()).thenThrow(RepositoryException.class); - mockMetadataRepository.removeStatement(null, null, null); - }); - } + // AND: Check existence before delete + assertThat(metadataRepository.find(context).size(), is(equalTo(30))); - /** - * Check exception handling of isStatementExist method - */ - @DirtiesContext - @Test - public void checkExceptionsIsStatementMethod() throws Exception { - assertThrows(MetadataRepositoryException.class, () -> { - when(repository.getConnection()).thenThrow(RepositoryException.class); - mockMetadataRepository.isStatementExist(f.createIRI(persistentUrl), - null, null); - }); - } + // WHEN: + metadataRepository.removeStatement(getUri(metadata), DCTERMS.LANGUAGE, getLanguage(metadata), context); - /** - * Check exception handling of storeStatement method - */ - @DirtiesContext - @Test - public void checkExceptionsStoreStatementMethod() throws Exception { - assertThrows(MetadataRepositoryException.class, () -> { - when(repository.getConnection()).thenThrow(RepositoryException.class); - mockMetadataRepository.storeStatements(STATEMENTS); - }); + // THEN: + assertThat(metadataRepository.find(context).size(), is(equalTo(29))); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryTest.java b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryTest.java index e6aacbf3dfcf3a9e364abcf4f985156a383c8542..4e54801dd3cac57ee75cf4b9d9d4e66184ea308e 100755 --- a/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/database/rdf/repository/generic/GenericMetadataRepositoryTest.java @@ -22,99 +22,108 @@ */ package nl.dtls.fairdatapoint.database.rdf.repository.generic; +import nl.dtls.fairdatapoint.WebIntegrationTest; +import nl.dtls.fairdatapoint.database.rdf.repository.catalog.CatalogMetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Resource; -import org.eclipse.rdf4j.model.Value; -import org.eclipse.rdf4j.repository.Repository; -import org.eclipse.rdf4j.repository.RepositoryConnection; -import org.junit.jupiter.api.BeforeEach; +import org.eclipse.rdf4j.model.Model; +import org.eclipse.rdf4j.model.vocabulary.DCTERMS; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.Spy; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.concurrent.ConcurrentMapCacheManager; -import java.util.Collections; +import java.util.ArrayList; import static nl.dtls.fairdatapoint.config.CacheConfig.CATALOG_THEMES_CACHE; -import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; -import static org.mockito.Mockito.*; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getLanguage; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.hamcrest.core.IsNull.nullValue; -public class GenericMetadataRepositoryTest { +public class GenericMetadataRepositoryTest extends WebIntegrationTest { - private IRI catalogUri = i("http://localhost/textmining"); - - @Spy - private Cache cache; - - @Mock - private Repository repository; - - @Mock - private RepositoryConnection repositoryConnection; - - @Mock - private Resource resource; - - @Mock - private Value value; - - @Mock + @Autowired private ConcurrentMapCacheManager cacheManager; - @InjectMocks - @Spy - private GenericMetadataRepositoryImpl metadataRepository; + @Autowired + private TestRdfMetadataFixtures testMetadataFixtures; - @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - } + @Autowired + private GenericMetadataRepository metadataRepository; + + @Autowired + private CatalogMetadataRepository catalogMetadataRepository; @Test - @DisplayName("'storeStatements' should evict cache") - public void storeStatementsEvictsCache() throws MetadataRepositoryException { + @DisplayName("'save' should evict cache") + public void saveEvictsCache() throws MetadataRepositoryException { // GIVEN: - when(cacheManager.getCache(CATALOG_THEMES_CACHE)).thenReturn(cache); - when(repository.getConnection()).thenReturn(repositoryConnection); + Model catalog = testMetadataFixtures.catalog1(); + IRI catalogUri = getUri(catalog); + Model dataset = testMetadataFixtures.c1_dataset1(); + + // AND: Compute cache + catalogMetadataRepository.getDatasetThemesForCatalog(catalogUri); + + // AND: Check if cache is full + assertThat(getCache().get(catalogUri.stringValue()), is(notNullValue())); // WHEN: - metadataRepository.storeStatements(Collections.emptyList(), catalogUri); + metadataRepository.save(new ArrayList<>(dataset), getUri(dataset)); // THEN: - verify(cache, times(1)).evict(catalogUri.toString()); + assertThat(getCache().get(catalogUri.stringValue()), is(nullValue())); } @Test @DisplayName("'removeStatement' should evict cache") public void removeStatementEvictsCache() throws MetadataRepositoryException { // GIVEN: - when(cacheManager.getCache(CATALOG_THEMES_CACHE)).thenReturn(cache); - when(repository.getConnection()).thenReturn(repositoryConnection); + Model catalog = testMetadataFixtures.catalog1(); + IRI catalogUri = getUri(catalog); + Model dataset = testMetadataFixtures.c1_dataset1(); + + // AND: Compute cache + catalogMetadataRepository.getDatasetThemesForCatalog(catalogUri); + + // AND: Check if cache is full + assertThat(getCache().get(catalogUri.stringValue()), is(notNullValue())); // WHEN: - metadataRepository.removeStatement(resource, catalogUri, value); + metadataRepository.removeStatement(getUri(dataset), DCTERMS.LANGUAGE, getLanguage(dataset), getUri(dataset)); // THEN: - verify(cache, times(1)).evict(catalogUri.toString()); + assertThat(getCache().get(catalogUri.stringValue()), is(nullValue())); } @Test - @DisplayName("'removeResource' should evict cache") - public void removeResourceEvictsCache() throws MetadataRepositoryException { + @DisplayName("'remove' should evict cache") + public void removeEvictsCache() throws MetadataRepositoryException { // GIVEN: - when(cacheManager.getCache(CATALOG_THEMES_CACHE)).thenReturn(cache); - when(repository.getConnection()).thenReturn(repositoryConnection); + Model catalog = testMetadataFixtures.catalog1(); + IRI catalogUri = getUri(catalog); + Model dataset = testMetadataFixtures.c1_dataset1(); + + // AND: Compute cache + catalogMetadataRepository.getDatasetThemesForCatalog(catalogUri); + + // AND: Check if cache is full + assertThat(getCache().get(catalogUri.stringValue()), is(notNullValue())); // WHEN: - metadataRepository.removeResource(catalogUri); + metadataRepository.remove(getUri(dataset)); // THEN: - verify(cache, times(1)).evict(catalogUri.toString()); + assertThat(getCache().get(catalogUri.stringValue()), is(nullValue())); + } + + private Cache getCache() { + return cacheManager.getCache(CATALOG_THEMES_CACHE); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterServiceTest.java b/src/test/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..62c7a0b01541e223e4f230028d2c78646bb19318 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/service/index/harvester/HarvesterServiceTest.java @@ -0,0 +1,149 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.index.harvester; + +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.data.RdfMetadataFixtures; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.factory.MetadataFactoryImpl; +import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; +import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.metadata.enhance.MetadataEnhancer; +import nl.dtls.fairdatapoint.service.profile.ProfileService; +import nl.dtls.fairdatapoint.service.resource.ResourceDefinitionCache; +import nl.dtls.fairdatapoint.vocabulary.R3D; +import org.eclipse.rdf4j.model.Model; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; +import static nl.dtls.fairdatapoint.util.RdfIOUtil.write; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +public class HarvesterServiceTest { + + @Mock + private RestTemplate restTemplate; + + @Mock + private ResourceDefinitionCache resourceDefinitionCache; + + @Spy + private GenericMetadataRepository genericMetadataRepository; + + @InjectMocks + private static MetadataEnhancer metadataEnhancer; + + @InjectMocks + private HarvesterService harvesterService; + + private final String repositoryUrl = "http://fairdatapoint.example"; + + private Model repository; + + private final String catalogUrl = "http://fairdatapoint.example/catalog/catalog-1"; + + private Model catalog; + + @BeforeEach + private void setup() { + // Setup resource definition; + ResourceDefinitionFixtures resourceDefinitionFixtures = new ResourceDefinitionFixtures(); + + // Setup RDF fixtures + RdfMetadataFixtures fixtures = new RdfMetadataFixtures(new MetadataFactoryImpl()); + + // Create repository + repository = fixtures.repositoryMetadata(repositoryUrl); + ResourceDefinition rdRepository = resourceDefinitionFixtures.repositoryDefinition(); + + // Create catalog + catalog = fixtures.catalog1(repositoryUrl, getUri(repository)); + repository.add(i(repositoryUrl), R3D.DATACATALOG, i(catalogUrl)); + } + + @Test + public void harvestSucceed() throws MetadataRepositoryException { + // GIVEN: Mock webserver + mockEndpoint(repositoryUrl, repository); + mockEndpoint(catalogUrl, catalog); + + // WHEN: + harvesterService.harvest(repositoryUrl); + + // THEN: + verify(genericMetadataRepository, times(1)).save(anyList(), eq(i(repositoryUrl))); + verify(genericMetadataRepository, times(1)).save(anyList(), eq(i(catalogUrl))); + } + + @Test + public void harvestFailedForLinkedChildren() throws MetadataRepositoryException { + // GIVEN: Mock webserver + mockEndpoint(repositoryUrl, repository); + mockEndpoint404(catalogUrl); + + // WHEN: + harvesterService.harvest(repositoryUrl); + + // THEN: + verify(genericMetadataRepository, times(1)).save(anyList(), eq(i(repositoryUrl))); + verify(genericMetadataRepository, times(0)).save(anyList(), eq(i(catalogUrl))); + } + + private void mockEndpoint(String url, Model body) { + // Create response + MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); + headers.set("Content-Type", "text/turtle"); + ResponseEntity<String> responseBody = new ResponseEntity<>(write(body), headers, HttpStatus.OK); + + // Mock + when(restTemplate.exchange(eq(url), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class))) + .thenReturn(responseBody); + } + + private void mockEndpoint404(String url) { + // Create response + ResponseEntity<String> responseBody = new ResponseEntity<>("", HttpStatus.NOT_FOUND); + + // Mock + when(restTemplate.exchange(eq(url), eq(HttpMethod.GET), any(HttpEntity.class), eq(String.class))) + .thenReturn(responseBody); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceMockTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceMockTest.java index 586dfde217587dc17b899fc6043d4d617855112a..a061880269a3b3001deb0cba0877f4556c266234 100755 --- a/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceMockTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceMockTest.java @@ -25,7 +25,7 @@ package nl.dtls.fairdatapoint.service.metadata.catalog; import nl.dtls.fairdatapoint.BaseIntegrationTest; import nl.dtls.fairdatapoint.database.rdf.repository.catalog.CatalogMetadataRepository; import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepositoryImpl; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Statement; @@ -53,7 +53,7 @@ import static org.mockito.Mockito.when; public class CatalogMetadataServiceMockTest extends BaseIntegrationTest { @Autowired - private TestMetadataFixtures testMetadataFixtures; + private TestRdfMetadataFixtures testMetadataFixtures; @Mock private GenericMetadataRepositoryImpl metadataRepository; @@ -65,8 +65,8 @@ public class CatalogMetadataServiceMockTest extends BaseIntegrationTest { private CatalogMetadataService catalogMetadataService; @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); + public void setUp() throws Exception { + MockitoAnnotations.openMocks(this).close(); } @Test @@ -74,7 +74,7 @@ public class CatalogMetadataServiceMockTest extends BaseIntegrationTest { // GIVEN: Retrieve catalog from Repository Model catalog = testMetadataFixtures.catalog1(); List<Statement> catalogStatements = new ArrayList<>(catalog); - when(metadataRepository.retrieveResource(getUri(catalog))).thenReturn(catalogStatements); + when(metadataRepository.find(getUri(catalog))).thenReturn(catalogStatements); // AND: Retrieve themes from datasets IRI theme1 = i("http://localhost/my_theme_1"); @@ -87,11 +87,9 @@ public class CatalogMetadataServiceMockTest extends BaseIntegrationTest { // THEN: List<IRI> themeTaxonomys = getThemeTaxonomies(catalogMetadata); - assertThat(themeTaxonomys.size(), is(equalTo(4))); + assertThat(themeTaxonomys.size(), is(equalTo(2))); assertThat(themeTaxonomys.get(0), is(equalTo(theme1))); assertThat(themeTaxonomys.get(1), is(equalTo(theme2_duplicated))); - assertThat(themeTaxonomys.get(2), is(equalTo(getThemeTaxonomies(catalog).get(1)))); - assertThat(themeTaxonomys.get(3), is(equalTo(getThemeTaxonomies(catalog).get(0)))); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceTest.java deleted file mode 100755 index f539f00bee6b88d43fd21a960f07d0fbb596bc2f..0000000000000000000000000000000000000000 --- a/src/test/java/nl/dtls/fairdatapoint/service/metadata/catalog/CatalogMetadataServiceTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package nl.dtls.fairdatapoint.service.metadata.catalog; - -import nl.dtls.fairdatapoint.BaseIntegrationTest; -import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; -import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; -import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; -import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Model; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.time.LocalDateTime; - -import static java.lang.String.format; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.*; -import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; -import static org.junit.jupiter.api.Assertions.*; - -public class CatalogMetadataServiceTest extends BaseIntegrationTest { - - @Autowired - private TestMetadataFixtures testMetadataFixtures; - - @Autowired - @Qualifier("genericMetadataService") - private MetadataService genericMetadataService; - - @Autowired - @Qualifier("catalogMetadataService") - private MetadataService catalogMetadataService; - - @Autowired - private ResourceDefinitionFixtures resourceDefinitionFixtures; - - private ResourceDefinition catalogRd; - - @BeforeEach - public void setUp() throws Exception { - catalogRd = resourceDefinitionFixtures.catalogDefinition(); - } - - @Test - public void retrieveNonExitingMetadata() { - assertThrows(ResourceNotFoundException.class, () -> { - // GIVEN: - IRI repositoryUri = getUri(testMetadataFixtures.repositoryMetadata()); - IRI catalogUri = i(format("%s/non-existing", repositoryUri)); - - // WHEN: - catalogMetadataService.retrieve(catalogUri); - - // THEN: - // Expect exception - }); - } - - @Test - public void specsLink() throws Exception { - // GIVEN: - Model catalog = testMetadataFixtures.catalog3(); - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // WHEN: - Model metadata = catalogMetadataService.retrieve(getUri(catalog)); - - // THEN: - assertNotNull(getSpecification(metadata)); - } - - @Test - public void storeAndRetrieve() throws Exception { - // GIVEN: - Model catalog = testMetadataFixtures.catalog3(); - - // WHEN: - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // THEN: - assertNotNull(catalogMetadataService.retrieve(getUri(catalog))); - } - - @Test - public void storeWithNoID() throws Exception { - // GIVEN: - Model catalog = testMetadataFixtures.catalog3(); - setMetadataIdentifier(catalog, getUri(catalog), null); - - // WHEN: - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // THEN: - Model result = catalogMetadataService.retrieve(getUri(catalog)); - assertNotNull(getMetadataIdentifier(result)); - } - - @Test - public void storeWithNoLanguage() throws Exception { - // GIVEN: - Model catalog = testMetadataFixtures.catalog3(); - setLanguage(catalog, getUri(catalog), null); - - // WHEN: - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // THEN: - Model result = catalogMetadataService.retrieve(getUri(catalog)); - assertNotNull(getLanguage(result)); - } - - @Test - public void storeWithNoLicense() throws Exception { - // GIVEN: - Model catalog = testMetadataFixtures.catalog3(); - setLicence(catalog, getUri(catalog), null); - - // WHEN: - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // THEN: - Model result = catalogMetadataService.retrieve(getUri(catalog)); - assertNotNull(getLicence(result)); - } - - @Test - public void updateParent() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - Model catalog = testMetadataFixtures.catalog3(); - - // WHEN: - catalogMetadataService.store(catalog, getUri(catalog), catalogRd); - - // THEN: - Model updatedRepository = genericMetadataService.retrieve(getUri(repository)); - Model updatedCatalog = catalogMetadataService.retrieve(getUri(catalog)); - LocalDateTime repositoryModified = getModified(updatedRepository); - LocalDateTime catalogModified = getModified(updatedCatalog); - assertFalse(repositoryModified.isBefore(catalogModified), "FDP modified is not after Catalog modified"); - } - -} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadata/common/GenericMetadataServiceTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/common/GenericMetadataServiceTest.java deleted file mode 100755 index 8797ff04c7a73ec863fb3d84831746546e1e3b5e..0000000000000000000000000000000000000000 --- a/src/test/java/nl/dtls/fairdatapoint/service/metadata/common/GenericMetadataServiceTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package nl.dtls.fairdatapoint.service.metadata.common; - -import nl.dtls.fairdatapoint.BaseIntegrationTest; -import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; -import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; -import nl.dtls.fairdatapoint.entity.exception.ValidationException; -import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; -import nl.dtls.fairdatapoint.service.metadata.exception.MetadataServiceException; -import nl.dtls.fairdatapoint.utils.AuthHelper; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Model; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import java.time.LocalDateTime; - -import static java.lang.String.format; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.*; -import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; -import static org.junit.jupiter.api.Assertions.*; - -public class GenericMetadataServiceTest extends BaseIntegrationTest { - - @Autowired - private TestMetadataFixtures testMetadataFixtures; - - @Autowired - @Qualifier("genericMetadataService") - private MetadataService genericMetadataService; - - @Autowired - @Qualifier("catalogMetadataService") - private MetadataService catalogMetadataService; - - @Autowired - private AuthHelper authHelper; - - @Autowired - private ResourceDefinitionFixtures resourceDefinitionFixtures; - - private ResourceDefinition distributionRd; - - @BeforeEach - public void before() { - authHelper.authenticateAsAlbert(); - distributionRd = resourceDefinitionFixtures.distributionDefinition(); - } - - @Test - public void retrieveNonExitingMetadata() { - assertThrows(ResourceNotFoundException.class, () -> { - // GIVEN: - IRI repositoryUri = getUri(testMetadataFixtures.repositoryMetadata()); - IRI datasetUri = i(format("%s/non-existing", repositoryUri)); - - // WHEN: - genericMetadataService.retrieve(datasetUri); - - // THEN: - // Expect exception - }); - } - - @Test - public void existenceDatasetMetaDataSpecsLink() throws Exception { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - Model metadata = genericMetadataService.retrieve(getUri(distribution)); - assertNotNull(getSpecification(metadata)); - } - - @Test - public void storeAndRetrieve() throws Exception { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - assertNotNull(genericMetadataService.retrieve(getUri(distribution))); - } - - @Test - public void storeWithNoParentURI() { - assertThrows(MetadataServiceException.class, () -> { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - setParent(distribution, getUri(distribution), null); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - // Expect exception - }); - } - - @Test - public void storeWithWrongParentURI() { - assertThrows(ValidationException.class, () -> { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - setParent(distribution, getUri(distribution), getUri(repository)); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - // Expect exception - }); - } - - @Test - public void storeWithNoID() throws Exception { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - setMetadataIdentifier(distribution, getUri(distribution), null); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - Model mdata = genericMetadataService.retrieve(getUri(distribution)); - assertNotNull(getMetadataIdentifier(mdata)); - } - - @Test - public void storeWithNoLicense() throws Exception { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - setLicence(distribution, getUri(distribution), null); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - Model mdata = genericMetadataService.retrieve(getUri(distribution)); - assertNotNull(getLicence(mdata)); - } - - @Test - public void storeWithNoLanguage() throws Exception { - // GIVEN: - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - setLanguage(distribution, getUri(distribution), null); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - Model mdata = genericMetadataService.retrieve(getUri(distribution)); - assertNotNull(getLanguage(mdata)); - } - - @Test - public void updateParent() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - Model catalog = testMetadataFixtures.catalog1(); - Model dataset = testMetadataFixtures.c1_dataset1(); - Model distribution = testMetadataFixtures.c1_d1_distribution1(); - - // WHEN: - genericMetadataService.store(distribution, getUri(distribution), distributionRd); - - // THEN: - Model updatedRepository = genericMetadataService.retrieve(getUri(repository)); - Model updatedCatalog = catalogMetadataService.retrieve(getUri(catalog)); - Model updatedDataset = genericMetadataService.retrieve(getUri(dataset)); - Model storedDistribution = genericMetadataService.retrieve(getUri(distribution)); - LocalDateTime repositoryModified = getModified(updatedRepository); - LocalDateTime catalogModified = getModified(updatedCatalog); - LocalDateTime datasetModified = getModified(updatedDataset); - LocalDateTime distributionModified = getModified(storedDistribution); - assertFalse(datasetModified.isBefore(distributionModified), "Dataset modified is not after Distribution " + - "modified"); - assertFalse(catalogModified.isBefore(distributionModified), "Catalog modified is not after Dataset modified"); - assertFalse(repositoryModified.isBefore(distributionModified), "FDP modified is not after Dataset modified"); - } - -} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataServiceTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fe45771b9b38fd60671bedd4e62269b8460556b8 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/service/metadata/generic/GenericMetadataServiceTest.java @@ -0,0 +1,212 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.metadata.generic; + +import nl.dtls.fairdatapoint.BaseIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.entity.exception.ResourceNotFoundException; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; +import nl.dtls.fairdatapoint.utils.AuthHelper; +import nl.dtls.fairdatapoint.utils.TestRdfMetadataFixtures; +import org.eclipse.rdf4j.model.IRI; +import org.eclipse.rdf4j.model.Model; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +import java.time.OffsetDateTime; + +import static java.lang.String.format; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; +import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.*; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.junit.jupiter.api.Assertions.*; + +public class GenericMetadataServiceTest extends BaseIntegrationTest { + + @Autowired + private TestRdfMetadataFixtures testMetadataFixtures; + + @Autowired + @Qualifier("genericMetadataService") + private MetadataService genericMetadataService; + + @Autowired + @Qualifier("catalogMetadataService") + private MetadataService catalogMetadataService; + + @Autowired + private AuthHelper authHelper; + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @BeforeEach + public void before() { + authHelper.authenticateAsAdmin(); + } + + @Test + public void retrieveNonExitingMetadataThrowsError() { + // GIVEN: + IRI repositoryUri = getUri(testMetadataFixtures.repositoryMetadata()); + IRI metadataUri = i(format("%s/distribution/non-existing", repositoryUri)); + + // WHEN: + ResourceNotFoundException exception = assertThrows( + ResourceNotFoundException.class, + () -> genericMetadataService.retrieve(metadataUri) + ); + + // THEN: + assertThat(exception.getMessage(), is(equalTo(format("No metadata found for the uri '%s'", metadataUri)))); + } + + @Test + public void storeWorks() throws Exception { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + + // WHEN: + genericMetadataService.store(metadata, getUri(metadata), metadataRd); + + // THEN: + Model metadataFromDB = genericMetadataService.retrieve(getUri(metadata)); + assertNotNull(metadataFromDB); + } + + @Test + public void storeWithNoParentURIThrowsError() { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + setParent(metadata, getUri(metadata), null); + + // WHEN: + ValidationException exception = assertThrows( + ValidationException.class, + () -> genericMetadataService.store(metadata, getUri(metadata), metadataRd) + ); + + // THEN: + assertThat(exception.getMessage(), is(equalTo("Metadata has no parent"))); + } + + @Test + public void storeWithWrongParentURIThrowsError() { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model repository = testMetadataFixtures.repositoryMetadata(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + setParent(metadata, getUri(metadata), getUri(repository)); + + // WHEN: + ValidationException exception = assertThrows( + ValidationException.class, + () -> genericMetadataService.store(metadata, getUri(metadata), metadataRd) + ); + + // THEN: + assertThat(exception.getMessage(), is(equalTo("Parent is not of correct type (RD: Repository)"))); + } + + @Test + public void storeWithNoMetadataIdentifier() throws Exception { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + setMetadataIdentifier(metadata, getUri(metadata), null); + + // WHEN: + genericMetadataService.store(metadata, getUri(metadata), metadataRd); + + // THEN: + Model metadataFromDB = genericMetadataService.retrieve(getUri(metadata)); + assertNotNull(getMetadataIdentifier(metadataFromDB)); + } + + @Test + public void storeWithNoLicense() throws Exception { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + setLicence(metadata, getUri(metadata), null); + + // WHEN: + genericMetadataService.store(metadata, getUri(metadata), metadataRd); + + // THEN: + Model metadataFromDB = genericMetadataService.retrieve(getUri(metadata)); + assertNotNull(getLicence(metadataFromDB)); + } + + @Test + public void storeWithNoLanguage() throws Exception { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model metadata = testMetadataFixtures.c1_d1_distribution1(); + setLanguage(metadata, getUri(metadata), null); + + // WHEN: + genericMetadataService.store(metadata, getUri(metadata), metadataRd); + + // THEN: + Model metadataFromDB = genericMetadataService.retrieve(getUri(metadata)); + assertNotNull(getLanguage(metadataFromDB)); + } + + @Test + public void updateParent() throws Exception { + // GIVEN: + ResourceDefinition metadataRd = resourceDefinitionFixtures.distributionDefinition(); + Model repository = testMetadataFixtures.repositoryMetadata(); + Model catalog = testMetadataFixtures.catalog1(); + Model dataset = testMetadataFixtures.c1_dataset1(); + Model distribution = testMetadataFixtures.c1_d1_distribution1(); + + // WHEN: + genericMetadataService.store(distribution, getUri(distribution), metadataRd); + + // THEN: + Model updatedRepository = genericMetadataService.retrieve(getUri(repository)); + Model updatedCatalog = catalogMetadataService.retrieve(getUri(catalog)); + Model updatedDataset = genericMetadataService.retrieve(getUri(dataset)); + Model storedDistribution = genericMetadataService.retrieve(getUri(distribution)); + OffsetDateTime repositoryModified = getModified(updatedRepository); + OffsetDateTime catalogModified = getModified(updatedCatalog); + OffsetDateTime datasetModified = getModified(updatedDataset); + OffsetDateTime distributionModified = getModified(storedDistribution); + assertFalse(datasetModified.isBefore(distributionModified), "Dataset modified is not after Distribution " + + "modified"); + assertFalse(catalogModified.isBefore(distributionModified), "Catalog modified is not after Dataset modified"); + assertFalse(repositoryModified.isBefore(distributionModified), "FDP modified is not after Dataset modified"); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImplTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataServiceTest.java old mode 100755 new mode 100644 similarity index 55% rename from src/test/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImplTest.java rename to src/test/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataServiceTest.java index 8c095bf437c5da7924ef0758995d5000d67d3b2b..8e1e5b8fa551a0ecd2a71c99120e32bd644e6c58 --- a/src/test/java/nl/dtls/fairdatapoint/service/metadatametrics/FairMetadataMetricsServiceImplTest.java +++ b/src/test/java/nl/dtls/fairdatapoint/service/metadata/metric/MetricsMetadataServiceTest.java @@ -25,48 +25,42 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package nl.dtls.fairdatapoint.service.metadatametrics; +package nl.dtls.fairdatapoint.service.metadata.metric; import nl.dtls.fairdatapoint.BaseIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.repository.SettingsRepository; import nl.dtls.fairdatapoint.entity.metadata.Metric; -import org.eclipse.rdf4j.model.ValueFactory; -import org.eclipse.rdf4j.model.impl.SimpleValueFactory; +import nl.dtls.fairdatapoint.service.settings.SettingsCache; +import org.eclipse.rdf4j.model.IRI; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import java.util.List; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.i; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; -// TODO What is purpose of this class -public class FairMetadataMetricsServiceImplTest extends BaseIntegrationTest { +public class MetricsMetadataServiceTest extends BaseIntegrationTest { - private final ValueFactory valueFactory = SimpleValueFactory.getInstance(); @Autowired - private FairMetadataMetricsServiceImpl fmMetricsServiceImpl; + private MetricsMetadataService metricsMetadataService; - /** - * Test getMetrics with null uri, this test is excepted to throw error - */ @Test - public void nullMetadataUri() { - assertThrows(NullPointerException.class, () -> { - fmMetricsServiceImpl.getMetrics(null); - }); - } + public void generateMetricsWorks() { + // GIVEN: + IRI entityUri = i("http://localhost"); - /** - * This test is excepted to pass - */ - @Test - public void validMetadataUri() { -// Map<String, String> metadataMetrics = new HashMap<>(); -// metadataMetrics.put("https://purl.org/fair-metrics/FM_F1A", "http://example.com/f1a"); -// fmMetricsServiceImpl.setMetadataMetrics(metadataMetrics); + // WHEN: + List<Metric> result = metricsMetadataService.generateMetrics(entityUri); - List<Metric> m = fmMetricsServiceImpl.getMetrics(valueFactory.createIRI("http://localhost")); - assertTrue(m.size() > 0); + // THEN: + assertThat(result.size(), is(equalTo(2))); + assertThat(result.get(0).getValue(), is(equalTo(i("https://www.ietf.org/rfc/rfc3986.txt")))); + assertThat(result.get(0).getMetricType(), is(equalTo(i("https://www.ietf.org/rfc/rfc3986.txt")))); + assertThat(result.get(1).getValue(), is(equalTo(i("https://www.wikidata.org/wiki/Q8777")))); + assertThat(result.get(1).getMetricType(), is(equalTo(i("https://www.wikidata.org/wiki/Q8777")))); } } diff --git a/src/test/java/nl/dtls/fairdatapoint/service/metadata/repository/RepositoryMetadataServiceTest.java b/src/test/java/nl/dtls/fairdatapoint/service/metadata/repository/RepositoryMetadataServiceTest.java deleted file mode 100755 index 41ae555b6618ad7eb9db9301bd1f379ad42c73b5..0000000000000000000000000000000000000000 --- a/src/test/java/nl/dtls/fairdatapoint/service/metadata/repository/RepositoryMetadataServiceTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * The MIT License - * Copyright © 2017 DTL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package nl.dtls.fairdatapoint.service.metadata.repository; - -import nl.dtls.fairdatapoint.BaseIntegrationTest; -import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; -import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; -import nl.dtls.fairdatapoint.service.metadata.common.MetadataService; -import nl.dtls.fairdatapoint.utils.AuthHelper; -import nl.dtls.fairdatapoint.utils.TestMetadataFixtures; -import org.eclipse.rdf4j.model.IRI; -import org.eclipse.rdf4j.model.Literal; -import org.eclipse.rdf4j.model.Model; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.*; -import static nl.dtls.fairdatapoint.entity.metadata.MetadataSetter.*; -import static nl.dtls.fairdatapoint.util.ValueFactoryHelper.l; -import static org.junit.jupiter.api.Assertions.*; - -public class RepositoryMetadataServiceTest extends BaseIntegrationTest { - - @Autowired - private TestMetadataFixtures testMetadataFixtures; - - @Autowired - private AuthHelper authHelper; - - @Autowired - @Qualifier("genericMetadataService") - private MetadataService genericMetadataService; - - @Autowired - private ResourceDefinitionFixtures resourceDefinitionFixtures; - - private ResourceDefinition repositoryRd; - - @BeforeEach - public void before() { - authHelper.authenticateAsAlbert(); - repositoryRd = resourceDefinitionFixtures.repositoryDefinition(); - } - - - @Test - public void storeAndRetrieve() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - assertNotNull(genericMetadataService.retrieve(getUri(repository))); - } - - @Test - public void storeWithNoTitle() { - assertThrows(Exception.class, () -> { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - setTitle(repository, getUri(repository), null); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - // Expect exception - }); - } - - @Test - public void storeWithNoID() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - setMetadataIdentifier(repository, getUri(repository), null); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - Model result = genericMetadataService.retrieve(getUri(repository)); - assertNotNull(getMetadataIdentifier(result)); - } - - @Test - public void storeWithNoLanguage() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - setLanguage(repository, getUri(repository), null); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - Model result = genericMetadataService.retrieve(getUri(repository)); - assertNotNull(getLanguage(result)); - } - - @Test - public void storeWithNoLicense() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - setLicence(repository, getUri(repository), null); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - Model result = genericMetadataService.retrieve(getUri(repository)); - assertNotNull(getLicence(result)); - } - - @Test - public void update() throws Exception { - // GIVEN: Authenticate due to perform changes - authHelper.authenticateAsAdmin(); - - // AND: Prepare data - Model repository = testMetadataFixtures.repositoryMetadata(); - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // WHEN: - Literal title = l("New FDP title"); - setTitle(repository, getUri(repository), title); - genericMetadataService.update(repository, getUri(repository), repositoryRd); - - // THEN: - Model result = genericMetadataService.retrieve(getUri(repository)); - assertEquals(title, getTitle(result)); - } - - @Test - public void nullFDPURI() { - assertThrows(NullPointerException.class, () -> { - // WHEN: - genericMetadataService.retrieve((IRI) null); - - // THEN: - // Expect exception - }); - } - - @Test - public void specsLink() throws Exception { - // GIVEN: - Model repository = testMetadataFixtures.repositoryMetadata(); - - // WHEN: - genericMetadataService.store(repository, getUri(repository), repositoryRd); - - // THEN: - Model result = genericMetadataService.retrieve(getUri(repository)); - assertNotNull(getSpecification(result)); - } - - -} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCacheTest.java b/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCacheTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d18ed54ec2d4aa76fa4a4737d2c80069a4abb768 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionCacheTest.java @@ -0,0 +1,75 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import nl.dtls.fairdatapoint.BaseIntegrationTest; +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; + +public class ResourceDefinitionCacheTest extends BaseIntegrationTest { + + @Autowired + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Autowired + private ResourceDefinitionCache resourceDefinitionCache; + + @Autowired + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + + @Test + public void computeCacheWorks() { + // GIVEN: Resource definitions + ResourceDefinition rdRepository = resourceDefinitionFixtures.repositoryDefinition(); + ResourceDefinition rdCatalog = resourceDefinitionFixtures.catalogDefinition(); + ResourceDefinition rdDataset = resourceDefinitionFixtures.datasetDefinition(); + ResourceDefinition rdDistribution = resourceDefinitionFixtures.distributionDefinition(); + + // WHEN: + resourceDefinitionCache.computeCache(); + + // THEN: caches by UUID + assertThat(resourceDefinitionCache.getByUuid(rdRepository.getUuid()).getName(), is(equalTo(rdRepository.getName()))); + assertThat(resourceDefinitionCache.getByUuid(rdCatalog.getUuid()).getName(), is(equalTo(rdCatalog.getName()))); + assertThat(resourceDefinitionCache.getByUuid(rdDataset.getUuid()).getName(), is(equalTo(rdDataset.getName()))); + assertThat(resourceDefinitionCache.getByUuid(rdDistribution.getUuid()).getName(), is(equalTo(rdDistribution.getName()))); + + // AND: caches parents + assertThat(resourceDefinitionCache.getParentsByUuid(rdRepository.getUuid()).isEmpty(), is(true)); + assertThat(resourceDefinitionCache.getParentsByUuid(rdCatalog.getUuid()).size(), is(equalTo(1))); + assertThat(resourceDefinitionCache.getParentsByUuid(rdCatalog.getUuid()).stream().toList().get(0).getUuid(), is(equalTo(rdRepository.getUuid()))); + assertThat(resourceDefinitionCache.getParentsByUuid(rdDataset.getUuid()).size(), is(equalTo(1))); + assertThat(resourceDefinitionCache.getParentsByUuid(rdDataset.getUuid()).stream().toList().get(0).getUuid(), is(equalTo(rdCatalog.getUuid()))); + assertThat(resourceDefinitionCache.getParentsByUuid(rdDistribution.getUuid()).size(), is(equalTo(1))); + assertThat(resourceDefinitionCache.getParentsByUuid(rdDistribution.getUuid()).stream().toList().get(0).getUuid(), is(equalTo(rdDataset.getUuid()))); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidatorTest.java b/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidatorTest.java new file mode 100644 index 0000000000000000000000000000000000000000..06af988c854a0e8394602486eed79a288dab866d --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/service/resource/ResourceDefinitionValidatorTest.java @@ -0,0 +1,193 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.service.resource; + +import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; +import nl.dtls.fairdatapoint.database.mongo.repository.ResourceDefinitionRepository; +import nl.dtls.fairdatapoint.entity.exception.ValidationException; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; +import nl.dtls.fairdatapoint.entity.resource.ResourceDefinitionChild; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.validation.BindException; + +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.hamcrest.core.IsNull.notNullValue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class ResourceDefinitionValidatorTest { + + @Mock + private ResourceDefinitionRepository resourceDefinitionRepository; + + @Mock + private ResourceDefinitionCache resourceDefinitionCache; + + @InjectMocks + private ResourceDefinitionValidator resourceDefinitionValidator; + + @InjectMocks + private ResourceDefinitionFixtures resourceDefinitionFixtures; + + @Test + public void nameUniqueness() throws BindException { + // GIVEN: Prepare reqDto + ResourceDefinition reqDto = resourceDefinitionFixtures.repositoryDefinition(); + reqDto.setChildren(List.of()); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.of(resourceDefinitionFixtures.repositoryDefinition())); + + // WHEN: + resourceDefinitionValidator.validate(reqDto); + + // THEN: + // Nothing to check + } + + @Test + public void nameUniquenessBreach() { + // GIVEN: Prepare reqDto + ResourceDefinition reqDto = resourceDefinitionFixtures.ontologyDefinition(); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.of(resourceDefinitionFixtures.repositoryDefinition())); + + // WHEN: + BindException exception = assertThrows( + BindException.class, + () -> resourceDefinitionValidator.validate(reqDto) + ); + + // THEN: + assertThat(exception.getBindingResult().getFieldError("name"), is(notNullValue())); + } + + @Test + public void urlPrefixUniqueness() throws BindException { + // GIVEN: Prepare reqDto + ResourceDefinition reqDto = resourceDefinitionFixtures.repositoryDefinition(); + reqDto.setChildren(List.of()); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.empty()); + when(resourceDefinitionRepository.findByUrlPrefix(reqDto.getUrlPrefix())) + .thenReturn(Optional.of(resourceDefinitionFixtures.repositoryDefinition())); + + // WHEN: + resourceDefinitionValidator.validate(reqDto); + + // THEN: + // Nothing to check + } + + @Test + public void urlPrefixUniquenessBreach() { + // GIVEN: Prepare reqDto + ResourceDefinition reqDto = resourceDefinitionFixtures.ontologyDefinition(); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.empty()); + when(resourceDefinitionRepository.findByUrlPrefix(reqDto.getUrlPrefix())) + .thenReturn(Optional.of(resourceDefinitionFixtures.repositoryDefinition())); + + // WHEN: + BindException exception = assertThrows( + BindException.class, + () -> resourceDefinitionValidator.validate(reqDto) + ); + + // THEN: + assertThat(exception.getBindingResult().getFieldError("urlPrefix"), is(notNullValue())); + } + + @Test + public void nonExistingChild() { + // GIVEN: Prepare reqDto + ResourceDefinition reqDto = resourceDefinitionFixtures.ontologyDefinition(); + ResourceDefinitionChild child = new ResourceDefinitionChild("nonExistingChild", "", null); + reqDto.setChildren(List.of(child)); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.empty()); + when(resourceDefinitionRepository.findByUrlPrefix(reqDto.getUrlPrefix())) + .thenReturn(Optional.empty()); + when(resourceDefinitionCache.getByUuid(child.getResourceDefinitionUuid())) + .thenReturn(null); + + // WHEN: + ValidationException exception = assertThrows( + ValidationException.class, + () -> resourceDefinitionValidator.validate(reqDto) + ); + + // THEN: + assertThat(exception.getMessage(), is(equalTo("Child doesn't exist"))); + } + + @Test + public void existingDependencyCycle() { + // GIVEN: Prepare reqDto and resource definitions + ResourceDefinition rdRepository = resourceDefinitionFixtures.repositoryDefinition(); + ResourceDefinition reqDto = resourceDefinitionFixtures.catalogDefinition(); + ResourceDefinition rdDataset = resourceDefinitionFixtures.datasetDefinition(); + + ResourceDefinitionChild rdDatasetChild = new ResourceDefinitionChild(rdRepository.getUuid(), "", null); + rdDataset.setChildren(List.of(rdDatasetChild)); + + // AND: Prepare database + when(resourceDefinitionRepository.findByName(reqDto.getName())) + .thenReturn(Optional.empty()); + when(resourceDefinitionRepository.findByUrlPrefix(reqDto.getUrlPrefix())) + .thenReturn(Optional.empty()); + when(resourceDefinitionCache.getByUuid(rdRepository.getUuid())) + .thenReturn(rdRepository); + when(resourceDefinitionCache.getByUuid(rdDataset.getUuid())) + .thenReturn(rdDataset); + + // WHEN: + ValidationException exception = assertThrows( + ValidationException.class, + () -> resourceDefinitionValidator.validate(reqDto) + ); + + // THEN: + assertThat(exception.getMessage(), is(equalTo("Detect dependency cycle through child"))); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/utils/CustomPageImpl.java b/src/test/java/nl/dtls/fairdatapoint/utils/CustomPageImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9f525e9439ff964d381d816eef04c01209b1a49b --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/utils/CustomPageImpl.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.utils; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class CustomPageImpl<T> { + + private int totalPages; + private long totalElements; + private boolean first; + private CustomSort sort; + private CustomPageable pageable; + private int number; + private int numberOfElements; + private boolean last; + private int size; + private List<T> content; + private boolean empty; + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class CustomPageable { + private int page; + private int size; + private CustomSort sort; + } + + @Data + @JsonIgnoreProperties(ignoreUnknown = true) + public static class CustomSort { + private boolean sorted; + private boolean unsorted; + private boolean empty; + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/utils/HttpUtilTest.java b/src/test/java/nl/dtls/fairdatapoint/utils/HttpUtilTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b53ed04845147a1ec1970a120f68159310638c2b --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/utils/HttpUtilTest.java @@ -0,0 +1,98 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.utils; + +import org.eclipse.rdf4j.model.IRI; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import javax.servlet.http.HttpServletRequest; + +import static nl.dtls.fairdatapoint.util.HttpUtil.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class HttpUtilTest { + + @ParameterizedTest + @CsvSource({ + "http://fairdatapoint.com/,http://purl.org/fairdatapoint/test", + "http://fairdatapoint.com/catalog/catalog-1,http://purl.org/fairdatapoint/test/catalog/catalog-1", + "https://fairdatapoint.com/catalog/catalog-1/,http://purl.org/fairdatapoint/test/catalog/catalog-1", + }) + public void getRequestURLTest(String url, String expected) { + // GIVEN: Prepare request + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRequestURL()).thenReturn(new StringBuffer(url)); + String persistentUrl = "http://purl.org/fairdatapoint/test"; + + // WHEN: + String result = getRequestURL(request, persistentUrl); + + // THEN: + assertThat(result, is(equalTo(expected))); + } + + @Test + public void generateNewIRITest() { + // GIVEN: Prepare request + String url = "http://fairdatapoint.com/"; + HttpServletRequest request = mock(HttpServletRequest.class); + when(request.getRequestURL()).thenReturn(new StringBuffer(url)); + String persistentUrl = "http://purl.org/fairdatapoint/test"; + + // WHEN: + IRI result = generateNewIRI(request, persistentUrl); + + // THEN: + assertThat(result.stringValue().length(), is(equalTo(71))); + assertThat(result.stringValue().startsWith(persistentUrl), is(equalTo(true))); + } + + @ParameterizedTest + @CsvSource({ + "http://example.com/,http://example.com", + "http://example.com,http://example.com", + "example.com/,example.com", + "example.com/foo,example.com/foo", + "example.com/foo/,example.com/foo", + }) + public void removeLastSlashTest(String url, String expected) { + assertThat(removeLastSlash(url), is(equalTo(expected))); + } + + @ParameterizedTest + @CsvSource({ + "http://example.com,example.com", + "https://example.com,example.com", + "example.com,example.com", + }) + public void removeProtocolTest(String url, String expected) { + assertThat(removeProtocol(url), is(equalTo(expected))); + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/utils/TestIndexEntryFixtures.java b/src/test/java/nl/dtls/fairdatapoint/utils/TestIndexEntryFixtures.java new file mode 100644 index 0000000000000000000000000000000000000000..3216d75a00076835aed98a658c67796ca50ddbb6 --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/utils/TestIndexEntryFixtures.java @@ -0,0 +1,70 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.utils; + +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntry; +import nl.dtls.fairdatapoint.entity.index.entry.IndexEntryState; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class TestIndexEntryFixtures { + + private static IndexEntry newIndexEntry(String uuid, String clientUrl, Instant timestamp) { + IndexEntry indexEntry = new IndexEntry(); + indexEntry.setUuid(uuid); + indexEntry.setClientUrl(clientUrl); + indexEntry.setModificationTime(timestamp); + indexEntry.setRegistrationTime(timestamp); + indexEntry.setState(IndexEntryState.Invalid); + return indexEntry; + } + + public static IndexEntry entryExample() { + return newIndexEntry("7663c0c2-2b9d-4787-968d-d284ff3fc5bd", "http://example.com", Instant.now()); + } + + public static List<IndexEntry> entriesFew() { + Instant ref = Instant.now(); + return Arrays.asList( + newIndexEntry("09200532-18b4-4721-86dd-fbfa13ec78c3", "http://example.com", ref), + newIndexEntry("b6cfa934-dc67-4b88-b8f9-c63448c8272c", "http://test.com", ref.minusSeconds(1)), + newIndexEntry("da9ddfb8-6fdb-41b1-889e-387c8cbafc39", "http://localhost", ref.minusSeconds(2)) + ); + } + + public static List<IndexEntry> entriesN(long n) { + ArrayList<IndexEntry> entries = new ArrayList<>(); + Instant ref = Instant.now(); + for (int i = 0; i < n; i++) { + Instant entryTime = ref.minusSeconds(i); + entries.add(newIndexEntry(UUID.randomUUID().toString(), "http://example" + i + ".com", + entryTime)); + } + return entries; + } + +} diff --git a/src/test/java/nl/dtls/fairdatapoint/utils/TestMetadataFixtures.java b/src/test/java/nl/dtls/fairdatapoint/utils/TestRdfMetadataFixtures.java old mode 100755 new mode 100644 similarity index 85% rename from src/test/java/nl/dtls/fairdatapoint/utils/TestMetadataFixtures.java rename to src/test/java/nl/dtls/fairdatapoint/utils/TestRdfMetadataFixtures.java index f8abaeb5d2cd2f7bd82566f791c5c4633ef86382..424a63265dcf02b30f1133bca23a8f5138c5e6ef --- a/src/test/java/nl/dtls/fairdatapoint/utils/TestMetadataFixtures.java +++ b/src/test/java/nl/dtls/fairdatapoint/utils/TestRdfMetadataFixtures.java @@ -23,7 +23,8 @@ package nl.dtls.fairdatapoint.utils; import nl.dtls.fairdatapoint.database.mongo.migration.development.resource.data.ResourceDefinitionFixtures; -import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.data.MetadataFixtures; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.data.RdfMetadataFixtures; +import nl.dtls.fairdatapoint.database.rdf.migration.development.metadata.factory.MetadataFactory; import nl.dtls.fairdatapoint.entity.resource.ResourceDefinition; import nl.dtls.fairdatapoint.service.metadata.enhance.MetadataEnhancer; import org.eclipse.rdf4j.model.Model; @@ -34,19 +35,26 @@ import org.springframework.stereotype.Service; import static nl.dtls.fairdatapoint.entity.metadata.MetadataGetter.getUri; @Service -public class TestMetadataFixtures extends MetadataFixtures { - - @Autowired - @Qualifier("persistentUrl") - private String persistentUrl; +public class TestRdfMetadataFixtures extends RdfMetadataFixtures { public String alternativePersistentUrl = "https://lorentz.fair-dtls.surf-hosted.nl/fdp"; - @Autowired - private MetadataEnhancer metadataEnhancer; + private final String persistentUrl; + + private final MetadataEnhancer metadataEnhancer; + + private final ResourceDefinitionFixtures resourceDefinitionFixtures; @Autowired - private ResourceDefinitionFixtures resourceDefinitionFixtures; + public TestRdfMetadataFixtures(MetadataFactory metadataFactory, + @Qualifier("persistentUrl") String persistentUrl, + MetadataEnhancer metadataEnhancer, + ResourceDefinitionFixtures resourceDefinitionFixtures) { + super(metadataFactory); + this.persistentUrl = persistentUrl; + this.metadataEnhancer = metadataEnhancer; + this.resourceDefinitionFixtures = resourceDefinitionFixtures; + } public Model repositoryMetadata() { Model metadata = super.repositoryMetadata(persistentUrl); diff --git a/version b/version index ec429617da2180a51560c0b53f351b9d969eb6ed..50aa215e614b2585a5a7332b0fff427b7a80b520 100644 --- a/version +++ b/version @@ -1 +1 @@ -v27 \ No newline at end of file +v28 \ No newline at end of file