From 2bf3b0dfac704a765be82e87ea353c027cc6ea4a Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 08:57:14 +0100 Subject: [PATCH 01/22] Project skeleton. --- .travis.yml | 10 +++ README.md | 6 ++ pom.xml | 79 +++++++++++++++++++ .../index/app/MetadataIndexApplication.java | 33 ++++++++ 4 files changed, 128 insertions(+) create mode 100644 .travis.yml create mode 100644 pom.xml create mode 100644 src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fe57773 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: java +jdk: + - openjdk11 + - openjdk12 + - openjdk13 +script: + - mvn -B -ff tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify +cache: + - directories: + - $HOME/.m2 diff --git a/README.md b/README.md index 1a703a7..53ef4bc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,8 @@ # fair-metadata-index Index of FAIR Data Points. + +# Introduction +The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. + +# License +This project is licensed under the [MIT License](LICENSE). diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..af55a5b --- /dev/null +++ b/pom.xml @@ -0,0 +1,79 @@ + + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.5.RELEASE + + + + solutions.fairdata + fair-metadata-index + 0.1.0-SNAPSHOT + + 2020 + + + + 11 + 3.0 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + com.mycila + license-maven-plugin + ${license-plugin.version} + +
com/mycila/maven/plugin/license/templates/MIT.txt
+ + https://fairdata.solutions + + + **/pom.xml + **/*.java + +
+
+
+
+
diff --git a/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java b/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java new file mode 100644 index 0000000..59c41df --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java @@ -0,0 +1,33 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.app; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MetadataIndexApplication { + public static void main(String[] args) { + SpringApplication.run(MetadataIndexApplication.class, args); + } +} From 70d0f0b3f102fd87221b8713a720810dfc919eec Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 09:35:23 +0100 Subject: [PATCH 02/22] Endpoint skeleton. --- README.md | 2 + .../index/app/MetadataIndexApplication.java | 3 ++ .../metadata/index/web/WebConfig.java | 32 +++++++++++++++ .../index/web/controller/PingController.java | 41 +++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java diff --git a/README.md b/README.md index 53ef4bc..ea001f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # fair-metadata-index Index of FAIR Data Points. +[![Build Status](https://travis-ci.com/FAIRDataTeam/fair-metadata-index.svg?branch=develop)](https://travis-ci.com/FAIRDataTeam/fair-metadata-index) + # Introduction The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. diff --git a/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java b/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java index 59c41df..5a05b92 100644 --- a/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java +++ b/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java @@ -24,8 +24,11 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Import; +import solutions.fairdata.metadata.index.web.WebConfig; @SpringBootApplication +@Import(WebConfig.class) public class MetadataIndexApplication { public static void main(String[] args) { SpringApplication.run(MetadataIndexApplication.class, args); diff --git a/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java b/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java new file mode 100644 index 0000000..6cdb710 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java @@ -0,0 +1,32 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.web; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +@ComponentScan +public class WebConfig implements WebMvcConfigurer { +} diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java new file mode 100644 index 0000000..46e8f12 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java @@ -0,0 +1,41 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.web.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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("/ping") +public class PingController { + private static final Logger logger = LoggerFactory.getLogger(PingController.class); + + @GetMapping + public void receivePing(@RequestParam String endpoint) { + logger.info("Received ping from {}", endpoint); + } +} From d9dba0e73ac5bd0a1bec61d7b9327bc0598b48c0 Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 11:09:04 +0100 Subject: [PATCH 03/22] Rough outline of service and storage layers. --- pom.xml | 8 +++ .../metadata/index/domain/IndexEntry.java | 34 ++++++++++++ .../metadata/index/service/IndexService.java | 53 +++++++++++++++++++ .../metadata/index/service/ServiceConfig.java | 34 ++++++++++++ .../index/storage/EntryRepository.java | 29 ++++++++++ .../metadata/index/storage/StorageConfig.java | 46 ++++++++++++++++ .../metadata/index/web/WebConfig.java | 3 ++ .../index/web/controller/PingController.java | 7 +++ 8 files changed, 214 insertions(+) create mode 100644 src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/service/IndexService.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java diff --git a/pom.xml b/pom.xml index af55a5b..f5355fb 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,14 @@ org.springframework.boot spring-boot-starter-web + + org.springframework.boot + spring-boot-starter-data-redis + + + org.projectlombok + lombok + diff --git a/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java b/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java new file mode 100644 index 0000000..71670cb --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.domain; + +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; +import lombok.Data; + +@RedisHash("entries") +@Data +public class IndexEntry { + @Id private String endpoint; + private String timestamp; +} diff --git a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java new file mode 100644 index 0000000..7479315 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java @@ -0,0 +1,53 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.service; + +import java.time.OffsetDateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import solutions.fairdata.metadata.index.domain.IndexEntry; +import solutions.fairdata.metadata.index.storage.EntryRepository; + +@Component +public class IndexService { + private static final Logger logger = LoggerFactory.getLogger(IndexService.class); + + @Autowired + private EntryRepository repository; + + public void storeEntry(String endpoint) { + var entry = new IndexEntry(); + entry.setEndpoint(endpoint); + entry.setTimestamp(OffsetDateTime.now().toString()); + + if (repository.existsById(endpoint)) { + logger.info("Updating timestamp of existing entry {}", entry.getEndpoint()); + } else { + logger.info("Storing new entry {}", entry.getEndpoint()); + } + + repository.save(entry); + } +} diff --git a/src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java b/src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java new file mode 100644 index 0000000..5ef8755 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.service; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import solutions.fairdata.metadata.index.storage.StorageConfig; + +@Configuration +@ComponentScan +@Import(StorageConfig.class) +public class ServiceConfig { +} diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java b/src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java new file mode 100644 index 0000000..0ea6f31 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java @@ -0,0 +1,29 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.storage; + +import org.springframework.data.repository.CrudRepository; +import solutions.fairdata.metadata.index.domain.IndexEntry; + +public interface EntryRepository extends CrudRepository { +} diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java b/src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java new file mode 100644 index 0000000..5c25a63 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java @@ -0,0 +1,46 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.storage; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; + +@Configuration +@EnableRedisRepositories +public class StorageConfig { + @Bean + public RedisConnectionFactory connectionFactory() { + return new LettuceConnectionFactory(); + } + + @Bean + public RedisTemplate redisTemplate() { + var template = new RedisTemplate(); + template.setConnectionFactory(connectionFactory()); + return template; + } +} diff --git a/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java b/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java index 6cdb710..81cef3e 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java @@ -24,9 +24,12 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import solutions.fairdata.metadata.index.service.ServiceConfig; @Configuration @ComponentScan +@Import(ServiceConfig.class) public class WebConfig implements WebMvcConfigurer { } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java index 46e8f12..f35a418 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java @@ -24,18 +24,25 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; 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; +import solutions.fairdata.metadata.index.service.IndexService; @RestController @RequestMapping("/ping") public class PingController { private static final Logger logger = LoggerFactory.getLogger(PingController.class); + @Autowired + private IndexService service; + @GetMapping public void receivePing(@RequestParam String endpoint) { logger.info("Received ping from {}", endpoint); + + service.storeEntry(endpoint); } } From 90b0178d08ceb1cd902bfcd69282eef969bc5ab0 Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 11:16:23 +0100 Subject: [PATCH 04/22] Dummy html output. --- pom.xml | 4 ++++ .../metadata/index/service/IndexService.java | 4 ++++ .../index/web/controller/HomeController.java | 21 ++++++++++++++++++ src/main/resources/templates/home.html | 22 +++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java create mode 100644 src/main/resources/templates/home.html diff --git a/pom.xml b/pom.xml index f5355fb..1d8c2aa 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,10 @@ org.springframework.boot spring-boot-starter-data-redis + + org.springframework.boot + spring-boot-starter-thymeleaf + org.projectlombok lombok diff --git a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java index 7479315..6db4ada 100644 --- a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java @@ -50,4 +50,8 @@ public void storeEntry(String endpoint) { repository.save(entry); } + + public Iterable getAllEntries() { + return repository.findAll(); + } } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java new file mode 100644 index 0000000..e846aa9 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java @@ -0,0 +1,21 @@ +package solutions.fairdata.metadata.index.web.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import solutions.fairdata.metadata.index.service.IndexService; + +@Controller +@RequestMapping("/") +public class HomeController { + @Autowired + private IndexService service; + + @GetMapping + public String home(Model model) { + model.addAttribute("entries", service.getAllEntries()); + return "home"; + } +} diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html new file mode 100644 index 0000000..3a394ed --- /dev/null +++ b/src/main/resources/templates/home.html @@ -0,0 +1,22 @@ + + + + FAIR Data Point index + + + + + + + + + + + + + + + +
EndpointTimestamp
+ + From ce5ef08d6a982131466164909f4529f806bfc43a Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 11:17:22 +0100 Subject: [PATCH 05/22] Added missing license header. --- .../index/web/controller/HomeController.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java index e846aa9..2ba8789 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java @@ -1,3 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.web.controller; import org.springframework.beans.factory.annotation.Autowired; From 5a37464f16fe4ec611b3850f84ece0946d499b3e Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 11:23:28 +0100 Subject: [PATCH 06/22] docker-compose stub for redis. --- docker-compose.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7fc54ec --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +version: "3.7" +services: + redis: + image: redis + container_name: redis + ports: + - "127.0.0.1:6379:6379" + volumes: + - ./redis-data:/data From 448eb200b84676f67a949cdd19d22deae7220bd9 Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 9 Mar 2020 11:34:06 +0100 Subject: [PATCH 07/22] Updated readme with small quickstart section. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index ea001f0..863371a 100644 --- a/README.md +++ b/README.md @@ -6,5 +6,11 @@ Index of FAIR Data Points. # Introduction The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. +# Quickstart +- start redis by running `docker-compose up -d` +- start the app by running `mvn spring-boot:run` +- post something using `curl http://localhost:8080/ping?endpoint=http://example.com` +- see the results in your browser at `http://localhost:8080/` + # License This project is licensed under the [MIT License](LICENSE). From ed2fc39acd678dcd7e53aa4e9cd2d1961c6233f8 Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 27 Apr 2020 16:03:48 +0200 Subject: [PATCH 08/22] Changed docker-compose build, domain entity for capturing more metadata. --- .dockerignore | 2 ++ Dockerfile | 7 ++++ docker-compose.yml | 14 +++++--- pom.xml | 7 ++++ .../metadata/index/app/package-info.java | 25 ++++++++++++++ .../metadata/index/domain/package-info.java | 25 ++++++++++++++ .../metadata/index/service/package-info.java | 25 ++++++++++++++ .../metadata/index/storage/package-info.java | 25 ++++++++++++++ .../index/web/controller/PingController.java | 17 ++++++---- .../index/web/controller/package-info.java | 25 ++++++++++++++ .../metadata/index/web/dto/PingDto.java | 34 +++++++++++++++++++ .../metadata/index/web/dto/package-info.java | 25 ++++++++++++++ .../metadata/index/web/package-info.java | 25 ++++++++++++++ 13 files changed, 246 insertions(+), 10 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 src/main/java/solutions/fairdata/metadata/index/app/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/domain/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/service/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/storage/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java create mode 100644 src/main/java/solutions/fairdata/metadata/index/web/package-info.java diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..251a318 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +** +!target/*.jar diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..743a147 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,7 @@ +FROM openjdk:11-jdk-slim + +WORKDIR /app + +ADD target/fair-metadata-index-0.1.0-SNAPSHOT.jar /app/app.jar + +ENTRYPOINT java -jar app.jar diff --git a/docker-compose.yml b/docker-compose.yml index 7fc54ec..83f52f9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,15 @@ version: "3.7" services: + index: + build: . + ports: + - "127.0.0.1:8080:8080" + redis: image: redis container_name: redis - ports: - - "127.0.0.1:6379:6379" - volumes: - - ./redis-data:/data + network_mode: service:index +# ports: +# - "127.0.0.1:6379:6379" +# volumes: +# - ./redis-data:/data diff --git a/pom.xml b/pom.xml index 1d8c2aa..2ed07c8 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ 11 3.0 + 4.0.0 @@ -63,6 +64,12 @@ org.projectlombok lombok
+ + + com.github.spotbugs + spotbugs-annotations + ${spotbugs.version} + diff --git a/src/main/java/solutions/fairdata/metadata/index/app/package-info.java b/src/main/java/solutions/fairdata/metadata/index/app/package-info.java new file mode 100644 index 0000000..d91f605 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/app/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.app; diff --git a/src/main/java/solutions/fairdata/metadata/index/domain/package-info.java b/src/main/java/solutions/fairdata/metadata/index/domain/package-info.java new file mode 100644 index 0000000..6878f93 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/domain/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.domain; diff --git a/src/main/java/solutions/fairdata/metadata/index/service/package-info.java b/src/main/java/solutions/fairdata/metadata/index/service/package-info.java new file mode 100644 index 0000000..79cb399 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/service/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.service; diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/package-info.java b/src/main/java/solutions/fairdata/metadata/index/storage/package-info.java new file mode 100644 index 0000000..6897bd9 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/storage/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.storage; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java index f35a418..4c82ddd 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java @@ -22,14 +22,18 @@ */ package solutions.fairdata.metadata.index.web.controller; +import javax.validation.Valid; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.http.HttpStatus; +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.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import solutions.fairdata.metadata.index.service.IndexService; +import solutions.fairdata.metadata.index.web.dto.PingDto; @RestController @RequestMapping("/ping") @@ -39,10 +43,11 @@ public class PingController { @Autowired private IndexService service; - @GetMapping - public void receivePing(@RequestParam String endpoint) { - logger.info("Received ping from {}", endpoint); + @PostMapping + @ResponseStatus(HttpStatus.NO_CONTENT) + public void receivePing(@RequestBody @Valid PingDto ping) { + logger.info("Received ping from {}", ping); - service.storeEntry(endpoint); + service.storeEntry(ping.getEndpoint()); } } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java new file mode 100644 index 0000000..723a8df --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.web.controller; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java b/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java new file mode 100644 index 0000000..5a645ce --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.metadata.index.web.dto; + +import javax.validation.constraints.NotNull; +import org.hibernate.validator.constraints.URL; +import lombok.Data; + +@Data +public class PingDto { + @NotNull + @URL + private String endpoint; +} diff --git a/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java b/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java new file mode 100644 index 0000000..b449418 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.web.dto; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/package-info.java b/src/main/java/solutions/fairdata/metadata/index/web/package-info.java new file mode 100644 index 0000000..2e7c5d8 --- /dev/null +++ b/src/main/java/solutions/fairdata/metadata/index/web/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.metadata.index.web; From eba42b392b685acd2dfc0d125aca5a5d49a6603f Mon Sep 17 00:00:00 2001 From: kburger Date: Mon, 27 Apr 2020 21:40:53 +0200 Subject: [PATCH 09/22] Listen for POST on root, renamed endpoint to clientUrl, and added the last modification date property. --- .../metadata/index/domain/IndexEntry.java | 5 +++-- .../metadata/index/service/IndexService.java | 19 ++++++++++++------- .../index/web/controller/PingController.java | 4 ++-- .../metadata/index/web/dto/PingDto.java | 2 +- src/main/resources/templates/home.html | 8 +++++--- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java b/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java index 71670cb..8057393 100644 --- a/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java +++ b/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java @@ -29,6 +29,7 @@ @RedisHash("entries") @Data public class IndexEntry { - @Id private String endpoint; - private String timestamp; + @Id private String clientUrl; + private String registrationTime; + private String modificationTime; } diff --git a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java index 6db4ada..bf3a42b 100644 --- a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java @@ -37,17 +37,22 @@ public class IndexService { @Autowired private EntryRepository repository; - public void storeEntry(String endpoint) { - var entry = new IndexEntry(); - entry.setEndpoint(endpoint); - entry.setTimestamp(OffsetDateTime.now().toString()); + public void storeEntry(String clientUrl) { + var entity = repository.findById(clientUrl); + var now = OffsetDateTime.now(); - if (repository.existsById(endpoint)) { - logger.info("Updating timestamp of existing entry {}", entry.getEndpoint()); + final IndexEntry entry; + if (entity.isPresent()) { + logger.info("Updating timestamp of existing entry {}", clientUrl); + entry = entity.orElseThrow(); } else { - logger.info("Storing new entry {}", entry.getEndpoint()); + logger.info("Storing new entry {}", clientUrl); + entry = new IndexEntry(); + entry.setClientUrl(clientUrl); + entry.setRegistrationTime(now.toString()); } + entry.setModificationTime(now.toString()); repository.save(entry); } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java index 4c82ddd..3a55ab5 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java @@ -36,7 +36,7 @@ import solutions.fairdata.metadata.index.web.dto.PingDto; @RestController -@RequestMapping("/ping") +@RequestMapping("/") public class PingController { private static final Logger logger = LoggerFactory.getLogger(PingController.class); @@ -48,6 +48,6 @@ public class PingController { public void receivePing(@RequestBody @Valid PingDto ping) { logger.info("Received ping from {}", ping); - service.storeEntry(ping.getEndpoint()); + service.storeEntry(ping.getClientUrl()); } } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java b/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java index 5a645ce..5f947d5 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java +++ b/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java @@ -30,5 +30,5 @@ public class PingDto { @NotNull @URL - private String endpoint; + private String clientUrl; } diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 3a394ed..b2d567a 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -8,13 +8,15 @@ Endpoint - Timestamp + Registration + Modification - - + + + From 948939b465c1ff185cb837de3d8774f30b87c7b1 Mon Sep 17 00:00:00 2001 From: kburger Date: Tue, 28 Apr 2020 11:53:32 +0200 Subject: [PATCH 10/22] Updated readme quickstart to reflect the new changes. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 863371a..40e0fc0 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ Index of FAIR Data Points. The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. # Quickstart +- build the app by running `mvn package` - start redis by running `docker-compose up -d` -- start the app by running `mvn spring-boot:run` -- post something using `curl http://localhost:8080/ping?endpoint=http://example.com` +- post something using `curl -H "Content-Type: application/json" -d '{"clientUrl":"http://example.com/"}' http://localhost:8080/` - see the results in your browser at `http://localhost:8080/` # License From c3f55a170b2194c2a8518d3695a9e766b86dfd9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 28 Apr 2020 16:43:03 +0200 Subject: [PATCH 11/22] Rename to FAIRDataPoint-index (#1) --- Dockerfile | 2 +- README.md | 6 ++--- pom.xml | 3 ++- .../app/FairDataPointIndexApplication.java} | 8 +++--- .../web => fdp/index/app}/package-info.java | 2 +- .../index/domain/IndexEntry.java | 2 +- .../index/domain}/package-info.java | 2 +- .../index/service/IndexService.java | 6 ++--- .../index/service/ServiceConfig.java | 4 +-- .../index/service}/package-info.java | 2 +- .../index/storage/EntryRepository.java | 4 +-- .../index/storage/StorageConfig.java | 2 +- .../index/storage}/package-info.java | 2 +- .../index/web/WebConfig.java | 4 +-- .../index/web/controller/HomeController.java | 4 +-- .../index/web/controller/PingController.java | 6 ++--- .../index/web/controller}/package-info.java | 2 +- .../index/web/dto/PingDto.java | 2 +- .../fdp/index/web/dto/package-info.java | 25 +++++++++++++++++++ .../fairdata/fdp/index/web/package-info.java | 25 +++++++++++++++++++ .../index/web/controller/package-info.java | 25 ------------------- .../metadata/index/web/dto/package-info.java | 25 ------------------- 22 files changed, 82 insertions(+), 81 deletions(-) rename src/main/java/solutions/fairdata/{metadata/index/app/MetadataIndexApplication.java => fdp/index/app/FairDataPointIndexApplication.java} (87%) rename src/main/java/solutions/fairdata/{metadata/index/web => fdp/index/app}/package-info.java (96%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/domain/IndexEntry.java (96%) rename src/main/java/solutions/fairdata/{metadata/index/app => fdp/index/domain}/package-info.java (96%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/service/IndexService.java (92%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/service/ServiceConfig.java (92%) rename src/main/java/solutions/fairdata/{metadata/index/domain => fdp/index/service}/package-info.java (95%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/storage/EntryRepository.java (92%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/storage/StorageConfig.java (97%) rename src/main/java/solutions/fairdata/{metadata/index/service => fdp/index/storage}/package-info.java (95%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/web/WebConfig.java (93%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/web/controller/HomeController.java (93%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/web/controller/PingController.java (92%) rename src/main/java/solutions/fairdata/{metadata/index/storage => fdp/index/web/controller}/package-info.java (95%) rename src/main/java/solutions/fairdata/{metadata => fdp}/index/web/dto/PingDto.java (96%) create mode 100644 src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java create mode 100644 src/main/java/solutions/fairdata/fdp/index/web/package-info.java delete mode 100644 src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java delete mode 100644 src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java diff --git a/Dockerfile b/Dockerfile index 743a147..eea0489 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,6 @@ FROM openjdk:11-jdk-slim WORKDIR /app -ADD target/fair-metadata-index-0.1.0-SNAPSHOT.jar /app/app.jar +ADD target/fairdatapoint-index.jar /app/app.jar ENTRYPOINT java -jar app.jar diff --git a/README.md b/README.md index 40e0fc0..d2a589b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# fair-metadata-index -Index of FAIR Data Points. +# FAIRDataPoint-index +Index of FAIR Data Points -[![Build Status](https://travis-ci.com/FAIRDataTeam/fair-metadata-index.svg?branch=develop)](https://travis-ci.com/FAIRDataTeam/fair-metadata-index) +[![Build Status](https://travis-ci.com/FAIRDataTeam/FAIRDataPoint-index.svg?branch=develop)](https://travis-ci.com/FAIRDataTeam/FAIRDataPoint-index) # Introduction The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. diff --git a/pom.xml b/pom.xml index 2ed07c8..b5a21e2 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ solutions.fairdata - fair-metadata-index + fairdatapoint-index 0.1.0-SNAPSHOT 2020 @@ -73,6 +73,7 @@ + fairdatapoint-index org.springframework.boot diff --git a/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java b/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java similarity index 87% rename from src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java rename to src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java index 5a05b92..73363fe 100644 --- a/src/main/java/solutions/fairdata/metadata/index/app/MetadataIndexApplication.java +++ b/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java @@ -20,17 +20,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.app; +package solutions.fairdata.fdp.index.app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Import; -import solutions.fairdata.metadata.index.web.WebConfig; +import solutions.fairdata.fdp.index.web.WebConfig; @SpringBootApplication @Import(WebConfig.class) -public class MetadataIndexApplication { +public class FairDataPointIndexApplication { public static void main(String[] args) { - SpringApplication.run(MetadataIndexApplication.class, args); + SpringApplication.run(FairDataPointIndexApplication.class, args); } } diff --git a/src/main/java/solutions/fairdata/metadata/index/web/package-info.java b/src/main/java/solutions/fairdata/fdp/index/app/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/metadata/index/web/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/app/package-info.java index 2e7c5d8..7f69d59 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/app/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.web; +package solutions.fairdata.fdp.index.app; diff --git a/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java b/src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java similarity index 96% rename from src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java rename to src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java index 8057393..d963e8a 100644 --- a/src/main/java/solutions/fairdata/metadata/index/domain/IndexEntry.java +++ b/src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.domain; +package solutions.fairdata.fdp.index.domain; import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; diff --git a/src/main/java/solutions/fairdata/metadata/index/app/package-info.java b/src/main/java/solutions/fairdata/fdp/index/domain/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/metadata/index/app/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/domain/package-info.java index d91f605..5e812c8 100644 --- a/src/main/java/solutions/fairdata/metadata/index/app/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/domain/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.app; +package solutions.fairdata.fdp.index.domain; diff --git a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java similarity index 92% rename from src/main/java/solutions/fairdata/metadata/index/service/IndexService.java rename to src/main/java/solutions/fairdata/fdp/index/service/IndexService.java index bf3a42b..77089dd 100644 --- a/src/main/java/solutions/fairdata/metadata/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java @@ -20,15 +20,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.service; +package solutions.fairdata.fdp.index.service; import java.time.OffsetDateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import solutions.fairdata.metadata.index.domain.IndexEntry; -import solutions.fairdata.metadata.index.storage.EntryRepository; +import solutions.fairdata.fdp.index.domain.IndexEntry; +import solutions.fairdata.fdp.index.storage.EntryRepository; @Component public class IndexService { diff --git a/src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java b/src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java similarity index 92% rename from src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java rename to src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java index 5ef8755..5e18adf 100644 --- a/src/main/java/solutions/fairdata/metadata/index/service/ServiceConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java @@ -20,12 +20,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.service; +package solutions.fairdata.fdp.index.service; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import solutions.fairdata.metadata.index.storage.StorageConfig; +import solutions.fairdata.fdp.index.storage.StorageConfig; @Configuration @ComponentScan diff --git a/src/main/java/solutions/fairdata/metadata/index/domain/package-info.java b/src/main/java/solutions/fairdata/fdp/index/service/package-info.java similarity index 95% rename from src/main/java/solutions/fairdata/metadata/index/domain/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/service/package-info.java index 6878f93..6b5f085 100644 --- a/src/main/java/solutions/fairdata/metadata/index/domain/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.domain; +package solutions.fairdata.fdp.index.service; diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java b/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java similarity index 92% rename from src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java rename to src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java index 0ea6f31..24a2ad2 100644 --- a/src/main/java/solutions/fairdata/metadata/index/storage/EntryRepository.java +++ b/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java @@ -20,10 +20,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.storage; +package solutions.fairdata.fdp.index.storage; import org.springframework.data.repository.CrudRepository; -import solutions.fairdata.metadata.index.domain.IndexEntry; +import solutions.fairdata.fdp.index.domain.IndexEntry; public interface EntryRepository extends CrudRepository { } diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java b/src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java similarity index 97% rename from src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java rename to src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java index 5c25a63..319180f 100644 --- a/src/main/java/solutions/fairdata/metadata/index/storage/StorageConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.storage; +package solutions.fairdata.fdp.index.storage; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/solutions/fairdata/metadata/index/service/package-info.java b/src/main/java/solutions/fairdata/fdp/index/storage/package-info.java similarity index 95% rename from src/main/java/solutions/fairdata/metadata/index/service/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/storage/package-info.java index 79cb399..e91d278 100644 --- a/src/main/java/solutions/fairdata/metadata/index/service/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/storage/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.service; +package solutions.fairdata.fdp.index.storage; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java b/src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java similarity index 93% rename from src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java rename to src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java index 81cef3e..04fa990 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/WebConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java @@ -20,13 +20,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.web; +package solutions.fairdata.fdp.index.web; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import solutions.fairdata.metadata.index.service.ServiceConfig; +import solutions.fairdata.fdp.index.service.ServiceConfig; @Configuration @ComponentScan diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java similarity index 93% rename from src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java rename to src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java index 2ba8789..cf07422 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java @@ -20,14 +20,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.web.controller; +package solutions.fairdata.fdp.index.web.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import solutions.fairdata.metadata.index.service.IndexService; +import solutions.fairdata.fdp.index.service.IndexService; @Controller @RequestMapping("/") diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java similarity index 92% rename from src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java rename to src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java index 3a55ab5..5eab808 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/PingController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.web.controller; +package solutions.fairdata.fdp.index.web.controller; import javax.validation.Valid; import org.slf4j.Logger; @@ -32,8 +32,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import solutions.fairdata.metadata.index.service.IndexService; -import solutions.fairdata.metadata.index.web.dto.PingDto; +import solutions.fairdata.fdp.index.service.IndexService; +import solutions.fairdata.fdp.index.web.dto.PingDto; @RestController @RequestMapping("/") diff --git a/src/main/java/solutions/fairdata/metadata/index/storage/package-info.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/package-info.java similarity index 95% rename from src/main/java/solutions/fairdata/metadata/index/storage/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/web/controller/package-info.java index 6897bd9..d34fa80 100644 --- a/src/main/java/solutions/fairdata/metadata/index/storage/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.storage; +package solutions.fairdata.fdp.index.web.controller; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java b/src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java similarity index 96% rename from src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java rename to src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java index 5f947d5..b96adac 100644 --- a/src/main/java/solutions/fairdata/metadata/index/web/dto/PingDto.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.metadata.index.web.dto; +package solutions.fairdata.fdp.index.web.dto; import javax.validation.constraints.NotNull; import org.hibernate.validator.constraints.URL; diff --git a/src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java b/src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java new file mode 100644 index 0000000..3780ee4 --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.fdp.index.web.dto; diff --git a/src/main/java/solutions/fairdata/fdp/index/web/package-info.java b/src/main/java/solutions/fairdata/fdp/index/web/package-info.java new file mode 100644 index 0000000..9ffa071 --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/web/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.fdp.index.web; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java b/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java deleted file mode 100644 index 723a8df..0000000 --- a/src/main/java/solutions/fairdata/metadata/index/web/controller/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * The MIT License - * Copyright © 2020 https://fairdata.solutions - * - * 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. - */ - -@javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.web.controller; diff --git a/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java b/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java deleted file mode 100644 index b449418..0000000 --- a/src/main/java/solutions/fairdata/metadata/index/web/dto/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * The MIT License - * Copyright © 2020 https://fairdata.solutions - * - * 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. - */ - -@javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.metadata.index.web.dto; From 52833511255ff2a75238ce1eba14ba06f00c94b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Wed, 29 Apr 2020 11:04:35 +0200 Subject: [PATCH 12/22] Switch to GitHub Actions --- .github/workflows/main.yml | 124 +++++++++++++++++++++++++++++++++++++ .travis.yml | 10 --- README.md | 3 +- 3 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..c9b6650 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,124 @@ +name: FAIRDataPoint-index CI + +on: + push: + pull_request: + +jobs: + btp: + name: Build-Tag-Push + runs-on: ubuntu-latest + + env: + PUBLIC_IMAGE: fairdata/fairdatapoint-index + PRIVATE_IMAGE: ${{ secrets.PRIVATE_REGISTRY_URL }}/fairdatapoint-index + TAG_DEVELOP: develop + TAG_LATEST: latest + JDK_VERSION: 11 + JDK_FILE: openjdk-11.0.2_linux-x64_bin.tar.gz + JDK_URL: https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz + + steps: + - uses: actions/checkout@v2 + + - name: Prepare JDK folder + run: mkdir -p ~/jdk + + # (1) -> Prepare cache and Java + - name: Cache ~/.m2 + uses: actions/cache@v1 + with: + path: ~/.m2 + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + + - name: Cache JDK folder + uses: actions/cache@v1 + with: + path: ~/jdk + key: ${{ env.JDK_FILE }} + + # (2) -> Prepare Java + - name: Download Oracle JDK + run: | + if [ ! -f ~/jdk/$JDK_FILE ]; then + wget --quiet $JDK_URL -O ~/jdk/$JDK_FILE + fi + cp ~/jdk/$JDK_FILE . + + - name: Setup Java + uses: actions/setup-java@master + with: + version: ${{ env.JDK_VERSION }} + jdkFile: ${{ env.JDK_FILE }} + + - name: Verify Maven and Java + run: | + mvn --version + + # (3) -> Test and build + - name: Build package and verify + run: | + mvn --quiet -B -U --fail-fast -DskipTests tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify + + # (4) -> Build Docker image + - name: Docker build + run: | + docker build -t $PRIVATE_IMAGE:$GITHUB_SHA . + + # (5) -> Docker image tagging + - name: Docker login + if: github.event_name == 'push' + run: | + docker login -u "$DOCKER_HUB_USERNAME" -p "$DOCKER_HUB_PASSWORD" + docker login -u "$PRIVATE_REGISTRY_USERNAME" -p "$PRIVATE_REGISTRY_PASSWORD" "$PRIVATE_REGISTRY_URL" + env: + DOCKER_HUB_USERNAME: ${{ secrets.DOCKER_HUB_USERNAME }} + DOCKER_HUB_PASSWORD: ${{ secrets.DOCKER_HUB_PASSWORD }} + PRIVATE_REGISTRY_URL: ${{ secrets.PRIVATE_REGISTRY_URL }} + PRIVATE_REGISTRY_USERNAME: ${{ secrets.PRIVATE_REGISTRY_USERNAME }} + PRIVATE_REGISTRY_PASSWORD: ${{ secrets.PRIVATE_REGISTRY_PASSWORD }} + + - name: Docker push - commit SHA (private) + if: github.event_name == 'push' && !startsWith(github.ref, 'refs/tags/') + run: | + docker push $PRIVATE_IMAGE:$GITHUB_SHA + + - name: Docker tag and push - branch (private) + if: github.event_name == 'push' && startsWith(github.ref, 'refs/heads/') && !contains(github.ref, 'release') + run: | + GITHUB_BRANCH=`echo $GITHUB_REF | cut -d/ -f3- | sed 's#/#-#g'` + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PRIVATE_IMAGE:$GITHUB_BRANCH + docker push $PRIVATE_IMAGE:$GITHUB_BRANCH + + - name: Docker tag and push - develop (public) + if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + run: | + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_DEVELOP + docker push $PUBLIC_IMAGE:$TAG_DEVELOP + + - name: Docker tag and push - latest (public) + if: github.event_name == 'push' && github.ref == 'refs/heads/master' + run: | + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $PUBLIC_IMAGE:$TAG_LATEST + docker push $PUBLIC_IMAGE:$TAG_LATEST + + - name: Docker tag and push - version tag (public) + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + run: | + GITHUB_TAG=`echo $GITHUB_REF | cut -d/ -f3` + # Release vX.Y.Z + if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + IMAGE_TAG_MAJOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*\..*/\1/g"` + IMAGE_TAG_MINOR="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v(.*)\..*/\1/g"` + IMAGE_TAG_PATCH="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` + echo "Publishing release: $IMAGE_TAG_PATCH"; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MAJOR && docker push $IMAGE_TAG_MAJOR; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_MINOR && docker push $IMAGE_TAG_MINOR; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_PATCH && docker push $IMAGE_TAG_PATCH; + fi + # Release candidate vX.Y.Z-rc.R + if [[ $GITHUB_TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$ ]]; then + IMAGE_TAG_RC="$PUBLIC_IMAGE:"`echo $GITHUB_TAG | sed -E "s/v//g"` + echo "Publishing release candidate: $IMAGE_TAG_RC"; + docker image tag $PRIVATE_IMAGE:$GITHUB_SHA $IMAGE_TAG_RC && docker push $IMAGE_TAG_RC; + fi diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fe57773..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: java -jdk: - - openjdk11 - - openjdk12 - - openjdk13 -script: - - mvn -B -ff tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify -cache: - - directories: - - $HOME/.m2 diff --git a/README.md b/README.md index d2a589b..364ab3a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # FAIRDataPoint-index Index of FAIR Data Points -[![Build Status](https://travis-ci.com/FAIRDataTeam/FAIRDataPoint-index.svg?branch=develop)](https://travis-ci.com/FAIRDataTeam/FAIRDataPoint-index) +[![FAIRDataPoint-index CI](https://github.com/FAIRDataTeam/FAIRDataPoint-index/workflows/FAIRDataPoint-index%20CI/badge.svg?branch=master)](https://github.com/FAIRDataTeam/FAIRDataPoint-index/actions) +[![License](https://img.shields.io/github/license/FAIRDataTeam/FAIRDataPoint-index)](LICENSE) # Introduction The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. From 450fe94a1ba0794b76d6b2756586e8ca75ad71f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 14 May 2020 14:34:33 +0200 Subject: [PATCH 13/22] [INDEX-1] Improve basic UI (#2) --- pom.xml | 18 +++++- src/main/resources/static/css/common.css | 57 ++++++++++++++++++ src/main/resources/static/img/fair_logo.png | Bin 0 -> 1416 bytes .../static/js/localize-timestamps.js | 6 ++ .../resources/templates/fragments/footer.html | 11 ++++ .../resources/templates/fragments/header.html | 13 ++++ src/main/resources/templates/home.html | 46 ++++++++------ src/main/resources/templates/layout.html | 22 +++++++ 8 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 src/main/resources/static/css/common.css create mode 100644 src/main/resources/static/img/fair_logo.png create mode 100644 src/main/resources/static/js/localize-timestamps.js create mode 100644 src/main/resources/templates/fragments/footer.html create mode 100644 src/main/resources/templates/fragments/header.html create mode 100644 src/main/resources/templates/layout.html diff --git a/pom.xml b/pom.xml index b5a21e2..7028f2e 100644 --- a/pom.xml +++ b/pom.xml @@ -60,11 +60,27 @@ org.springframework.boot spring-boot-starter-thymeleaf + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + org.projectlombok lombok - + + + org.webjars + bootstrap + 4.4.1 + + + org.webjars + jquery + 3.5.1 + + + com.github.spotbugs spotbugs-annotations diff --git a/src/main/resources/static/css/common.css b/src/main/resources/static/css/common.css new file mode 100644 index 0000000..5998fde --- /dev/null +++ b/src/main/resources/static/css/common.css @@ -0,0 +1,57 @@ +body { + font-family: "Open Sans", sans-serif; +} + +main { + display: flex; + flex-direction: column; + min-height: 100vh; +} + +header img.logo { + max-height: 3em; + margin-right: 2em; +} + +header div.container { + min-height: 90px; + display: flex; + align-items: center; +} + +header h1 { + font-size: 2rem; + font-weight: 700; + display: inline-block; +} + +section#content { + flex-grow: 1; + padding-top: 1rem; + padding-bottom: 1rem; +} + +footer { + margin-top: 2rem; + border-top: 1px solid #dcdcdc; +} + +footer div.container { + text-align: center; + padding: 2rem; +} + +div.separator { + width: 100%; + height: 10px; + background: #00518E; + background: linear-gradient(90deg, #00518E, #c6c6c6); +} + +table.entries td.endpoint { + overflow-wrap: anywhere; +} +table.entries td.timestamp, +table.entries th.right { + text-align: right; +} diff --git a/src/main/resources/static/img/fair_logo.png b/src/main/resources/static/img/fair_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..d9926e4d85ebb64db147b3da497740899db00252 GIT binary patch literal 1416 zcmV;31$X+1P)MMP%<_xD_t#k1r7E{N!2;Qm~2KBggLMD*7PC*#AGh(Zfz zD_L&VMD#^z^S=_&qvLN45nT`5--?Kqj=#MnqOSw@=R}s9`p=&1!_qz^Y)JTF;d+f) z$;LR5RLOF4s~7^%%q9QtA@o^pUipEsuF7K5=eqrbi`@_IirmL|>^E7zCjM$Z@h9wF(GA3y|ZaIsf>50YPX0ay$!)`bi=P%|MRR=ek~kAyIw0 zt;!;rvguPmj@_urV(C$`-3yl5GcLazzf2MhpsMoq}pKiWfus-e{2-`pFjx? zgZJQ@7T!uOW*>wsHxgrg!N~9g4?hI<`u3t{)MNntHL(HF}=noH!<5FD9f=_ zvkkfto91PfK~R?CRo|HufHz|EU(K~e(30aH{Gka%#_WQiD92Ce5{*vlh%;X#zAW3C zjen#Ls49z3Qrr57vK-&KPR|I$keG7vt$Q__7C~8#i`eFCO$4W@T2AmL+_MORvK)Ws zPyb*Q(6NK6u1q~p_Y4Ffi6q!U2 zSdQ0_W6;4GP}CA(Z4myaoCYhGF(MK{=xlN{ zVL8@V^cr#;KU*KSlL*3##LDNsK#oBRHULZCzsV@OMv!ArW54RY{kN%?P52P2BS4P9 zp0&h1i!KO|<1iRH8#cG|dFQk%n60@Jm0tP9ZuL0OJ} zha8U&U-Ol~j;$+h+Ln%WA&MX<%kcx`csjU?B{9wW`H(3fV`&kzHs~DbK+KfhTpB;^Z@@;qq}SdPCbZ60!*2<&%~i!>g| z^JGDQ90MQtm8!%_`_v@QlLP^B40}G37iTY62!1}Vv+O&ShY}L!=p*|QP88DhYsJo5!GBA=hi1Nm==NX7 WBKrMXo^KEU0000 { + jQuery("td.timestamp").each(function() { + const dt = new Date($(this).text()); + $(this).text(dt.toLocaleString("en-GB")); + }); +}); diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html new file mode 100644 index 0000000..2da1e4b --- /dev/null +++ b/src/main/resources/templates/fragments/footer.html @@ -0,0 +1,11 @@ + + + +
+
+ FAIR Data Team © 2020 +
+
+
+ + diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html new file mode 100644 index 0000000..5f87394 --- /dev/null +++ b/src/main/resources/templates/fragments/header.html @@ -0,0 +1,13 @@ + + + +
+
+ +

FAIR Data Point index

+
+
+
+ + diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index b2d567a..b86edbf 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -1,24 +1,30 @@ - - - FAIR Data Point index - + + - - - - - - - - - - - - - - - -
EndpointRegistrationModification
+
+ + + + + + + + + + + + + + + +
EndpointRegistrationModification
+ +
+ +
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html new file mode 100644 index 0000000..5044faf --- /dev/null +++ b/src/main/resources/templates/layout.html @@ -0,0 +1,22 @@ + + + + FAIR Data Point index + + + + + + + +
+
+ +
+ +
+
+ + From cc5224966605b902ab57b03333520fb0bf4a801d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Sun, 17 May 2020 16:16:32 +0200 Subject: [PATCH 14/22] [INDEX-2] Add entries pagination (#3) --- package-lock.json | 1521 +++++++++++++++++ package.json | 25 + pom.xml | 57 +- .../fdp/index/service/IndexService.java | 6 + .../fdp/index/storage/EntryRepository.java | 4 +- .../index/web/controller/HomeController.java | 6 +- src/main/resources/application.properties | 7 + src/main/resources/static/css/common.css | 57 - src/main/resources/templates/home.html | 79 +- src/main/resources/templates/layout.html | 7 +- src/main/scss/site.scss | 60 + 11 files changed, 1728 insertions(+), 101 deletions(-) create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/main/resources/application.properties delete mode 100644 src/main/resources/static/css/common.css create mode 100644 src/main/scss/site.scss diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b9f8d43 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1521 @@ +{ + "name": "FAIRDataPoint-index", + "version": "0.1.0-SNAPSHOT", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "ajv": { + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz", + "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, + "bootstrap": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.5.0.tgz", + "integrity": "sha512-Z93QoXvodoVslA+PWNdk23Hze4RBYIkpb5h8I2HY2Tu2h7A0LpAgLcyrhrSUyo2/Oxm2l1fRZPs1e5hnxnliXA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "copyfiles": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.2.0.tgz", + "integrity": "sha512-iJbHJI+8OKqsq+4JF0rqgRkZzo++jqO6Wf4FUU1JM41cJF6JcY5968XyF4tm3Kkm7ZOMrqlljdm8N9oyY5raGw==", + "requires": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^0.5.1", + "noms": "0.0.0", + "through2": "^2.0.1", + "yargs": "^13.2.4" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globule": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.12", + "minimatch": "~3.0.2" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jquery": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", + "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==" + }, + "js-base64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + } + }, + "noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + } + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==" + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "^2.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "^7.1.2" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5120e81 --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "FAIRDataPoint-index", + "version": "0.1.0-SNAPSHOT", + "description": "", + "main": "index.js", + "scripts": { + "scss": "node-sass src/main/scss -o target/classes/static/css" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/FAIRDataTeam/FAIRDataPoint-index.git" + }, + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/FAIRDataTeam/FAIRDataPoint-index/issues" + }, + "homepage": "https://github.com/FAIRDataTeam/FAIRDataPoint-index", + "dependencies": { + "bootstrap": "^4.5.0", + "copyfiles": "^2.1.0", + "jquery": "^3.5.1", + "node-sass": "4.14.1" + } +} diff --git a/pom.xml b/pom.xml index 7028f2e..91dc28b 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ 11 3.0 4.0.0 + v12.16.3 @@ -68,18 +69,6 @@ org.projectlombok lombok
- - - org.webjars - bootstrap - 4.4.1 - - - org.webjars - jquery - 3.5.1 - - com.github.spotbugs @@ -90,6 +79,19 @@ fairdatapoint-index + + + ${project.basedir}/src/main/resources + + + ${project.basedir}/node_modules/jquery/dist + static/js/jquery + + + ${project.basedir}/node_modules/bootstrap/dist/js + static/js/bootstrap + + org.springframework.boot @@ -110,6 +112,37 @@ + + com.github.eirslett + frontend-maven-plugin + 1.10.0 + + ${node.version} + + + + install-node-and-npm + + install-node-and-npm + + + + npm-install + + npm + + + + scss-compile + + npm + + + run scss + + + + diff --git a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java index 77089dd..7f09c3c 100644 --- a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java @@ -26,6 +26,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; import solutions.fairdata.fdp.index.domain.IndexEntry; import solutions.fairdata.fdp.index.storage.EntryRepository; @@ -59,4 +61,8 @@ public void storeEntry(String clientUrl) { public Iterable getAllEntries() { return repository.findAll(); } + + public Page getEntriesPage(Pageable pageable) { + return repository.findAll(pageable); + } } diff --git a/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java b/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java index 24a2ad2..427a2c7 100644 --- a/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java +++ b/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java @@ -22,8 +22,8 @@ */ package solutions.fairdata.fdp.index.storage; -import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.PagingAndSortingRepository; import solutions.fairdata.fdp.index.domain.IndexEntry; -public interface EntryRepository extends CrudRepository { +public interface EntryRepository extends PagingAndSortingRepository { } diff --git a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java index cf07422..49b24f5 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java @@ -23,6 +23,8 @@ package solutions.fairdata.fdp.index.web.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.data.web.PageableDefault; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -36,8 +38,8 @@ public class HomeController { private IndexService service; @GetMapping - public String home(Model model) { - model.addAttribute("entries", service.getAllEntries()); + public String home(Model model, Pageable pageable) { + model.addAttribute("entries", service.getEntriesPage(pageable)); return "home"; } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..d330e6b --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,7 @@ +spring.data.web.pageable.size-parameter=size +spring.data.web.pageable.page-parameter=page +spring.data.web.pageable.default-page-size=50 +spring.data.web.pageable.one-indexed-parameters=true +spring.data.web.pageable.max-page-size=2000 +spring.data.web.pageable.prefix= +spring.data.web.pageable.qualifier-delimiter=_ diff --git a/src/main/resources/static/css/common.css b/src/main/resources/static/css/common.css deleted file mode 100644 index 5998fde..0000000 --- a/src/main/resources/static/css/common.css +++ /dev/null @@ -1,57 +0,0 @@ -body { - font-family: "Open Sans", sans-serif; -} - -main { - display: flex; - flex-direction: column; - min-height: 100vh; -} - -header img.logo { - max-height: 3em; - margin-right: 2em; -} - -header div.container { - min-height: 90px; - display: flex; - align-items: center; -} - -header h1 { - font-size: 2rem; - font-weight: 700; - display: inline-block; -} - -section#content { - flex-grow: 1; - padding-top: 1rem; - padding-bottom: 1rem; -} - -footer { - margin-top: 2rem; - border-top: 1px solid #dcdcdc; -} - -footer div.container { - text-align: center; - padding: 2rem; -} - -div.separator { - width: 100%; - height: 10px; - background: #00518E; - background: linear-gradient(90deg, #00518E, #c6c6c6); -} - -table.entries td.endpoint { - overflow-wrap: anywhere; -} -table.entries td.timestamp, -table.entries th.right { - text-align: right; -} diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index b86edbf..0a213aa 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -3,28 +3,59 @@ xmlns:th="http://thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{layout}"> - - -
- - - - - - - - - - - - - - - -
EndpointRegistrationModification
- -
- -
- + + +
+ + + + + + + + + + + + + + + +
EndpointRegistrationModification
+ +
+
+
+
+ entries in total +
+ +
+ +
+ diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index 5044faf..fa50a8c 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -4,11 +4,10 @@ xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"> FAIR Data Point index - - + - - + +
diff --git a/src/main/scss/site.scss b/src/main/scss/site.scss new file mode 100644 index 0000000..ba897d3 --- /dev/null +++ b/src/main/scss/site.scss @@ -0,0 +1,60 @@ +$primary: #00518E; +$secondary: #C6C6C6; + +$font-family-sans-serif: 'Open Sans', sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; + +@import "../../../node_modules/bootstrap/scss/bootstrap"; + +div.separator { + width: 100%; + height: 10px; + background: $primary; + background: linear-gradient(90deg, $primary, $secondary); +} + +main { + display: flex; + flex-direction: column; + min-height: 100vh; +} + +header img.logo { + max-height: 3em; + margin-right: 2em; +} + +header div.container { + min-height: 90px; + display: flex; + align-items: center; +} + +header h1 { + font-size: 2rem; + font-weight: 700; + display: inline-block; +} + +section#content { + flex-grow: 1; + padding-top: 1rem; + padding-bottom: 1rem; +} + +footer { + margin-top: 2rem; + border-top: 1px solid #dcdcdc; +} + +footer div.container { + text-align: center; + padding: 2rem; +} + +table.entries td.endpoint { + overflow-wrap: anywhere; +} +table.entries td.timestamp, +table.entries th.right { + text-align: right; +} From 6d4a17911e9c36bb0fdbd8eda575d34f308b790e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Tue, 19 May 2020 18:04:22 +0200 Subject: [PATCH 15/22] [INDEX-3] Provide API access (#4) --- pom.xml | 22 ++++++- .../fairdata/fdp/index/api/ApiConfig.java | 34 +++++++++++ .../fdp/index/api/config/OpenApiConfig.java | 57 +++++++++++++++++++ .../api/controller/EntriesController.java | 56 ++++++++++++++++++ .../controller/PingController.java | 9 ++- .../index/api/controller/package-info.java | 25 ++++++++ .../fairdata/fdp/index/api/dto/EntryDTO.java | 43 ++++++++++++++ .../dto/PingDto.java => api/dto/PingDTO.java} | 7 ++- .../index/{web => api}/dto/package-info.java | 2 +- .../fairdata/fdp/index/api/package-info.java | 25 ++++++++ .../app/FairDataPointIndexApplication.java | 5 +- .../fdp/index/service/IndexService.java | 9 +++ 12 files changed, 283 insertions(+), 11 deletions(-) create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java rename src/main/java/solutions/fairdata/fdp/index/{web => api}/controller/PingController.java (89%) create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/controller/package-info.java create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java rename src/main/java/solutions/fairdata/fdp/index/{web/dto/PingDto.java => api/dto/PingDTO.java} (90%) rename src/main/java/solutions/fairdata/fdp/index/{web => api}/dto/package-info.java (96%) create mode 100644 src/main/java/solutions/fairdata/fdp/index/api/package-info.java diff --git a/pom.xml b/pom.xml index 91dc28b..cbf3a6c 100644 --- a/pom.xml +++ b/pom.xml @@ -43,8 +43,9 @@ 11 3.0 - 4.0.0 v12.16.3 + 4.0.0 + 1.3.9 @@ -69,6 +70,17 @@ org.projectlombok lombok + + + org.springdoc + springdoc-openapi-ui + ${springdoc.version} + + + org.springdoc + springdoc-openapi-data-rest + ${springdoc.version} + com.github.spotbugs @@ -96,6 +108,14 @@ org.springframework.boot spring-boot-maven-plugin + + + build-info + + build-info + + + com.mycila diff --git a/src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java b/src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java new file mode 100644 index 0000000..55322db --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java @@ -0,0 +1,34 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.api; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import solutions.fairdata.fdp.index.service.ServiceConfig; + +@Configuration +@ComponentScan +@Import(ServiceConfig.class) +public class ApiConfig { +} diff --git a/src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java b/src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java new file mode 100644 index 0000000..1deee01 --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java @@ -0,0 +1,57 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.api.config; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; +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; + +@Configuration +public class OpenApiConfig { + + @Autowired + BuildProperties buildProperties; + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .components(new Components()) + .info( + new Info().title( + "FAIR Data Point Index API" + ).description( + "This is OpenAPI documentation of FAIR Data Point Index REST API." + ).version( + buildProperties.getVersion() + ).license( + new License().name("MIT") + ) + ); + } +} diff --git a/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java b/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java new file mode 100644 index 0000000..e98bbff --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java @@ -0,0 +1,56 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.api.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import solutions.fairdata.fdp.index.api.dto.EntryDTO; +import solutions.fairdata.fdp.index.service.IndexService; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Tag(name = "Entries") +@RestController +@RequestMapping("/entries") +public class EntriesController { + + @Autowired + private IndexService service; + + @GetMapping("") + public Page getEntriesPage(Pageable pageable) { + return service.getEntriesPage(pageable).map(service::toDTO); + } + + @GetMapping("/all") + public List getEntriesAll() { + return StreamSupport.stream(service.getAllEntries().spliterator(), true).map(service::toDTO).collect(Collectors.toList()); + } +} diff --git a/src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java b/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java similarity index 89% rename from src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java rename to src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java index 5eab808..cdeff6b 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/controller/PingController.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java @@ -20,9 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.web.controller; +package solutions.fairdata.fdp.index.api.controller; import javax.validation.Valid; + +import io.swagger.v3.oas.annotations.tags.Tag; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -33,8 +35,9 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import solutions.fairdata.fdp.index.service.IndexService; -import solutions.fairdata.fdp.index.web.dto.PingDto; +import solutions.fairdata.fdp.index.api.dto.PingDTO; +@Tag(name = "Ping") @RestController @RequestMapping("/") public class PingController { @@ -45,7 +48,7 @@ public class PingController { @PostMapping @ResponseStatus(HttpStatus.NO_CONTENT) - public void receivePing(@RequestBody @Valid PingDto ping) { + public void receivePing(@RequestBody @Valid PingDTO ping) { logger.info("Received ping from {}", ping); service.storeEntry(ping.getClientUrl()); diff --git a/src/main/java/solutions/fairdata/fdp/index/api/controller/package-info.java b/src/main/java/solutions/fairdata/fdp/index/api/controller/package-info.java new file mode 100644 index 0000000..c31eb74 --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/controller/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.fdp.index.api.controller; diff --git a/src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java b/src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java new file mode 100644 index 0000000..7c98b7c --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java @@ -0,0 +1,43 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.api.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.URL; +import javax.validation.constraints.NotNull; +import java.time.OffsetDateTime; + +@Data +@Schema(name = "Entry") +public class EntryDTO { + @NotNull + @URL + private String clientUrl; + + @NotNull + private OffsetDateTime registrationTime; + + @NotNull + private OffsetDateTime modificationTime; +} diff --git a/src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java b/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java similarity index 90% rename from src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java rename to src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java index b96adac..137fad8 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/dto/PingDto.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java @@ -20,14 +20,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.web.dto; +package solutions.fairdata.fdp.index.api.dto; import javax.validation.constraints.NotNull; + +import io.swagger.v3.oas.annotations.media.Schema; import org.hibernate.validator.constraints.URL; import lombok.Data; @Data -public class PingDto { +@Schema(name = "Ping") +public class PingDTO { @NotNull @URL private String clientUrl; diff --git a/src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java b/src/main/java/solutions/fairdata/fdp/index/api/dto/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/api/dto/package-info.java index 3780ee4..f110e40 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/dto/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/dto/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.web.dto; +package solutions.fairdata.fdp.index.api.dto; diff --git a/src/main/java/solutions/fairdata/fdp/index/api/package-info.java b/src/main/java/solutions/fairdata/fdp/index/api/package-info.java new file mode 100644 index 0000000..ce0e3bb --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/api/package-info.java @@ -0,0 +1,25 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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. + */ + +@javax.annotation.ParametersAreNonnullByDefault +package solutions.fairdata.fdp.index.api; diff --git a/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java b/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java index 73363fe..938909e 100644 --- a/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java +++ b/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java @@ -24,11 +24,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Import; -import solutions.fairdata.fdp.index.web.WebConfig; -@SpringBootApplication -@Import(WebConfig.class) +@SpringBootApplication(scanBasePackages = {"solutions.fairdata.fdp.index"}) public class FairDataPointIndexApplication { public static void main(String[] args) { SpringApplication.run(FairDataPointIndexApplication.class, args); diff --git a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java index 7f09c3c..1725238 100644 --- a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java @@ -29,6 +29,7 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; +import solutions.fairdata.fdp.index.api.dto.EntryDTO; import solutions.fairdata.fdp.index.domain.IndexEntry; import solutions.fairdata.fdp.index.storage.EntryRepository; @@ -65,4 +66,12 @@ public Iterable getAllEntries() { public Page getEntriesPage(Pageable pageable) { return repository.findAll(pageable); } + + public EntryDTO toDTO(IndexEntry indexEntry) { + EntryDTO dto = new EntryDTO(); + dto.setClientUrl(indexEntry.getClientUrl()); + dto.setRegistrationTime(OffsetDateTime.parse(indexEntry.getRegistrationTime())); + dto.setModificationTime(OffsetDateTime.parse(indexEntry.getModificationTime())); + return dto; + } } From 11e3466649d105c760c469643ff6f7c4ebeb0c5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Thu, 4 Jun 2020 20:25:18 +0200 Subject: [PATCH 16/22] [INDEX-6] Use MongoDB and tests (#5) --- .dockerignore | 2 - .github/workflows/main.yml | 10 + Dockerfile | 3 +- README.md | 10 +- docker-compose.yml | 15 +- pom.xml | 16 +- .../FairDataPointIndexApplication.java | 3 +- .../fairdata/fdp/index/Profiles.java | 37 +++ .../api/controller/EntriesController.java | 10 +- .../index/api/controller/PingController.java | 22 +- .../dto/{EntryDTO.java => IndexEntryDTO.java} | 3 +- .../fairdata/fdp/index/api/dto/PingDTO.java | 6 +- .../index/{api => }/config/OpenApiConfig.java | 35 +-- .../{storage => config}/StorageConfig.java | 37 +-- .../fdp/index/{web => config}/WebConfig.java | 7 +- .../index/{web => config}/package-info.java | 2 +- .../changelogs/DatabaseChangeLog.java} | 19 +- .../changelogs}/package-info.java | 2 +- .../repository}/EntryRepository.java | 11 +- .../repository}/package-info.java | 2 +- .../index/{domain => entity}/IndexEntry.java | 13 +- .../index/{app => entity}/package-info.java | 2 +- .../fdp/index/{api => }/package-info.java | 2 +- ...dexService.java => IndexEntryService.java} | 29 +-- .../index/web/controller/HomeController.java | 7 +- ...itional-spring-configuration-metadata.json | 29 +++ src/main/resources/application.properties | 7 - src/main/resources/application.yml | 21 ++ src/main/resources/log4j2.xml | 16 ++ .../static/js/localize-timestamps.js | 2 +- .../resources/templates/fragments/footer.html | 2 +- .../resources/templates/fragments/header.html | 2 +- src/main/resources/templates/home.html | 50 ++-- src/main/resources/templates/layout.html | 32 +-- src/main/scss/site.scss | 1 + .../fdp/index/WebIntegrationTest.java | 51 ++++ .../api/entries/EntriesAll_GET.java | 137 +++++++++++ .../api/entries/EntriesPage_GET.java | 227 ++++++++++++++++++ .../acceptance/api/ping/ReceivePing_POST.java | 179 ++++++++++++++ .../index/acceptance/web/home/Home_GET.java | 227 ++++++++++++++++++ .../index/fixtures/IndexEntryFixtures.java | 62 +++++ .../fdp/index/utils/CustomPageImpl.java} | 46 +++- src/test/resources/application-testing.yml | 4 + src/test/resources/log4j2.xml | 12 + 44 files changed, 1240 insertions(+), 172 deletions(-) delete mode 100644 .dockerignore rename src/main/java/solutions/fairdata/fdp/index/{app => }/FairDataPointIndexApplication.java (93%) create mode 100644 src/main/java/solutions/fairdata/fdp/index/Profiles.java rename src/main/java/solutions/fairdata/fdp/index/api/dto/{EntryDTO.java => IndexEntryDTO.java} (98%) rename src/main/java/solutions/fairdata/fdp/index/{api => }/config/OpenApiConfig.java (60%) rename src/main/java/solutions/fairdata/fdp/index/{storage => config}/StorageConfig.java (59%) rename src/main/java/solutions/fairdata/fdp/index/{web => config}/WebConfig.java (83%) rename src/main/java/solutions/fairdata/fdp/index/{web => config}/package-info.java (96%) rename src/main/java/solutions/fairdata/fdp/index/{service/ServiceConfig.java => database/changelogs/DatabaseChangeLog.java} (72%) rename src/main/java/solutions/fairdata/fdp/index/{storage => database/changelogs}/package-info.java (95%) rename src/main/java/solutions/fairdata/fdp/index/{storage => database/repository}/EntryRepository.java (76%) rename src/main/java/solutions/fairdata/fdp/index/{domain => database/repository}/package-info.java (95%) rename src/main/java/solutions/fairdata/fdp/index/{domain => entity}/IndexEntry.java (86%) rename src/main/java/solutions/fairdata/fdp/index/{app => entity}/package-info.java (96%) rename src/main/java/solutions/fairdata/fdp/index/{api => }/package-info.java (96%) rename src/main/java/solutions/fairdata/fdp/index/service/{IndexService.java => IndexEntryService.java} (86%) create mode 100644 src/main/resources/META-INF/additional-spring-configuration-metadata.json delete mode 100644 src/main/resources/application.properties create mode 100644 src/main/resources/application.yml create mode 100644 src/main/resources/log4j2.xml create mode 100644 src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java create mode 100644 src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java create mode 100644 src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java create mode 100644 src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java create mode 100644 src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java create mode 100644 src/test/java/solutions/fairdata/fdp/index/fixtures/IndexEntryFixtures.java rename src/{main/java/solutions/fairdata/fdp/index/api/ApiConfig.java => test/java/solutions/fairdata/fdp/index/utils/CustomPageImpl.java} (55%) create mode 100644 src/test/resources/application-testing.yml create mode 100644 src/test/resources/log4j2.xml diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index 251a318..0000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -** -!target/*.jar diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c9b6650..76714f8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,6 +18,12 @@ jobs: JDK_FILE: openjdk-11.0.2_linux-x64_bin.tar.gz JDK_URL: https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz + services: + mongo: + image: mongo:4.2 + ports: + - 27017:27017 + steps: - uses: actions/checkout@v2 @@ -56,6 +62,10 @@ jobs: mvn --version # (3) -> Test and build + - name: Run tests + run: | + mvn --quiet -U -B org.jacoco:jacoco-maven-plugin:prepare-agent test + - name: Build package and verify run: | mvn --quiet -B -U --fail-fast -DskipTests tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify diff --git a/Dockerfile b/Dockerfile index eea0489..fdc2644 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,5 +3,6 @@ FROM openjdk:11-jdk-slim WORKDIR /app ADD target/fairdatapoint-index.jar /app/app.jar +ADD target/classes/application.yml /app/application.yml -ENTRYPOINT java -jar app.jar +ENTRYPOINT java -jar app.jar --spring.config.location=classpath:/application.yml,file:/app/application.yml diff --git a/README.md b/README.md index 364ab3a..c3a61fe 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ # FAIRDataPoint-index + Index of FAIR Data Points [![FAIRDataPoint-index CI](https://github.com/FAIRDataTeam/FAIRDataPoint-index/workflows/FAIRDataPoint-index%20CI/badge.svg?branch=master)](https://github.com/FAIRDataTeam/FAIRDataPoint-index/actions) [![License](https://img.shields.io/github/license/FAIRDataTeam/FAIRDataPoint-index)](LICENSE) # Introduction + The index serves as a registry for [FAIR Data Point](https://github.com/FAIRDataTeam/FAIRDataPoint) deployments. # Quickstart + - build the app by running `mvn package` -- start redis by running `docker-compose up -d` -- post something using `curl -H "Content-Type: application/json" -d '{"clientUrl":"http://example.com/"}' http://localhost:8080/` -- see the results in your browser at `http://localhost:8080/` +- start whole stack by running `docker-compose up -d` +- visit `http://localhost:8080/` +- see API docs `http://localhost:8080/swagger-ui.html` # License + This project is licensed under the [MIT License](LICENSE). diff --git a/docker-compose.yml b/docker-compose.yml index 83f52f9..0624a08 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,12 +4,11 @@ services: build: . ports: - "127.0.0.1:8080:8080" - - redis: - image: redis - container_name: redis + - "127.0.0.1:27017:27017" +# volumes: +# - ./application.yml:/app/application.yml + mongo: + image: mongo network_mode: service:index -# ports: -# - "127.0.0.1:6379:6379" -# volumes: -# - ./redis-data:/data +# volumes: +# - ./mongo-data:/data/db diff --git a/pom.xml b/pom.xml index cbf3a6c..788b2fe 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ 11 3.0 + 0.13 v12.16.3 4.0.0 1.3.9 @@ -56,7 +57,7 @@ org.springframework.boot - spring-boot-starter-data-redis + spring-boot-starter-data-mongodb org.springframework.boot @@ -70,6 +71,11 @@ org.projectlombok lombok + + com.github.mongobee + mongobee + ${mongobee.version} + org.springdoc @@ -81,7 +87,13 @@ springdoc-openapi-data-rest ${springdoc.version} - + + + org.springframework.boot + spring-boot-starter-test + test + + com.github.spotbugs spotbugs-annotations diff --git a/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java similarity index 93% rename from src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java rename to src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java index 938909e..e65a42f 100644 --- a/src/main/java/solutions/fairdata/fdp/index/app/FairDataPointIndexApplication.java +++ b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java @@ -20,10 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.app; +package solutions.fairdata.fdp.index; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; @SpringBootApplication(scanBasePackages = {"solutions.fairdata.fdp.index"}) public class FairDataPointIndexApplication { diff --git a/src/main/java/solutions/fairdata/fdp/index/Profiles.java b/src/main/java/solutions/fairdata/fdp/index/Profiles.java new file mode 100644 index 0000000..3e49320 --- /dev/null +++ b/src/main/java/solutions/fairdata/fdp/index/Profiles.java @@ -0,0 +1,37 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index; + +public class Profiles { + + public static final String PRODUCTION = "production"; + + public static final String DEVELOPMENT = "development"; + + public static final String TESTING = "testing"; + + public static final String NON_TESTING = "!testing"; + + public static final String NON_PRODUCTION = "!production"; + +} diff --git a/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java b/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java index e98bbff..0bcfdaa 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/controller/EntriesController.java @@ -29,8 +29,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import solutions.fairdata.fdp.index.api.dto.EntryDTO; -import solutions.fairdata.fdp.index.service.IndexService; +import solutions.fairdata.fdp.index.api.dto.IndexEntryDTO; +import solutions.fairdata.fdp.index.service.IndexEntryService; import java.util.List; import java.util.stream.Collectors; @@ -42,15 +42,15 @@ public class EntriesController { @Autowired - private IndexService service; + private IndexEntryService service; @GetMapping("") - public Page getEntriesPage(Pageable pageable) { + public Page getEntriesPage(Pageable pageable) { return service.getEntriesPage(pageable).map(service::toDTO); } @GetMapping("/all") - public List getEntriesAll() { + public List getEntriesAll() { return StreamSupport.stream(service.getAllEntries().spliterator(), true).map(service::toDTO).collect(Collectors.toList()); } } diff --git a/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java b/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java index cdeff6b..c967297 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/controller/PingController.java @@ -22,35 +22,33 @@ */ package solutions.fairdata.fdp.index.api.controller; -import javax.validation.Valid; - +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; -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.ResponseStatus; -import org.springframework.web.bind.annotation.RestController; -import solutions.fairdata.fdp.index.service.IndexService; +import org.springframework.web.bind.annotation.*; import solutions.fairdata.fdp.index.api.dto.PingDTO; +import solutions.fairdata.fdp.index.service.IndexEntryService; + +import javax.validation.Valid; @Tag(name = "Ping") @RestController @RequestMapping("/") public class PingController { private static final Logger logger = LoggerFactory.getLogger(PingController.class); - + @Autowired - private IndexService service; - + private IndexEntryService service; + + @Operation(hidden = true) @PostMapping @ResponseStatus(HttpStatus.NO_CONTENT) public void receivePing(@RequestBody @Valid PingDTO ping) { logger.info("Received ping from {}", ping); - + service.storeEntry(ping.getClientUrl()); } } diff --git a/src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java b/src/main/java/solutions/fairdata/fdp/index/api/dto/IndexEntryDTO.java similarity index 98% rename from src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java rename to src/main/java/solutions/fairdata/fdp/index/api/dto/IndexEntryDTO.java index 7c98b7c..b13cf38 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/dto/EntryDTO.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/dto/IndexEntryDTO.java @@ -25,12 +25,13 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import org.hibernate.validator.constraints.URL; + import javax.validation.constraints.NotNull; import java.time.OffsetDateTime; @Data @Schema(name = "Entry") -public class EntryDTO { +public class IndexEntryDTO { @NotNull @URL private String clientUrl; diff --git a/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java b/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java index 137fad8..ec47d14 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java +++ b/src/main/java/solutions/fairdata/fdp/index/api/dto/PingDTO.java @@ -22,11 +22,11 @@ */ package solutions.fairdata.fdp.index.api.dto; -import javax.validation.constraints.NotNull; - import io.swagger.v3.oas.annotations.media.Schema; -import org.hibernate.validator.constraints.URL; import lombok.Data; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.NotNull; @Data @Schema(name = "Ping") diff --git a/src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java b/src/main/java/solutions/fairdata/fdp/index/config/OpenApiConfig.java similarity index 60% rename from src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java rename to src/main/java/solutions/fairdata/fdp/index/config/OpenApiConfig.java index 1deee01..47e8904 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/config/OpenApiConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/config/OpenApiConfig.java @@ -20,18 +20,21 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.api.config; +package solutions.fairdata.fdp.index.config; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; +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.servers.Server; 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.Collections; + @Configuration public class OpenApiConfig { @@ -39,19 +42,21 @@ public class OpenApiConfig { BuildProperties buildProperties; @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI() + public OpenAPI customOpenAPI(@Value("${fdp-index.api.url:#{null}}") String serverUrl, + @Value("${fdp-index.api.title:#{null}}") String title, + @Value("${fdp-index.api.description:#{null}}") String description, + @Value("${fdp-index.api.contactUrl:#{null}}") String contactUrl, + @Value("${fdp-index.api.contactName:#{null}}") String contactName) { + String version = buildProperties.getVersion(); + OpenAPI openAPI = new OpenAPI() .components(new Components()) - .info( - new Info().title( - "FAIR Data Point Index API" - ).description( - "This is OpenAPI documentation of FAIR Data Point Index REST API." - ).version( - buildProperties.getVersion() - ).license( - new License().name("MIT") - ) - ); + .info(new Info().title(title).description(description).version(version)); + if (contactUrl != null) { + openAPI.getInfo().contact(new Contact().url(contactUrl).name(contactName)); + } + if (serverUrl != null) { + openAPI.servers(Collections.singletonList(new Server().url(serverUrl))); + } + return openAPI; } } diff --git a/src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java b/src/main/java/solutions/fairdata/fdp/index/config/StorageConfig.java similarity index 59% rename from src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java rename to src/main/java/solutions/fairdata/fdp/index/config/StorageConfig.java index 319180f..210eee1 100644 --- a/src/main/java/solutions/fairdata/fdp/index/storage/StorageConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/config/StorageConfig.java @@ -20,27 +20,34 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.storage; +package solutions.fairdata.fdp.index.config; +import com.github.mongobee.Mongobee; +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 org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; +import org.springframework.core.env.Environment; +import org.springframework.data.mongodb.config.EnableMongoAuditing; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @Configuration -@EnableRedisRepositories +@EnableMongoAuditing +@EnableMongoRepositories(basePackages = {"solutions.fairdata.fdp.index"}) public class StorageConfig { + + @Value("${spring.data.mongodb.uri}") + private String mongoUri; + + @Autowired + private Environment environment; + @Bean - public RedisConnectionFactory connectionFactory() { - return new LettuceConnectionFactory(); - } - - @Bean - public RedisTemplate redisTemplate() { - var template = new RedisTemplate(); - template.setConnectionFactory(connectionFactory()); - return template; + public Mongobee mongobee() throws Exception { + Mongobee runner = new Mongobee(mongoUri); + runner.setChangeLogsScanPackage("solutions.fairdata.fdp.index.storage.changelogs"); + runner.setSpringEnvironment(environment); + runner.execute(); + return runner; } } diff --git a/src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java b/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java similarity index 83% rename from src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java rename to src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java index 04fa990..0405dde 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/WebConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java @@ -20,16 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.web; +package solutions.fairdata.fdp.index.config; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import solutions.fairdata.fdp.index.service.ServiceConfig; @Configuration -@ComponentScan -@Import(ServiceConfig.class) public class WebConfig implements WebMvcConfigurer { } diff --git a/src/main/java/solutions/fairdata/fdp/index/web/package-info.java b/src/main/java/solutions/fairdata/fdp/index/config/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/fdp/index/web/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/config/package-info.java index 9ffa071..e19afe9 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/config/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.web; +package solutions.fairdata.fdp.index.config; diff --git a/src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java b/src/main/java/solutions/fairdata/fdp/index/database/changelogs/DatabaseChangeLog.java similarity index 72% rename from src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java rename to src/main/java/solutions/fairdata/fdp/index/database/changelogs/DatabaseChangeLog.java index 5e18adf..d3c50a9 100644 --- a/src/main/java/solutions/fairdata/fdp/index/service/ServiceConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/database/changelogs/DatabaseChangeLog.java @@ -20,15 +20,16 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.service; +package solutions.fairdata.fdp.index.database.changelogs; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import solutions.fairdata.fdp.index.storage.StorageConfig; +import com.github.mongobee.changeset.ChangeLog; +import com.github.mongobee.changeset.ChangeSet; +import com.mongodb.client.MongoDatabase; -@Configuration -@ComponentScan -@Import(StorageConfig.class) -public class ServiceConfig { +@ChangeLog +public class DatabaseChangeLog { + @ChangeSet(order = "000", id = "initMongoDB", author = "MarekSuchanek") + public void initMongoDB(MongoDatabase db) { + // Nothing to DO, just "first" making the version + } } diff --git a/src/main/java/solutions/fairdata/fdp/index/storage/package-info.java b/src/main/java/solutions/fairdata/fdp/index/database/changelogs/package-info.java similarity index 95% rename from src/main/java/solutions/fairdata/fdp/index/storage/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/database/changelogs/package-info.java index e91d278..38b7667 100644 --- a/src/main/java/solutions/fairdata/fdp/index/storage/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/database/changelogs/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.storage; +package solutions.fairdata.fdp.index.database.changelogs; diff --git a/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java b/src/main/java/solutions/fairdata/fdp/index/database/repository/EntryRepository.java similarity index 76% rename from src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java rename to src/main/java/solutions/fairdata/fdp/index/database/repository/EntryRepository.java index 427a2c7..4dc3cc9 100644 --- a/src/main/java/solutions/fairdata/fdp/index/storage/EntryRepository.java +++ b/src/main/java/solutions/fairdata/fdp/index/database/repository/EntryRepository.java @@ -20,10 +20,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.storage; +package solutions.fairdata.fdp.index.database.repository; -import org.springframework.data.repository.PagingAndSortingRepository; -import solutions.fairdata.fdp.index.domain.IndexEntry; +import org.springframework.data.mongodb.repository.MongoRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; -public interface EntryRepository extends PagingAndSortingRepository { +import java.util.Optional; + +public interface EntryRepository extends MongoRepository { + Optional findByClientUrl(String clientUrl); } diff --git a/src/main/java/solutions/fairdata/fdp/index/domain/package-info.java b/src/main/java/solutions/fairdata/fdp/index/database/repository/package-info.java similarity index 95% rename from src/main/java/solutions/fairdata/fdp/index/domain/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/database/repository/package-info.java index 5e812c8..90e4a79 100644 --- a/src/main/java/solutions/fairdata/fdp/index/domain/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/database/repository/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.domain; +package solutions.fairdata.fdp.index.database.repository; diff --git a/src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java b/src/main/java/solutions/fairdata/fdp/index/entity/IndexEntry.java similarity index 86% rename from src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java rename to src/main/java/solutions/fairdata/fdp/index/entity/IndexEntry.java index d963e8a..63dc7f6 100644 --- a/src/main/java/solutions/fairdata/fdp/index/domain/IndexEntry.java +++ b/src/main/java/solutions/fairdata/fdp/index/entity/IndexEntry.java @@ -20,16 +20,19 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.domain; +package solutions.fairdata.fdp.index.entity; -import org.springframework.data.annotation.Id; -import org.springframework.data.redis.core.RedisHash; import lombok.Data; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; -@RedisHash("entries") +@Document @Data public class IndexEntry { - @Id private String clientUrl; + @Id + protected ObjectId id; + private String clientUrl; private String registrationTime; private String modificationTime; } diff --git a/src/main/java/solutions/fairdata/fdp/index/app/package-info.java b/src/main/java/solutions/fairdata/fdp/index/entity/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/fdp/index/app/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/entity/package-info.java index 7f69d59..c1bffb3 100644 --- a/src/main/java/solutions/fairdata/fdp/index/app/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/entity/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.app; +package solutions.fairdata.fdp.index.entity; diff --git a/src/main/java/solutions/fairdata/fdp/index/api/package-info.java b/src/main/java/solutions/fairdata/fdp/index/package-info.java similarity index 96% rename from src/main/java/solutions/fairdata/fdp/index/api/package-info.java rename to src/main/java/solutions/fairdata/fdp/index/package-info.java index ce0e3bb..800cb4f 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/package-info.java +++ b/src/main/java/solutions/fairdata/fdp/index/package-info.java @@ -22,4 +22,4 @@ */ @javax.annotation.ParametersAreNonnullByDefault -package solutions.fairdata.fdp.index.api; +package solutions.fairdata.fdp.index; diff --git a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java b/src/main/java/solutions/fairdata/fdp/index/service/IndexEntryService.java similarity index 86% rename from src/main/java/solutions/fairdata/fdp/index/service/IndexService.java rename to src/main/java/solutions/fairdata/fdp/index/service/IndexEntryService.java index 1725238..ae7c4bc 100644 --- a/src/main/java/solutions/fairdata/fdp/index/service/IndexService.java +++ b/src/main/java/solutions/fairdata/fdp/index/service/IndexEntryService.java @@ -22,28 +22,29 @@ */ package solutions.fairdata.fdp.index.service; -import java.time.OffsetDateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Component; -import solutions.fairdata.fdp.index.api.dto.EntryDTO; -import solutions.fairdata.fdp.index.domain.IndexEntry; -import solutions.fairdata.fdp.index.storage.EntryRepository; +import solutions.fairdata.fdp.index.api.dto.IndexEntryDTO; +import solutions.fairdata.fdp.index.database.repository.EntryRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; + +import java.time.OffsetDateTime; @Component -public class IndexService { - private static final Logger logger = LoggerFactory.getLogger(IndexService.class); - +public class IndexEntryService { + private static final Logger logger = LoggerFactory.getLogger(IndexEntryService.class); + @Autowired private EntryRepository repository; - + public void storeEntry(String clientUrl) { - var entity = repository.findById(clientUrl); + var entity = repository.findByClientUrl(clientUrl); var now = OffsetDateTime.now(); - + final IndexEntry entry; if (entity.isPresent()) { logger.info("Updating timestamp of existing entry {}", clientUrl); @@ -54,11 +55,11 @@ public void storeEntry(String clientUrl) { entry.setClientUrl(clientUrl); entry.setRegistrationTime(now.toString()); } - + entry.setModificationTime(now.toString()); repository.save(entry); } - + public Iterable getAllEntries() { return repository.findAll(); } @@ -67,8 +68,8 @@ public Page getEntriesPage(Pageable pageable) { return repository.findAll(pageable); } - public EntryDTO toDTO(IndexEntry indexEntry) { - EntryDTO dto = new EntryDTO(); + public IndexEntryDTO toDTO(IndexEntry indexEntry) { + IndexEntryDTO dto = new IndexEntryDTO(); dto.setClientUrl(indexEntry.getClientUrl()); dto.setRegistrationTime(OffsetDateTime.parse(indexEntry.getRegistrationTime())); dto.setModificationTime(OffsetDateTime.parse(indexEntry.getModificationTime())); diff --git a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java index 49b24f5..a1d8516 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java @@ -24,19 +24,18 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; -import org.springframework.data.web.PageableDefault; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import solutions.fairdata.fdp.index.service.IndexService; +import solutions.fairdata.fdp.index.service.IndexEntryService; @Controller @RequestMapping("/") public class HomeController { @Autowired - private IndexService service; - + private IndexEntryService service; + @GetMapping public String home(Model model, Pageable pageable) { model.addAttribute("entries", service.getEntriesPage(pageable)); diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 0000000..b04014a --- /dev/null +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,29 @@ +{ + "properties": [ + { + "name": "fdp-index.api.url", + "type": "java.lang.String", + "description": "Server URL where API is running" + }, + { + "name": "fdp-index.api.title", + "type": "java.lang.String", + "description": "Title for OpenAPI docs" + }, + { + "name": "fdp-index.api.description", + "type": "java.lang.String", + "description": "Description for OpenAPI docs" + }, + { + "name": "fdp-index.api.contactUrl", + "type": "java.lang.String", + "description": "Contact URL for OpenAPI docs" + }, + { + "name": "fdp-index.api.contactName", + "type": "java.lang.String", + "description": "Contact name/label for OpenAPI docs" + } + ] +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index d330e6b..0000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,7 +0,0 @@ -spring.data.web.pageable.size-parameter=size -spring.data.web.pageable.page-parameter=page -spring.data.web.pageable.default-page-size=50 -spring.data.web.pageable.one-indexed-parameters=true -spring.data.web.pageable.max-page-size=2000 -spring.data.web.pageable.prefix= -spring.data.web.pageable.qualifier-delimiter=_ diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..700fc47 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,21 @@ +spring: + data: + mongodb: + uri: mongodb://localhost:27017/fdp-index + web: + pageable: + size-parameter: size + page-parameter: page + default-page-size: 50 + one-indexed-parameters: true + max-page-size: 2000 + prefix: + qualifier-delimiter: _ + +fdp-index: + api: + # url: + title: FAIR Data Point Index API + description: This is OpenAPI specification of FAIR Data Point Index REST API. + contactUrl: https://github.com/FAIRDataTeam/FAIRDataPoint-index + contactName: GitHub repository diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..40c09c3 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,16 @@ + + + + %d %-4relative [%thread] %-5level %logger{35} - %msg%n + + + + + + + + + + + + diff --git a/src/main/resources/static/js/localize-timestamps.js b/src/main/resources/static/js/localize-timestamps.js index 6b33195..f7835b7 100644 --- a/src/main/resources/static/js/localize-timestamps.js +++ b/src/main/resources/static/js/localize-timestamps.js @@ -1,5 +1,5 @@ jQuery(document).ready(() => { - jQuery("td.timestamp").each(function() { + jQuery("td.timestamp").each(function () { const dt = new Date($(this).text()); $(this).text(dt.toLocaleString("en-GB")); }); diff --git a/src/main/resources/templates/fragments/footer.html b/src/main/resources/templates/fragments/footer.html index 2da1e4b..7888c76 100644 --- a/src/main/resources/templates/fragments/footer.html +++ b/src/main/resources/templates/fragments/footer.html @@ -3,7 +3,7 @@
- FAIR Data Team © 2020 + FAIR Data Team © 2020
diff --git a/src/main/resources/templates/fragments/header.html b/src/main/resources/templates/fragments/header.html index 5f87394..997fc6b 100644 --- a/src/main/resources/templates/fragments/header.html +++ b/src/main/resources/templates/fragments/header.html @@ -4,7 +4,7 @@
- +

FAIR Data Point index

diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 0a213aa..7fb68cf 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -1,12 +1,12 @@ + xmlns:th="http://thymeleaf.org">
- +
@@ -17,40 +17,46 @@ - - + +
Endpoint
- +

- entries in total + entries in total
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index fa50a8c..a24b7b5 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -1,21 +1,21 @@ - + - - FAIR Data Point index - + xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" + xmlns:th="http://thymeleaf.org"> + + FAIR Data Point index + - - - - -
-
+ + + + +
+
-
+
-
-
- +
+
+ diff --git a/src/main/scss/site.scss b/src/main/scss/site.scss index ba897d3..65e0d8b 100644 --- a/src/main/scss/site.scss +++ b/src/main/scss/site.scss @@ -54,6 +54,7 @@ footer div.container { table.entries td.endpoint { overflow-wrap: anywhere; } + table.entries td.timestamp, table.entries th.right { text-align: right; diff --git a/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java b/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java new file mode 100644 index 0000000..0fbc071 --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java @@ -0,0 +1,51 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index; + +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.data.mongodb.core.MongoTemplate; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; + +@ExtendWith(SpringExtension.class) +@ActiveProfiles(Profiles.TESTING) +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT, + properties = {"spring.main.allow-bean-definition-overriding=true"}) +@AutoConfigureMockMvc +public abstract class WebIntegrationTest { + + @Autowired + protected MongoTemplate mongoTemplate; + + @Autowired + protected MockMvc mvc; + + @Autowired + protected TestRestTemplate client; +} diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java new file mode 100644 index 0000000..e4ef9e9 --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java @@ -0,0 +1,137 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.acceptance.api.entries; + +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.data.mongodb.core.MongoTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import solutions.fairdata.fdp.index.WebIntegrationTest; +import solutions.fairdata.fdp.index.api.dto.IndexEntryDTO; +import solutions.fairdata.fdp.index.database.repository.EntryRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; +import solutions.fairdata.fdp.index.fixtures.IndexEntryFixtures; + +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; + +public class EntriesAll_GET extends WebIntegrationTest { + + @Autowired + private EntryRepository entryRepository; + @Autowired + private MongoTemplate mongoTemplate; + + private URI url() { + return URI.create("/entries/all"); + } + + @Test + @DisplayName("HTTP 200: list empty") + public void res200_listEmpty() { + // GIVEN (prepare data) + mongoTemplate.getDb().drop(); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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) + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesFew(); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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) + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(300); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java new file mode 100644 index 0000000..bae581b --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java @@ -0,0 +1,227 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.acceptance.api.entries; + +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 solutions.fairdata.fdp.index.WebIntegrationTest; +import solutions.fairdata.fdp.index.api.dto.IndexEntryDTO; +import solutions.fairdata.fdp.index.database.repository.EntryRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; +import solutions.fairdata.fdp.index.fixtures.IndexEntryFixtures; +import solutions.fairdata.fdp.index.utils.CustomPageImpl; + +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; + + +public class EntriesPage_GET extends WebIntegrationTest { + + @Autowired + private EntryRepository entryRepository; + + private URI url() { + return URI.create("/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) + mongoTemplate.getDb().drop(); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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) + mongoTemplate.getDb().drop(); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(urlWithPage(7)) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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) + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesFew(); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(url()) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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) + Integer items = 300; + int size = 30; + int page = 3; + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(items); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(urlWithPageSize(page, size)) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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.longValue()))); + 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) + Integer items = 666; + int size = 300; + int lastSize = 66; + int page = 3; + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(items); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestEntity request = RequestEntity + .get(urlWithPageSize(page, size)) + .accept(MediaType.APPLICATION_JSON) + .build(); + ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity> 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.longValue()))); + assertThat("There is correct number of entries in the response", result.getBody().getContent().size(), is(equalTo(lastSize))); + } +} diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java new file mode 100644 index 0000000..dce70f0 --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java @@ -0,0 +1,179 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.acceptance.api.ping; + +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.data.mongodb.core.MongoTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import solutions.fairdata.fdp.index.WebIntegrationTest; +import solutions.fairdata.fdp.index.api.dto.PingDTO; +import solutions.fairdata.fdp.index.database.repository.EntryRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; +import solutions.fairdata.fdp.index.fixtures.IndexEntryFixtures; + +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; + +public class ReceivePing_POST extends WebIntegrationTest { + + @Autowired + private EntryRepository entryRepository; + @Autowired + private MongoTemplate mongoTemplate; + + 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_newEnty() { + // GIVEN (prepare data) + String clientUrl = "http://example.com"; + mongoTemplate.getDb().drop(); + PingDTO reqDto = reqDTO(clientUrl); + + // AND (prepare request) + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + assertThat("Entry does not exist before the ping", entryRepository.findByClientUrl(clientUrl).isPresent(), is(Boolean.FALSE)); + ResponseEntity 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", entryRepository.findByClientUrl(clientUrl).isPresent(), is(Boolean.TRUE)); + } + + @Test + @DisplayName("HTTP 204: existing entry") + public void res204_existingEnty() { + // GIVEN (prepare data) + IndexEntry indexEntry = IndexEntryFixtures.entryExample(); + String clientUrl = indexEntry.getClientUrl(); + mongoTemplate.getDb().drop(); + PingDTO reqDto = reqDTO(clientUrl); + + // AND (prepare request) + RequestEntity request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + entryRepository.save(indexEntry); + assertThat("Entry exists before the ping", entryRepository.findByClientUrl(clientUrl).isPresent(), is(Boolean.TRUE)); + ResponseEntity 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", entryRepository.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 request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity 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 request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(reqDto); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity 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 dummyData = new HashMap<>(); + dummyData.put("content", "http://test"); + + // AND (prepare request) + RequestEntity> request = RequestEntity + .post(url()) + .accept(MediaType.APPLICATION_JSON) + .body(dummyData); + ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { + }; + + // WHEN + ResponseEntity 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/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java new file mode 100644 index 0000000..e7de234 --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java @@ -0,0 +1,227 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.acceptance.web.home; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.RequestBuilder; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.web.util.UriComponentsBuilder; +import solutions.fairdata.fdp.index.WebIntegrationTest; +import solutions.fairdata.fdp.index.database.repository.EntryRepository; +import solutions.fairdata.fdp.index.entity.IndexEntry; +import solutions.fairdata.fdp.index.fixtures.IndexEntryFixtures; + +import java.net.URI; +import java.util.List; + +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +public class Home_GET extends WebIntegrationTest { + + @Autowired + private EntryRepository entryRepository; + + private URI url() { + return URI.create("/"); + } + + private URI urlWithPageSize(int page, int size) { + return UriComponentsBuilder.fromUri(url()) + .queryParam("page", page) + .queryParam("size", size) + .build().toUri(); + } + + @Test + @DisplayName("HTTP 200: empty table") + public void res200_emptyTable() throws Exception { + // GIVEN (prepare data) + mongoTemplate.getDb().drop(); + + // AND (prepare request) + RequestBuilder request = MockMvcRequestBuilders + .get(url()) + .accept(MediaType.TEXT_HTML); + + // WHEN + ResultActions result = mvc.perform(request); + + // THEN + result + .andExpect(status().isOk()) + .andExpect(view().name("home")) + .andExpect(xpath("//table[@id='entries']/thead/tr").exists()) + .andExpect(xpath("//table[@id='entries']/tbody/tr").doesNotExist()) + .andExpect(xpath("//span[@id='totalEntries']").string("0")) + .andExpect(xpath("//span[@id='currentPage']").string("1")) + .andExpect(xpath("//span[@id='totalPages']").string("1")) + .andExpect(xpath("//*[@id='firstPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='previousPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='nextPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='lastPage']/a").doesNotExist()); + } + + @Test + @DisplayName("HTTP 200: single page") + public void res200_singlePage() throws Exception { + // GIVEN (prepare data) + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesFew(); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestBuilder request = MockMvcRequestBuilders + .get(url()) + .accept(MediaType.TEXT_HTML); + + // WHEN + ResultActions result = mvc.perform(request); + + // THEN + result + .andExpect(status().isOk()) + .andExpect(view().name("home")) + .andExpect(xpath("//table[@id='entries']/thead/tr").exists()) + .andExpect(xpath("//table[@id='entries']/tbody/tr").nodeCount(entries.size())) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a").string(entries.get(0).getClientUrl())) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a/@href").string(entries.get(0).getClientUrl())) + .andExpect(xpath("//span[@id='totalEntries']").string(String.valueOf(entries.size()))) + .andExpect(xpath("//span[@id='currentPage']").string("1")) + .andExpect(xpath("//span[@id='totalPages']").string("1")) + .andExpect(xpath("//*[@id='firstPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='previousPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='nextPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='lastPage']/a").doesNotExist()); + } + + @Test + @DisplayName("HTTP 200: first page of many") + public void res200_firstPageOfMany() throws Exception { + // GIVEN (prepare data) + int items = 333; + int size = 50; + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(items); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestBuilder request = MockMvcRequestBuilders + .get(urlWithPageSize(1, size)) + .accept(MediaType.TEXT_HTML); + + // WHEN + ResultActions result = mvc.perform(request); + + // THEN + result + .andExpect(status().isOk()) + .andExpect(view().name("home")) + .andExpect(xpath("//table[@id='entries']/thead/tr").exists()) + .andExpect(xpath("//table[@id='entries']/tbody/tr").nodeCount(size)) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a").string(entries.get(0).getClientUrl())) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a/@href").string(entries.get(0).getClientUrl())) + .andExpect(xpath("//span[@id='totalEntries']").string(String.valueOf(items))) + .andExpect(xpath("//span[@id='currentPage']").string("1")) + .andExpect(xpath("//span[@id='totalPages']").string("7")) + .andExpect(xpath("//*[@id='firstPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='previousPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='nextPage']/a").exists()) + .andExpect(xpath("//*[@id='lastPage']/a").exists()); + } + + @Test + @DisplayName("HTTP 200: last page of many") + public void res200_lastPageOfMany() throws Exception { + // GIVEN (prepare data) + int items = 333; + int size = 50; + int page = 7; + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(items); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestBuilder request = MockMvcRequestBuilders + .get(urlWithPageSize(page, size)) + .accept(MediaType.TEXT_HTML); + + // WHEN + ResultActions result = mvc.perform(request); + + // THEN + result + .andExpect(status().isOk()) + .andExpect(view().name("home")) + .andExpect(xpath("//table[@id='entries']/thead/tr").exists()) + .andExpect(xpath("//table[@id='entries']/tbody/tr").nodeCount(33)) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a").string(entries.get((page - 1) * size).getClientUrl())) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a/@href").string(entries.get((page - 1) * size).getClientUrl())) + .andExpect(xpath("//span[@id='totalEntries']").string(String.valueOf(items))) + .andExpect(xpath("//span[@id='currentPage']").string(String.valueOf(page))) + .andExpect(xpath("//span[@id='totalPages']").string(String.valueOf(page))) + .andExpect(xpath("//*[@id='firstPage']/a").exists()) + .andExpect(xpath("//*[@id='previousPage']/a").exists()) + .andExpect(xpath("//*[@id='nextPage']/a").doesNotExist()) + .andExpect(xpath("//*[@id='lastPage']/a").doesNotExist()); + } + + @Test + @DisplayName("HTTP 200: middle page of many") + public void res200_middlePageOfMany() throws Exception { + // GIVEN (prepare data) + int items = 333; + int size = 50; + int page = 4; + mongoTemplate.getDb().drop(); + List entries = IndexEntryFixtures.entriesN(items); + entryRepository.saveAll(entries); + + // AND (prepare request) + RequestBuilder request = MockMvcRequestBuilders + .get(urlWithPageSize(page, size)) + .accept(MediaType.TEXT_HTML); + + // WHEN + ResultActions result = mvc.perform(request); + + // THEN + result + .andExpect(status().isOk()) + .andExpect(view().name("home")) + .andExpect(xpath("//table[@id='entries']/thead/tr").exists()) + .andExpect(xpath("//table[@id='entries']/tbody/tr").nodeCount(size)) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a").string(entries.get((page - 1) * size).getClientUrl())) + .andExpect(xpath("//table[@id='entries']/tbody/tr[1]/td[@class='endpoint']/a/@href").string(entries.get((page - 1) * size).getClientUrl())) + .andExpect(xpath("//span[@id='totalEntries']").string(String.valueOf(items))) + .andExpect(xpath("//span[@id='currentPage']").string(String.valueOf(page))) + .andExpect(xpath("//span[@id='totalPages']").string(String.valueOf(7))) + .andExpect(xpath("//*[@id='firstPage']/a").exists()) + .andExpect(xpath("//*[@id='previousPage']/a").exists()) + .andExpect(xpath("//*[@id='nextPage']/a").exists()) + .andExpect(xpath("//*[@id='lastPage']/a").exists()); + } +} diff --git a/src/test/java/solutions/fairdata/fdp/index/fixtures/IndexEntryFixtures.java b/src/test/java/solutions/fairdata/fdp/index/fixtures/IndexEntryFixtures.java new file mode 100644 index 0000000..71485b5 --- /dev/null +++ b/src/test/java/solutions/fairdata/fdp/index/fixtures/IndexEntryFixtures.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright © 2020 https://fairdata.solutions + * + * 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 solutions.fairdata.fdp.index.fixtures; + +import solutions.fairdata.fdp.index.entity.IndexEntry; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class IndexEntryFixtures { + + private static final String TIMESTAMP = "2020-01-01T00:00:00Z"; + + private static IndexEntry newIndexEntry(String clientUrl) { + IndexEntry indexEntry = new IndexEntry(); + indexEntry.setClientUrl(clientUrl); + indexEntry.setModificationTime(TIMESTAMP); + indexEntry.setRegistrationTime(TIMESTAMP); + return indexEntry; + } + + public static IndexEntry entryExample() { + return newIndexEntry("http://example.com"); + } + + public static List entriesFew() { + return Arrays.asList( + newIndexEntry("http://example.com"), + newIndexEntry("http://test.com"), + newIndexEntry("http://localhost") + ); + } + + public static List entriesN(int n) { + ArrayList entries = new ArrayList<>(); + for (int i = 0; i < n; i++) { + entries.add(newIndexEntry("http://example" + i + ".com")); + } + return entries; + } +} diff --git a/src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java b/src/test/java/solutions/fairdata/fdp/index/utils/CustomPageImpl.java similarity index 55% rename from src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java rename to src/test/java/solutions/fairdata/fdp/index/utils/CustomPageImpl.java index 55322db..48ed58c 100644 --- a/src/main/java/solutions/fairdata/fdp/index/api/ApiConfig.java +++ b/src/test/java/solutions/fairdata/fdp/index/utils/CustomPageImpl.java @@ -20,15 +20,43 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package solutions.fairdata.fdp.index.api; +package solutions.fairdata.fdp.index.utils; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import solutions.fairdata.fdp.index.service.ServiceConfig; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +import java.util.List; + +@Data +@JsonIgnoreProperties(ignoreUnknown = true) +public class CustomPageImpl { + + 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 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; + } -@Configuration -@ComponentScan -@Import(ServiceConfig.class) -public class ApiConfig { } diff --git a/src/test/resources/application-testing.yml b/src/test/resources/application-testing.yml new file mode 100644 index 0000000..fe07ea1 --- /dev/null +++ b/src/test/resources/application-testing.yml @@ -0,0 +1,4 @@ +spring: + data: + mongodb: + uri: mongodb://localhost:27017/fdp-index-test diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml new file mode 100644 index 0000000..f830fe7 --- /dev/null +++ b/src/test/resources/log4j2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + From 90bc2da393df608ac7aaf71afb3216e151441034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 8 Jun 2020 08:24:33 +0200 Subject: [PATCH 17/22] [INDEX-5] Allow to specify table sort and page size (#6) --- .../index/FairDataPointIndexApplication.java | 1 - .../index/web/controller/HomeController.java | 10 +++- src/main/resources/static/img/fair_logo.png | Bin 1416 -> 12357 bytes src/main/resources/static/img/favicon.png | Bin 0 -> 9770 bytes src/main/resources/templates/home.html | 54 +++++++++++++++--- src/main/resources/templates/layout.html | 1 + src/main/scss/site.scss | 14 +++++ 7 files changed, 70 insertions(+), 10 deletions(-) create mode 100644 src/main/resources/static/img/favicon.png diff --git a/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java index e65a42f..760ed04 100644 --- a/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java +++ b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java @@ -24,7 +24,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; @SpringBootApplication(scanBasePackages = {"solutions.fairdata.fdp.index"}) public class FairDataPointIndexApplication { diff --git a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java index a1d8516..074247f 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java @@ -24,12 +24,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.SortDefault; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import solutions.fairdata.fdp.index.service.IndexEntryService; +import java.util.Optional; + @Controller @RequestMapping("/") public class HomeController { @@ -37,8 +41,12 @@ public class HomeController { private IndexEntryService service; @GetMapping - public String home(Model model, Pageable pageable) { + public String home(Model model, @SortDefault(sort = "modificationTime", direction = Sort.Direction.DESC) Pageable pageable) { + Optional order = pageable.getSort().stream().findFirst(); + String sort = order.map(o -> o.getProperty() + "," + o.getDirection().name().toLowerCase()).orElse(""); + model.addAttribute("entries", service.getEntriesPage(pageable)); + model.addAttribute("sort", sort); return "home"; } } diff --git a/src/main/resources/static/img/fair_logo.png b/src/main/resources/static/img/fair_logo.png index d9926e4d85ebb64db147b3da497740899db00252..3e9b8eb56ee6105bdafaeb1f287c7a7e6dd5ea22 100644 GIT binary patch literal 12357 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 - Endpoint - Registration - Modification + + Endpoint + + + + + Registration + + + + + Modification + + + @@ -25,18 +37,18 @@
-
+
entries in total
+
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+ + +
+
+
+
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index a24b7b5..0c6d0f6 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -5,6 +5,7 @@ FAIR Data Point index + diff --git a/src/main/scss/site.scss b/src/main/scss/site.scss index 65e0d8b..9f8f843 100644 --- a/src/main/scss/site.scss +++ b/src/main/scss/site.scss @@ -59,3 +59,17 @@ table.entries td.timestamp, table.entries th.right { text-align: right; } + +a.sort-link:hover { + text-decoration: none; +} + +a.sort-link { + color: $secondary; + text-decoration: none; +} + +a.sort-link.active { + color: $primary; + text-decoration: none; +} From de300c14f7535e0b26d11dd96df55fc2eba262e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 15 Jun 2020 14:11:49 +0200 Subject: [PATCH 18/22] Prepare for v0.1.0 release --- CHANGELOG.md | 21 +++++++++++++++++++++ pom.xml | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5f2af25 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0] + +Initial version for simple list of FAIR Data Points. + +### Added + +- Endpoint for "call home" ping and storing entries in MongoDB +- REST API to retrieve entries list (both all and paged) documented using Swagger/OpenAPI +- Simple webpage with table to browse entries including sorting and pagination + +[Unreleased]: /../../compare/v0.1.0...develop +[0.1.0]: /../../tree/v0.1.0 diff --git a/pom.xml b/pom.xml index 788b2fe..e8326c6 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,7 @@ solutions.fairdata fairdatapoint-index - 0.1.0-SNAPSHOT + 0.1.0 2020 From cc3d50f707f9163f9b839e113ae1e4238240f794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 15 Jun 2020 18:03:45 +0200 Subject: [PATCH 19/22] Simplify getting sort order for view Co-authored-by: kburger <6997485+kburger@users.noreply.github.com> --- .../fairdata/fdp/index/web/controller/HomeController.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java index 074247f..0bb5151 100644 --- a/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java +++ b/src/main/java/solutions/fairdata/fdp/index/web/controller/HomeController.java @@ -42,8 +42,10 @@ public class HomeController { @GetMapping public String home(Model model, @SortDefault(sort = "modificationTime", direction = Sort.Direction.DESC) Pageable pageable) { - Optional order = pageable.getSort().stream().findFirst(); - String sort = order.map(o -> o.getProperty() + "," + o.getDirection().name().toLowerCase()).orElse(""); + var sort = pageable.getSort().stream() + .findFirst() + .map(o -> o.getProperty() + "," + o.getDirection().name().toLowerCase()) + .orElse(""); model.addAttribute("entries", service.getEntriesPage(pageable)); model.addAttribute("sort", sort); From ed9157d66f947ef17de4eae26e56a03df4dd783d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 15 Jun 2020 21:27:50 +0200 Subject: [PATCH 20/22] Add CORS config --- .../solutions/fairdata/fdp/index/config/WebConfig.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java b/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java index 0405dde..5f4c086 100644 --- a/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java +++ b/src/main/java/solutions/fairdata/fdp/index/config/WebConfig.java @@ -23,8 +23,16 @@ package solutions.fairdata.fdp.index.config; import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration +@EnableWebMvc public class WebConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**"); + } } From b74fc0ccbc6a711666c0b0965502c52bc0f1720f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 15 Jun 2020 21:29:05 +0200 Subject: [PATCH 21/22] Update+simplify Spring and tests --- pom.xml | 2 +- .../index/FairDataPointIndexApplication.java | 2 +- src/main/resources/templates/home.html | 6 +++--- .../fairdata/fdp/index/WebIntegrationTest.java | 1 + ...iesAll_GET.java => EntriesAll_GET_Test.java} | 11 ++++------- ...sPage_GET.java => EntriesPage_GET_Test.java} | 17 +++++------------ ...ing_POST.java => ReceivePing_POST_Test.java} | 15 ++++----------- .../home/{Home_GET.java => Home_GET_Test.java} | 3 ++- 8 files changed, 21 insertions(+), 36 deletions(-) rename src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/{EntriesAll_GET.java => EntriesAll_GET_Test.java} (92%) rename src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/{EntriesPage_GET.java => EntriesPage_GET_Test.java} (93%) rename src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/{ReceivePing_POST.java => ReceivePing_POST_Test.java} (91%) rename src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/{Home_GET.java => Home_GET_Test.java} (99%) diff --git a/pom.xml b/pom.xml index e8326c6..f9356c7 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ org.springframework.boot spring-boot-starter-parent - 2.2.5.RELEASE + 2.2.7.RELEASE diff --git a/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java index 760ed04..e518374 100644 --- a/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java +++ b/src/main/java/solutions/fairdata/fdp/index/FairDataPointIndexApplication.java @@ -25,7 +25,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -@SpringBootApplication(scanBasePackages = {"solutions.fairdata.fdp.index"}) +@SpringBootApplication public class FairDataPointIndexApplication { public static void main(String[] args) { SpringApplication.run(FairDataPointIndexApplication.class, args); diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 2df03aa..3d36838 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -78,7 +78,7 @@
- +
@@ -86,14 +86,14 @@
- +
- +
diff --git a/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java b/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java index 0fbc071..fadbb65 100644 --- a/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java +++ b/src/test/java/solutions/fairdata/fdp/index/WebIntegrationTest.java @@ -23,6 +23,7 @@ package solutions.fairdata.fdp.index; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET_Test.java similarity index 92% rename from src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java rename to src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET_Test.java index e4ef9e9..ee4ac2b 100644 --- a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET.java +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesAll_GET_Test.java @@ -45,13 +45,16 @@ import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.notNullValue; -public class EntriesAll_GET extends WebIntegrationTest { +@DisplayName("GET /entries/all") +public class EntriesAll_GET_Test extends WebIntegrationTest { @Autowired private EntryRepository entryRepository; @Autowired private MongoTemplate mongoTemplate; + private final ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() {}; + private URI url() { return URI.create("/entries/all"); } @@ -67,8 +70,6 @@ public void res200_listEmpty() { .get(url()) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -92,8 +93,6 @@ public void res200_listFew() { .get(url()) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -120,8 +119,6 @@ public void res200_listMany() { .get(url()) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET_Test.java similarity index 93% rename from src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java rename to src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET_Test.java index bae581b..0331579 100644 --- a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET.java +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/entries/EntriesPage_GET_Test.java @@ -25,6 +25,7 @@ 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.HttpStatus; import org.springframework.http.MediaType; @@ -46,12 +47,14 @@ import static org.hamcrest.core.IsEqual.equalTo; import static org.hamcrest.core.IsNull.notNullValue; - -public class EntriesPage_GET extends WebIntegrationTest { +@DisplayName("GET /entries") +public class EntriesPage_GET_Test extends WebIntegrationTest { @Autowired private EntryRepository entryRepository; + private final ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() {}; + private URI url() { return URI.create("/entries"); } @@ -80,8 +83,6 @@ public void res200_pageEmpty() { .get(url()) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -108,8 +109,6 @@ public void res200_outOfBoundsPage() { .get(urlWithPage(7)) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -138,8 +137,6 @@ public void res200_pageFew() { .get(url()) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -174,8 +171,6 @@ public void res200_pageManyMiddle() { .get(urlWithPageSize(page, size)) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); @@ -208,8 +203,6 @@ public void res200_pageManyLast() { .get(urlWithPageSize(page, size)) .accept(MediaType.APPLICATION_JSON) .build(); - ParameterizedTypeReference> responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity> result = client.exchange(request, responseType); diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST_Test.java similarity index 91% rename from src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java rename to src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST_Test.java index dce70f0..c46fa80 100644 --- a/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST.java +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/api/ping/ReceivePing_POST_Test.java @@ -44,13 +44,16 @@ import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsEqual.equalTo; -public class ReceivePing_POST extends WebIntegrationTest { +@DisplayName("POST /ping") +public class ReceivePing_POST_Test extends WebIntegrationTest { @Autowired private EntryRepository entryRepository; @Autowired private MongoTemplate mongoTemplate; + private final ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() {}; + private URI url() { return URI.create("/"); } @@ -74,8 +77,6 @@ public void res204_newEnty() { .post(url()) .accept(MediaType.APPLICATION_JSON) .body(reqDto); - ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { - }; // WHEN assertThat("Entry does not exist before the ping", entryRepository.findByClientUrl(clientUrl).isPresent(), is(Boolean.FALSE)); @@ -100,8 +101,6 @@ public void res204_existingEnty() { .post(url()) .accept(MediaType.APPLICATION_JSON) .body(reqDto); - ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { - }; // WHEN entryRepository.save(indexEntry); @@ -124,8 +123,6 @@ public void res400_nullClientUrl() { .post(url()) .accept(MediaType.APPLICATION_JSON) .body(reqDto); - ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity result = client.exchange(request, responseType); @@ -145,8 +142,6 @@ public void res400_nonUrlClientUrl() { .post(url()) .accept(MediaType.APPLICATION_JSON) .body(reqDto); - ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity result = client.exchange(request, responseType); @@ -167,8 +162,6 @@ public void res400_differentBody() { .post(url()) .accept(MediaType.APPLICATION_JSON) .body(dummyData); - ParameterizedTypeReference responseType = new ParameterizedTypeReference<>() { - }; // WHEN ResponseEntity result = client.exchange(request, responseType); diff --git a/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java b/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET_Test.java similarity index 99% rename from src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java rename to src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET_Test.java index e7de234..c5db9c6 100644 --- a/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET.java +++ b/src/test/java/solutions/fairdata/fdp/index/acceptance/web/home/Home_GET_Test.java @@ -40,7 +40,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -public class Home_GET extends WebIntegrationTest { +@DisplayName("Browse /") +public class Home_GET_Test extends WebIntegrationTest { @Autowired private EntryRepository entryRepository; From e494a68194e7a2ae90584f870954e2c96dfa5e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Such=C3=A1nek?= Date: Mon, 15 Jun 2020 21:33:18 +0200 Subject: [PATCH 22/22] Use Zulu JDK in CI --- .github/workflows/main.yml | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 76714f8..53e0b2d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,8 +15,6 @@ jobs: TAG_DEVELOP: develop TAG_LATEST: latest JDK_VERSION: 11 - JDK_FILE: openjdk-11.0.2_linux-x64_bin.tar.gz - JDK_URL: https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz services: mongo: @@ -37,25 +35,13 @@ jobs: path: ~/.m2 key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - - name: Cache JDK folder - uses: actions/cache@v1 - with: - path: ~/jdk - key: ${{ env.JDK_FILE }} - # (2) -> Prepare Java - - name: Download Oracle JDK - run: | - if [ ! -f ~/jdk/$JDK_FILE ]; then - wget --quiet $JDK_URL -O ~/jdk/$JDK_FILE - fi - cp ~/jdk/$JDK_FILE . - - name: Setup Java - uses: actions/setup-java@master + uses: actions/setup-java@v1 with: - version: ${{ env.JDK_VERSION }} - jdkFile: ${{ env.JDK_FILE }} + java-version: ${{ env.JDK_VERSION }} + java-package: jdk + architecture: x64 - name: Verify Maven and Java run: | @@ -64,11 +50,11 @@ jobs: # (3) -> Test and build - name: Run tests run: | - mvn --quiet -U -B org.jacoco:jacoco-maven-plugin:prepare-agent test + mvn -U -B org.jacoco:jacoco-maven-plugin:prepare-agent test - name: Build package and verify run: | - mvn --quiet -B -U --fail-fast -DskipTests tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify + mvn -U -B --fail-fast -DskipTests tidy:check com.github.spotbugs:spotbugs-maven-plugin:check license:check verify # (4) -> Build Docker image - name: Docker build