diff --git a/docker-compose.yml b/docker-compose.yml index 500a55a6fb21fed63c69840e7b65526def3ddadd..145696a4497ef93ae6d761550ae7a97a8c6b803a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -122,6 +122,25 @@ services: logging: driver: json-file + fda-document-service: + restart: on-failure + container_name: fda-document-service + hostname: fda-document-service + build: ./fda-document-service + image: fda-document-service + networks: + fda-public: + environment: + SPRING_PROFILES_ACTIVE: docker + TZ: Europe/Vienna + ports: + - "9099:9099" + depends_on: + fda-discovery-service: + condition: service_healthy + logging: + driver: json-file + fda-authentication-service: restart: on-failure container_name: fda-authentication-service diff --git a/fda-document-service/.gitignore b/fda-document-service/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..cf45e2b44c0bdcd00a8a3e1640f092bc9f946db5 --- /dev/null +++ b/fda-document-service/.gitignore @@ -0,0 +1,37 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### Generated ### +ready +service_ready + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea/ +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/fda-document-service/Dockerfile b/fda-document-service/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..93015fd61a17e46e5ebeb67da9f2004837dece9e --- /dev/null +++ b/fda-document-service/Dockerfile @@ -0,0 +1,33 @@ +###### FIRST STAGE ###### +FROM fda-metadata-db:latest as dependency +MAINTAINER Martin Weise <martin.weise@tuwien.ac.at> + +###### SECOND STAGE ###### +FROM maven:slim as build + +COPY ./pom.xml ./ + +RUN mvn -fn -B dependency:go-offline > /dev/null + +COPY --from=dependency /root/.m2/repository/at/tuwien /root/.m2/repository/at/tuwien + +COPY ./rest-service ./rest-service +COPY ./services ./services +COPY ./report ./report + +# Make sure it compiles +RUN mvn -q clean package -DskipTests > /dev/null + +###### THIRD STAGE ###### +FROM openjdk:11-jre-slim as runtime + +COPY ./service_ready /usr/bin +RUN chmod +x /usr/bin/service_ready + +HEALTHCHECK --interval=10s --timeout=5s --retries=12 CMD service_ready + +COPY --from=build ./rest-service/target/rest-service-*.jar ./rest-service.jar + +EXPOSE 9099 + +ENTRYPOINT ["java", "-Dlog4j2.formatMsgNoLookups=true", "-jar", "./rest-service.jar"] diff --git a/fda-document-service/README.md b/fda-document-service/README.md new file mode 100644 index 0000000000000000000000000000000000000000..afa0452aece523062f5fb095cb14409667ef2f74 --- /dev/null +++ b/fda-document-service/README.md @@ -0,0 +1,7 @@ +# FDA Document Service + +## Documentation + +- OpenAPI v3: http://localhost:9099/swagger-ui/index.html +- OpenAPI v3 endpoint: http://localhost:9099/v3/api-docs/ +- OpenAPI v3 YAML: http://localhost:9099/v3/api-docs.yaml \ No newline at end of file diff --git a/fda-document-service/mvnw b/fda-document-service/mvnw new file mode 100755 index 0000000000000000000000000000000000000000..a16b5431b4c3cab50323a3f558003fd0abd87dad --- /dev/null +++ b/fda-document-service/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/fda-document-service/mvnw.cmd b/fda-document-service/mvnw.cmd new file mode 100644 index 0000000000000000000000000000000000000000..c8d43372c986d97911cdc21bd87e0cbe3d83bdda --- /dev/null +++ b/fda-document-service/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/fda-document-service/pom.xml b/fda-document-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..c53a944f5803686f4cea695623aa1655eb00c23c --- /dev/null +++ b/fda-document-service/pom.xml @@ -0,0 +1,208 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-parent</artifactId> + <version>2.3.10.RELEASE</version> + </parent> + + <groupId>at.tuwien</groupId> + <artifactId>fda-document-service</artifactId> + <version>1.1.0-alpha</version> + <name>fda-document-service</name> + <description>Demo project for Spring Boot</description> + + <packaging>pom</packaging> + <modules> + <module>rest-service</module> + <module>services</module> + <module>report</module> + </modules> + + <properties> + <java.version>11</java.version> + <spring-cloud.version>3.0.1</spring-cloud.version> + <mapstruct.version>1.4.2.Final</mapstruct.version> + <docker.version>3.2.7</docker.version> + <testcontainers.version>1.15.2</testcontainers.version> + <swagger.version>2.1.7</swagger.version> + <jacoco.version>0.8.7</jacoco.version> + <sqlserver.version>9.2.1.jre11</sqlserver.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + </dependency> + <dependency><!-- https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#validation-starter-no-longer-included-in-web-starters --> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-validation</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.cloud</groupId> + <artifactId>spring-cloud-starter-bootstrap</artifactId> + <version>${spring-cloud.version}</version> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.security</groupId> + <artifactId>spring-security-test</artifactId> + <scope>test</scope> + </dependency> + <!-- Data Source --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-data-jpa</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.data</groupId> + <artifactId>spring-data-elasticsearch</artifactId> + </dependency> + <!-- Entity and API --> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>fda-metadata-db-api</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>fda-metadata-db-entites</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> + <!-- DataSource --> + <dependency> + <groupId>org.postgresql</groupId> + <artifactId>postgresql</artifactId> + <version>${postgresql.version}</version> + </dependency> + <dependency> + <groupId>org.mariadb.jdbc</groupId> + <artifactId>mariadb-java-client</artifactId> + <version>${mariadb.version}</version> + </dependency> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + <version>${mysql.version}</version> + </dependency> + <dependency> + <groupId>com.microsoft.sqlserver</groupId> + <artifactId>mssql-jdbc</artifactId> + <version>${sqlserver.version}</version> + </dependency> + <!-- Testing --> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + <exclusions> + <exclusion> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-vintage-engine</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + </dependency> + <!-- IDE --> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + </dependency> + <!-- Docker --> + <dependency> + <groupId>com.github.docker-java</groupId> + <artifactId>docker-java</artifactId> + <version>${docker.version}</version> + <exclusions> + <exclusion> + <groupId>javax.ws.rs</groupId> + <artifactId>jsr311-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>com.github.docker-java</groupId> + <artifactId>docker-java-transport-httpclient5</artifactId> + <version>${docker.version}</version> + </dependency> + <!-- Mapping --> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + <optional>true</optional><!-- IntelliJ --> + </dependency> + <dependency> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct</artifactId> + <version>${mapstruct.version}</version> + </dependency> + </dependencies> + + <build> + <resources> + <resource> + <directory>${basedir}/src/main/resources</directory> + <filtering>true</filtering> + <includes> + <include>**/application*.yml</include> + </includes> + </resource> + </resources> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <configuration> + <excludes> + <exclude>at/tuwien/utils/**/*</exclude> + <exclude>at/tuwien/handlers/**/*</exclude> + <exclude>at/tuwien/seeder/**/*</exclude> + <exclude>at/tuwien/mapper/**/*</exclude> + <exclude>at/tuwien/exception/**/*</exclude> + <exclude>at/tuwien/config/**/*</exclude> + <exclude>**/FdaContainerManagingApplication.class</exclude> + </excludes> + </configuration> + <executions> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> diff --git a/fda-document-service/report/pom.xml b/fda-document-service/report/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..a2aa61fbb830c24d05265bdb3e75de0f058cee40 --- /dev/null +++ b/fda-document-service/report/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-document-service</artifactId> + <version>1.1.0-alpha</version> + </parent> + + <artifactId>report</artifactId> + <version>1.1.0-alpha</version> + <name>fda-document-service-report</name> + <description> + This module is only intended for the pipeline coverage report. See the detailed report in the + respective modules + </description> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <dependencies> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>rest-service</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>services</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>${jacoco.version}</version> + <executions> + <execution> + <id>report-aggregate</id> + <phase>verify</phase> + <goals> + <goal>report-aggregate</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-document-service/rest-service/pom.xml b/fda-document-service/rest-service/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd42b4e61d672a739038fce699fb8f7ba6e09992 --- /dev/null +++ b/fda-document-service/rest-service/pom.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.tuwien</groupId> + <artifactId>fda-document-service</artifactId> + <version>1.1.0-alpha</version> + </parent> + + <artifactId>rest-service</artifactId> + <version>1.1.0-alpha</version> + <name>fda-document-service-rest-service</name> + + <properties> + <jacoco.version>0.8.7</jacoco.version> + </properties> + + <dependencies> + <dependency> + <groupId>at.tuwien</groupId> + <artifactId>services</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-maven-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>repackage</goal><!-- to make it exuteable with $ java -jar ./app.jar --> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/FdaDocumentManagingApplication.java b/fda-document-service/rest-service/src/main/java/at/tuwien/FdaDocumentManagingApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..582259d7d3685b4954e8f70263e0ed66b83e5a98 --- /dev/null +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/FdaDocumentManagingApplication.java @@ -0,0 +1,23 @@ +package at.tuwien; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@SpringBootApplication +@EnableJpaAuditing +@EnableTransactionManagement +@EnableElasticsearchRepositories(basePackages = {"at.tuwien.repository.elastic"}) +@EnableJpaRepositories(basePackages = {"at.tuwien.repository.jpa"}) +@EntityScan(basePackages = {"at.tuwien.entities"}) +public class FdaDocumentManagingApplication { + + public static void main(String[] args) { + SpringApplication.run(FdaDocumentManagingApplication.class, args); + } + +} diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java b/fda-document-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..3bdf7daf401e7ff161b3a1ea43db70ad74f601e9 --- /dev/null +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/config/SwaggerConfig.java @@ -0,0 +1,48 @@ +package at.tuwien.config; + +import io.swagger.v3.oas.models.ExternalDocumentation; +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 org.springdoc.core.GroupedOpenApi; +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 SwaggerConfig { + + @Value("${app.version:unknown}") + private String version; + + @Bean + public OpenAPI springShopOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("Database Repository Document Service API") + .contact(new Contact() + .name("Prof. Andreas Rauber") + .email("andreas.rauber@tuwien.ac.at")) + .description("Service that manages the documents") + .version(version) + .license(new License() + .name("Apache 2.0") + .url("https://www.apache.org/licenses/LICENSE-2.0"))) + .externalDocs(new ExternalDocumentation() + .description("Wiki Documentation") + .url("https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/wikis")); + } + + @Bean + public GroupedOpenApi publicApi() { + return GroupedOpenApi.builder() + .group("document-service") + .pathsToMatch("/api/**") + .build(); + } + +} diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java new file mode 100644 index 0000000000000000000000000000000000000000..2436b9748bc4e11979c02f8f947e99e481da8287 --- /dev/null +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/endpoints/DocumentEndpoint.java @@ -0,0 +1,71 @@ +package at.tuwien.endpoints; + +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.exception.DraftRecordCreateException; +import at.tuwien.service.DocumentService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.security.Principal; + + +@Log4j2 +@RestController +@CrossOrigin(origins = "*") +@ControllerAdvice +@RequestMapping("/api/document") +public class DocumentEndpoint { + + private final DocumentService documentService; + + @Autowired + public DocumentEndpoint(DocumentService documentService) { + this.documentService = documentService; + } + + @PostMapping + @PreAuthorize("hasRole('ROLE_RESEARCHER')") + @Transactional(readOnly = true) + @Operation(summary = "Create a draft", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<DraftDto> create(@NotNull @Valid @RequestBody CreateDraftDto data, + @NotNull Principal principal) throws DraftRecordCreateException { + final DraftDto document = documentService.create(data, principal); + return ResponseEntity.status(HttpStatus.CREATED) + .body(document); + } + + @GetMapping("/{id}") + @PreAuthorize("hasRole('ROLE_RESEARCHER')") + @Transactional(readOnly = true) + @Operation(summary = "Find a draft", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<DraftDto> find(@NotNull @PathVariable("id") String documentId, + @NotNull Principal principal) throws DraftRecordCreateException { + final DraftDto document = documentService.findById(documentId, principal); + log.info("Found draft record with id {}", documentId); + log.debug("found draft record {}", document); + return ResponseEntity.status(HttpStatus.OK) + .body(document); + } + + @PostMapping("/{id}") + @PreAuthorize("hasRole('ROLE_RESEARCHER')") + @Transactional(readOnly = true) + @Operation(summary = "Reserve draft DOI", security = @SecurityRequirement(name = "bearerAuth")) + public ResponseEntity<DraftDto> reserve(@NotNull @PathVariable("id") String documentId, + @NotNull Principal principal) throws DraftRecordCreateException { + final DraftDto document = documentService.reserveDoi(documentId, principal); + return ResponseEntity.status(HttpStatus.CREATED) + .body(document); + } + +} diff --git a/fda-document-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java b/fda-document-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..8941436966d303f9360cda96ecfa94e59c17c942 --- /dev/null +++ b/fda-document-service/rest-service/src/main/java/at/tuwien/handlers/ApiExceptionHandler.java @@ -0,0 +1,28 @@ +package at.tuwien.handlers; + +import at.tuwien.api.error.ApiErrorDto; +import at.tuwien.exception.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; + +@ControllerAdvice +public class ApiExceptionHandler extends ResponseEntityExceptionHandler { + + @ResponseStatus(HttpStatus.EXPECTATION_FAILED) + @ExceptionHandler(DraftRecordCreateException.class) + public ResponseEntity<ApiErrorDto> handle(DraftRecordCreateException e, WebRequest request) { + final ApiErrorDto response = ApiErrorDto.builder() + .status(HttpStatus.EXPECTATION_FAILED) + .message(e.getLocalizedMessage()) + .code("error.document.create") + .build(); + return new ResponseEntity<>(response, new HttpHeaders(), response.getStatus()); + } + +} \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/resources/application-docker.yml b/fda-document-service/rest-service/src/main/resources/application-docker.yml new file mode 100644 index 0000000000000000000000000000000000000000..46f56dc08b4dff9989e3e1d942e2253678759f7a --- /dev/null +++ b/fda-document-service/rest-service/src/main/resources/application-docker.yml @@ -0,0 +1,34 @@ +app.version: '@project.version@' +spring: + main.banner-mode: off + datasource: + url: jdbc:postgresql://fda-metadata-db:5432/fda + driver-class-name: org.postgresql.Driver + username: postgres + password: postgres + jpa: + show-sql: false + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: validate + open-in-view: false + application: + name: fda-document-service + cloud: + loadbalancer.ribbon.enabled: false +server.port: 9099 +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: warn + at.tuwien.: debug + at.tuwien.gateway.: trace + org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug +eureka: + instance.hostname: fda-document-service + client.serviceUrl.defaultZone: http://fda-discovery-service:9090/eureka/ +fda: + mount.path: /tmp + ready.path: /ready + document.endpoint: https://test.researchdata.tuwien.ac.at +dev.token: "${TOKEN}" \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/resources/application.yml b/fda-document-service/rest-service/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..47db505983d03a94640962f3b394da6c91bd3ac7 --- /dev/null +++ b/fda-document-service/rest-service/src/main/resources/application.yml @@ -0,0 +1,35 @@ +app.version: '@project.version@' +spring: + main.banner-mode: off + datasource: + url: jdbc:postgresql://localhost:5432/fda + driver-class-name: org.postgresql.Driver + username: postgres + password: postgres + jpa: + show-sql: false + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: validate + open-in-view: false + application: + name: fda-document-service + cloud: + loadbalancer.ribbon.enabled: false +springdoc.swagger-ui.enabled: true +server.port: 9099 +logging: + pattern.console: "%d %highlight(%-5level) %msg%n" + level: + root: warn + at.tuwien.: debug + at.tuwien.gateway.: trace + org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver: debug +eureka: + instance.hostname: fda-document-service + client.serviceUrl.defaultZone: http://localhost:9090/eureka/ +fda: + mount.path: /tmp + ready.path: ./ready + document.endpoint: https://test.researchdata.tuwien.ac.at +dev.token: "${TOKEN}" \ No newline at end of file diff --git a/fda-document-service/rest-service/src/main/resources/config.properties b/fda-document-service/rest-service/src/main/resources/config.properties new file mode 100644 index 0000000000000000000000000000000000000000..e993ed9c62272ab86ae23a64f6195f21e465216f --- /dev/null +++ b/fda-document-service/rest-service/src/main/resources/config.properties @@ -0,0 +1 @@ +# https://github.com/Netflix/Hystrix/issues/275 \ No newline at end of file diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7f4f0cc7ebc0635d6e11bbccd62c25dbae8dd6da --- /dev/null +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/BaseUnitTest.java @@ -0,0 +1,81 @@ +package at.tuwien; + +import at.tuwien.api.document.metadata.*; +import at.tuwien.api.document.record.*; +import org.springframework.test.context.TestPropertySource; + +import java.time.Instant; +import java.util.Date; +import java.util.List; + +@TestPropertySource(locations = "classpath:application.properties") +public abstract class BaseUnitTest { + + public final static String USER_1_USERNAME = "junit"; + + public final static AccessTypeDto DOCUMENT_1_RECORD_TYPE = AccessTypeDto.PUBLIC; + public final static FileTypeDto DOCUMENT_1_FILE_TYPE = FileTypeDto.PUBLIC; + + public final static AccessOptionsDto DOCUMENT_1_ACCESS_OPTIONS = AccessOptionsDto.builder() + .record(DOCUMENT_1_RECORD_TYPE) + .files(DOCUMENT_1_FILE_TYPE) + .build(); + + public final static Boolean DOCUMENT_1_FILES_ENABLED = true; + + public final static FilesOptionsDto DOCUMENT_1_FILES_OPTIONS = FilesOptionsDto.builder() + .enabled(DOCUMENT_1_FILES_ENABLED) + .build(); + + public final static String DOCUMENT_1_TITLE = "Test Draft"; + public final static String DOCUMENT_1_RESOURCE_TYPE_TYPE = "other"; + public final static Date DOCUMENT_1_PUBLICATION_DATE = Date.from(Instant.now()); + + public final static ResourceTypeDto DOCUMENT_1_RESOURCE_TYPE = ResourceTypeDto.builder() + .id(DOCUMENT_1_RESOURCE_TYPE_TYPE) + .build(); + + public final static String IDENTIFIER_1_IDENTIFIER = "0000-0003-4216-302X"; + public final static IdentifierTypeDto IDENTIFIER_1_TYPE = IdentifierTypeDto.ORCID; + + public final static IdentifierDto IDENTIFIER_1 = IdentifierDto.builder() + .identifier(IDENTIFIER_1_IDENTIFIER) + .scheme(IDENTIFIER_1_TYPE) + .build(); + + public final static String PERSON_1_GIVEN_NAME = "Martin"; + public final static String PERSON_1_FAMILY_NAME = "Weise"; + public final static String PERSON_1_NAME = "Weise, Martin"; + public final static PersonOrOrgTypeDto PERSON_1_TYPE = PersonOrOrgTypeDto.PERSONAL; + + public final static PersonOrOrganizationDto PERSON_1 = PersonOrOrganizationDto.builder() + .givenName(PERSON_1_GIVEN_NAME) + .familyName(PERSON_1_FAMILY_NAME) + .name(PERSON_1_NAME) + .type(PERSON_1_TYPE) + .identifiers(List.of(IDENTIFIER_1)) + .build(); + + public final static AffiliationDto AFFILIATION_1 = AffiliationDto.builder() + .name("TU Wien") + .build(); + + public final static CreatorDto CREATOR_1 = CreatorDto.builder() + .personOrOrganization(PERSON_1) + .affiliations(List.of(AFFILIATION_1)) + .build(); + + public final static MetadataDto DOCUMENT_1_METADATA = MetadataDto.builder() + .title(DOCUMENT_1_TITLE) + .resourceType(DOCUMENT_1_RESOURCE_TYPE) + .publicationDate(DOCUMENT_1_PUBLICATION_DATE) + .creators(List.of(CREATOR_1)) + .build(); + + public final static CreateDraftDto DOCUMENT_1_CREATE_DRAFT = CreateDraftDto.builder() + .access(DOCUMENT_1_ACCESS_OPTIONS) + .files(DOCUMENT_1_FILES_OPTIONS) + .metadata(DOCUMENT_1_METADATA) + .build(); + +} diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0965a30b1e3fe46573e7e50f798b044d9af81cc4 --- /dev/null +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/endpoint/DocumentEndpointUnitTest.java @@ -0,0 +1,13 @@ +package at.tuwien.endpoint; + +import at.tuwien.BaseUnitTest; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest +public class DocumentEndpointUnitTest extends BaseUnitTest { + + +} diff --git a/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentEndpointIntegrationTest.java b/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentEndpointIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e62b5d378c6e62952fd88929cf7e43bd169fb062 --- /dev/null +++ b/fda-document-service/rest-service/src/test/java/at/tuwien/service/DocumentEndpointIntegrationTest.java @@ -0,0 +1,55 @@ +package at.tuwien.service; + +import at.tuwien.BaseUnitTest; +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.exception.DraftRecordCreateException; +import lombok.extern.log4j.Log4j2; +import org.apache.http.auth.BasicUserPrincipal; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.security.Principal; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Log4j2 +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +@ExtendWith(SpringExtension.class) +@SpringBootTest +public class DocumentEndpointIntegrationTest extends BaseUnitTest { + + @Autowired + private DocumentService documentService; + + @Test + public void create_succeeds() throws DraftRecordCreateException { + final CreateDraftDto request = DOCUMENT_1_CREATE_DRAFT; + final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); + + /* mock */ + + /* test */ + final DraftDto response = documentService.create(request, principal); + assertEquals(DOCUMENT_1_TITLE, response.getMetadata().getTitle()); + } + + @Test + public void reserve_succeeds() throws DraftRecordCreateException { + final CreateDraftDto request = DOCUMENT_1_CREATE_DRAFT; + final Principal principal = new BasicUserPrincipal(USER_1_USERNAME); + + /* mock */ + + /* test */ + final DraftDto document = documentService.create(request, principal); + final DraftDto response = documentService.reserveDoi(document.getId(), principal); + assertNotNull(response.getPids().getDoi()); + } + +} diff --git a/fda-document-service/rest-service/src/test/resources/application.properties b/fda-document-service/rest-service/src/test/resources/application.properties new file mode 100644 index 0000000000000000000000000000000000000000..1f8a9f4089f393b2a8d25f28472a80a35658aab5 --- /dev/null +++ b/fda-document-service/rest-service/src/test/resources/application.properties @@ -0,0 +1,15 @@ +# disable discovery +spring.cloud.discovery.enabled = false + +# disable cloud config and config discovery +spring.cloud.config.discovery.enabled = false +spring.cloud.config.enabled = false + +# disable datasource +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=false \ No newline at end of file diff --git a/fda-document-service/services/pom.xml b/fda-document-service/services/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..556e2833e894c562c2186e885368323d805142dd --- /dev/null +++ b/fda-document-service/services/pom.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <artifactId>fda-document-service</artifactId> + <groupId>at.tuwien</groupId> + <version>1.1.0-alpha</version> + </parent> + + <artifactId>services</artifactId> + <version>1.1.0-alpha</version> + <name>fda-document-service-services</name> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + <annotationProcessorPaths> + <path> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>${lombok.version}</version> + </path> + <!-- keep this order https://stackoverflow.com/questions/47676369/mapstruct-and-lombok-not-working-together#answer-65021876 --> + <path> + <groupId>org.mapstruct</groupId> + <artifactId>mapstruct-processor</artifactId> + <version>${mapstruct.version}</version> + </path> + </annotationProcessorPaths> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java b/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..e33f0dba4dddf90216af08dbb5ec98b184fbf6f6 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/auth/AuthTokenFilter.java @@ -0,0 +1,58 @@ +package at.tuwien.auth; + +import at.tuwien.gateway.AuthenticationServiceGateway; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.util.StringUtils; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Slf4j +public class AuthTokenFilter extends OncePerRequestFilter { + + private final AuthenticationServiceGateway authenticationServiceGateway; + + public AuthTokenFilter(AuthenticationServiceGateway authenticationServiceGateway) { + this.authenticationServiceGateway = authenticationServiceGateway; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + final String jwt = parseJwt(request); + if (jwt != null) { + final UserDetails userDetails = authenticationServiceGateway.validate(jwt); + log.info("Authenticated user with username {} and authorities {}", userDetails.getUsername(), + userDetails.getAuthorities()); + log.debug("authenticated user {}", userDetails); + final UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + + SecurityContextHolder.getContext().setAuthentication(authentication); + } + filterChain.doFilter(request, response); + } + + /** + * Parses the token from the HTTP header of the request + * + * @param request The request. + * @return The token. + */ + private String parseJwt(HttpServletRequest request) { + String headerAuth = request.getHeader("Authorization"); + if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) { + return headerAuth.substring(7, headerAuth.length()); + } + return null; + } +} \ No newline at end of file diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..006541ad8cd45351c455e1bf03b4c546acf3a6e8 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/config/GatewayConfig.java @@ -0,0 +1,22 @@ +package at.tuwien.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.DefaultUriBuilderFactory; + +@Configuration +public class GatewayConfig { + + @Value("${fda.document.endpoint}") + private String documentEndpoint; + + @Bean + public RestTemplate restTemplate() { + final RestTemplate restTemplate = new RestTemplate(); + restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory(documentEndpoint)); + return restTemplate; + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/InvenioConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/InvenioConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..98aa6731f87e383a472acfc579f08b819e1e0dc1 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/config/InvenioConfig.java @@ -0,0 +1,15 @@ +package at.tuwien.config; + +import lombok.Getter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + + +@Getter +@Configuration +public class InvenioConfig { + + @Value("${dev.token}") + private String debugToken; + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/ReadyConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/ReadyConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..2250fa50884df3f47b0b063975aea74f06203f80 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/config/ReadyConfig.java @@ -0,0 +1,25 @@ +package at.tuwien.config; + +import com.google.common.io.Files; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.EventListener; + +import java.io.File; +import java.io.IOException; + +@Log4j2 +@Configuration +public class ReadyConfig { + + @Value("${fda.ready.path}") + private String readyPath; + + @EventListener(ApplicationReadyEvent.class) + public void init() throws IOException { + Files.touch(new File(readyPath)); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java b/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..70dac68fcd138939eaa08a33a7789bd5830b369d --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/config/WebSecurityConfig.java @@ -0,0 +1,93 @@ +package at.tuwien.config; + +import at.tuwien.auth.AuthTokenFilter; +import at.tuwien.gateway.AuthenticationServiceGateway; +import io.swagger.v3.oas.annotations.enums.SecuritySchemeType; +import io.swagger.v3.oas.annotations.security.SecurityScheme; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.http.HttpServletResponse; + +@Configuration +@EnableWebSecurity +@EnableGlobalMethodSecurity(prePostEnabled = true) +@SecurityScheme( + name = "bearerAuth", + type = SecuritySchemeType.HTTP, + bearerFormat = "JWT", + scheme = "bearer" +) +public class WebSecurityConfig extends WebSecurityConfigurerAdapter { + + private final AuthenticationServiceGateway authenticationServiceGateway; + + @Autowired + public WebSecurityConfig(AuthenticationServiceGateway authenticationServiceGateway) { + this.authenticationServiceGateway = authenticationServiceGateway; + } + + @Bean + public AuthTokenFilter authTokenFilter() { + return new AuthTokenFilter(authenticationServiceGateway); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + /* enable CORS and disable CSRF */ + http = http.cors().and().csrf().disable(); + /* set session management to stateless */ + http = http + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and(); + /* set unauthorized requests exception handler */ + http = http + .exceptionHandling() + .authenticationEntryPoint( + (request, response, ex) -> { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, + ex.getMessage() + ); + } + ).and(); + /* set permissions on endpoints */ + http.authorizeRequests() + /* our public endpoints */ + .antMatchers(HttpMethod.GET, "/api/document/**").permitAll() + .antMatchers("/v3/api-docs.yaml", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html").permitAll() + /* our private endpoints */ + .anyRequest().authenticated(); + /* add JWT token filter */ + http.addFilterBefore(authTokenFilter(), + UsernamePasswordAuthenticationFilter.class + ); + } + + @Bean + public CorsFilter corsFilter() { + final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + final CorsConfiguration config = new CorsConfiguration(); + config.setAllowCredentials(true); + config.addAllowedOrigin("*"); + config.addAllowedHeader("*"); + config.addAllowedMethod("*"); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/exception/DraftRecordCreateException.java b/fda-document-service/services/src/main/java/at/tuwien/exception/DraftRecordCreateException.java new file mode 100644 index 0000000000000000000000000000000000000000..6b8e7337a1a74d8c3325ae362973d1c49ec10930 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/exception/DraftRecordCreateException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.EXPECTATION_FAILED) +public class DraftRecordCreateException extends Exception { + + public DraftRecordCreateException(String msg) { + super(msg); + } + + public DraftRecordCreateException(String msg, Throwable thr) { + super(msg, thr); + } + + public DraftRecordCreateException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java new file mode 100644 index 0000000000000000000000000000000000000000..fc47ce246da851244cf1630b15f493ded20249d8 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/AuthenticationServiceGateway.java @@ -0,0 +1,14 @@ +package at.tuwien.gateway; + +import org.springframework.security.core.userdetails.UserDetails; + +public interface AuthenticationServiceGateway { + + /** + * Validates a token + * + * @param token The token + * @return User details on success + */ + UserDetails validate(String token); +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java new file mode 100644 index 0000000000000000000000000000000000000000..129d17a458811089db84e589c5b460f509ccfb58 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/DocumentGateway.java @@ -0,0 +1,13 @@ +package at.tuwien.gateway; + +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.exception.DraftRecordCreateException; + +public interface DocumentGateway { + DraftDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException; + + DraftDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException; + + DraftDto findDraft(String id, String token) throws DraftRecordCreateException; +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..56d691a6c825b473029c8f1dcd320c949cdcf177 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/AuthenticationServiceGatewayImpl.java @@ -0,0 +1,38 @@ +package at.tuwien.gateway.impl; + +import at.tuwien.api.user.UserDto; +import at.tuwien.gateway.AuthenticationServiceGateway; +import at.tuwien.mapper.UserMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Service +public class AuthenticationServiceGatewayImpl implements AuthenticationServiceGateway { + + private final UserMapper userMapper; + private final RestTemplate restTemplate; + + @Autowired + public AuthenticationServiceGatewayImpl(UserMapper userMapper, RestTemplate restTemplate) { + this.userMapper = userMapper; + this.restTemplate = restTemplate; + } + + @Override + public UserDetails validate(String token) { + final HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Bearer " + token); + final ResponseEntity<UserDto> response = restTemplate.exchange("/api/auth", HttpMethod.PUT, + new HttpEntity<>("", headers), UserDto.class); + return userMapper.userDtoToUserDetailsDto(response.getBody()); + } + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..18b9dcd0738ad6aaabcd04a9410df12041a6d7a8 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/gateway/impl/InvenioDocumentGatewayImpl.java @@ -0,0 +1,76 @@ +package at.tuwien.gateway.impl; + +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.exception.DraftRecordCreateException; +import at.tuwien.gateway.DocumentGateway; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.*; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +@Slf4j +@Component +public class InvenioDocumentGatewayImpl implements DocumentGateway { + + private RestTemplate restTemplate; + + @Autowired + public InvenioDocumentGatewayImpl(RestTemplate restTemplate) { + this.restTemplate = restTemplate; + } + + @Override + public DraftDto createDraft(CreateDraftDto data, String token) throws DraftRecordCreateException { + log.trace("sending {}", data); + final ResponseEntity<DraftDto> response; + try { + response = restTemplate.exchange("/api/records", HttpMethod.POST, + new HttpEntity<>(data, headers(token)), DraftDto.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to create draft record"); + throw new DraftRecordCreateException("Failed to create draft record", e); + } + return response.getBody(); + } + + @Override + public DraftDto reserveDraftDoi(String id, String token) throws DraftRecordCreateException { + final ResponseEntity<DraftDto> response; + try { + response = restTemplate.exchange("/api/records/" + id + "/draft/pids/doi", HttpMethod.POST, + new HttpEntity<>(null, headers(token)), DraftDto.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to reserve draft doi"); + throw new DraftRecordCreateException("Failed to reserve draft doi", e); + } + return response.getBody(); + } + + @Override + public DraftDto findDraft(String id, String token) throws DraftRecordCreateException { + final ResponseEntity<DraftDto> response; + try { + response = restTemplate.exchange("/api/records" + id +"/draft", HttpMethod.GET, + new HttpEntity<>(null, headers(token)), DraftDto.class); + } catch (HttpClientErrorException.BadRequest e) { + log.error("Failed to find draft record"); + throw new DraftRecordCreateException("Failed to create find record", e); + } + return response.getBody(); + } + + /** + * Prepares the headers for all requests to authorize with the bearer token. + * + * @param token The token. + * @return The headers. + */ + private HttpHeaders headers(String token) { + final HttpHeaders headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + token); + return headers; + } +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java b/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..0132073b6294cdb9be25a589d4d253fd06ed5b6c --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/mapper/DocumentMapper.java @@ -0,0 +1,10 @@ +package at.tuwien.mapper; + +import org.mapstruct.*; + + +@Mapper(componentModel = "spring") +public interface DocumentMapper { + + +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/mapper/UserMapper.java b/fda-document-service/services/src/main/java/at/tuwien/mapper/UserMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5620c8b3643c2face4747287e24483a56030f1f2 --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/mapper/UserMapper.java @@ -0,0 +1,21 @@ +package at.tuwien.mapper; + +import at.tuwien.api.user.GrantedAuthorityDto; +import at.tuwien.api.user.UserDetailsDto; +import at.tuwien.api.user.UserDto; +import at.tuwien.entities.user.User; +import org.mapstruct.Mapper; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +@Mapper(componentModel = "spring") +public interface UserMapper { + + UserDetailsDto userDtoToUserDetailsDto(UserDto data); + + UserDto userToUserDto(User data); + + default GrantedAuthority grantedAuthorityDtoToGrantedAuthority(GrantedAuthorityDto data) { + return new SimpleGrantedAuthority(data.getAuthority()); + } +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/repository/elastic/DatabaseRepository.java b/fda-document-service/services/src/main/java/at/tuwien/repository/elastic/DatabaseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..aa60a6dbbcdd124de8a38c4098ee43c7115df16f --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/repository/elastic/DatabaseRepository.java @@ -0,0 +1,9 @@ +package at.tuwien.repository.elastic; + +import at.tuwien.entities.database.Database; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; +import org.springframework.stereotype.Repository; + +@Repository(value = "ElasticDatabaseService") +public interface DatabaseRepository extends ElasticsearchRepository<Database, Long> { +} \ No newline at end of file diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java b/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java new file mode 100644 index 0000000000000000000000000000000000000000..48e0de0e77c8929ff76a987037f0417e150ff7bc --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/service/DocumentService.java @@ -0,0 +1,16 @@ +package at.tuwien.service; + +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.exception.DraftRecordCreateException; + +import java.security.Principal; + +public interface DocumentService { + + DraftDto findById(String id, Principal principal) throws DraftRecordCreateException; + + DraftDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException; + + DraftDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException; +} diff --git a/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDocumentServiceImpl.java b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDocumentServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..60682bcbccd2dc1e7f3eda4a8ee174485758ffae --- /dev/null +++ b/fda-document-service/services/src/main/java/at/tuwien/service/impl/InvenioDocumentServiceImpl.java @@ -0,0 +1,55 @@ +package at.tuwien.service.impl; + +import at.tuwien.api.document.record.CreateDraftDto; +import at.tuwien.api.document.record.DraftDto; +import at.tuwien.config.InvenioConfig; +import at.tuwien.exception.DraftRecordCreateException; +import at.tuwien.gateway.DocumentGateway; +import at.tuwien.service.DocumentService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.security.Principal; + +@Slf4j +@Service +public class InvenioDocumentServiceImpl implements DocumentService { + + private final DocumentGateway documentGateway; + private final InvenioConfig invenioConfig; + + @Autowired + public InvenioDocumentServiceImpl(DocumentGateway documentGateway, InvenioConfig invenioConfig) { + this.documentGateway = documentGateway; + this.invenioConfig = invenioConfig; + } + + @Override + public DraftDto findById(String id, Principal principal) throws DraftRecordCreateException { + /* get token */ + /* remote */ + return documentGateway.findDraft(id, invenioConfig.getDebugToken()); + } + + @Override + public DraftDto create(CreateDraftDto data, Principal principal) throws DraftRecordCreateException { + /* get token */ + /* remote */ + final DraftDto document = documentGateway.createDraft(data, invenioConfig.getDebugToken()); + log.info("Created draft record with id {}", document.getId()); + log.debug("created draft record {}", document); + return document; + } + + @Override + public DraftDto reserveDoi(String id, Principal principal) throws DraftRecordCreateException { + /* get token */ + /* remote */ + final DraftDto document = documentGateway.reserveDraftDoi(id, invenioConfig.getDebugToken()); + log.info("Reserved DOI {} for draft record with id {}", document.getPids().getDoi(), document.getId()); + log.debug("reserved PID {} for draft record with id {}", document.getPids(), document); + return document; + } + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DoiDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DoiDto.java new file mode 100644 index 0000000000000000000000000000000000000000..6fe993813def5001b3bb876504f493ec6f222352 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DoiDto.java @@ -0,0 +1,28 @@ +package at.tuwien.api.document.links; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotBlank; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DoiDto { + + @Parameter(name = "client") + private String client; + + @NotBlank(message = "identifier is required") + @Parameter(name = "identifier") + private String identifier; + + @Parameter(name = "provider") + private String provider; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DraftLinksDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DraftLinksDto.java new file mode 100644 index 0000000000000000000000000000000000000000..e3b14bcdc0e788c4ef6e5dd88f025927d25ed2e9 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/DraftLinksDto.java @@ -0,0 +1,42 @@ +package at.tuwien.api.document.links; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class DraftLinksDto { + + @Parameter(name = "latest") + private String latest; + + @Parameter(name = "versions") + private String versions; + + @JsonProperty("self_html") + @Parameter(name = "self html") + private String selfHtml; + + @Parameter(name = "publish") + private String publish; + + @JsonProperty("latest_html") + @Parameter(name = "latest html") + private String latestHtml; + + @Parameter(name = "self") + private String self; + + @Parameter(name = "files") + private String files; + + @JsonProperty("access_links") + @Parameter(name = "access links") + private String accessLinks; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/PersistentIdentifiersDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/PersistentIdentifiersDto.java new file mode 100644 index 0000000000000000000000000000000000000000..c7626b8c85c7a7a604140b1d9ae174f34ecf1959 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/links/PersistentIdentifiersDto.java @@ -0,0 +1,19 @@ +package at.tuwien.api.document.links; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class PersistentIdentifiersDto { + + @Parameter(name = "doi") + private DoiDto doi; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/AffiliationDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/AffiliationDto.java new file mode 100644 index 0000000000000000000000000000000000000000..b150e6138725a7ef84c350b598d6c81a3c677e9a --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/AffiliationDto.java @@ -0,0 +1,20 @@ +package at.tuwien.api.document.metadata; + +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class AffiliationDto { + + @Parameter(name = "id", description = "The organizational or institutional id from the controlled vocabulary.") + private String id; + + @Parameter(name = "name", description = "The name of the organisation or institution.") + private String name; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/CreatorDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/CreatorDto.java new file mode 100644 index 0000000000000000000000000000000000000000..5ead5d487c477829b90bc3cbc353395f33d827c5 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/CreatorDto.java @@ -0,0 +1,29 @@ +package at.tuwien.api.document.metadata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CreatorDto { + + @JsonProperty("person_or_org") + @NotNull(message = "person or organization is required") + @Parameter(name = "person or organization", description = "The person or organization.") + private PersonOrOrganizationDto personOrOrganization; + + @Parameter(name = "role", description = "The role of the person or organisation selected from a customizable " + + "controlled vocabulary.") + private String role; + + @Parameter(name = "affiliations", description = "Affilations if person_or_org.type is personal.") + private List<AffiliationDto> affiliations; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierDto.java new file mode 100644 index 0000000000000000000000000000000000000000..7ef178644d5abf23b3d7c58a5f488a571a026b7c --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierDto.java @@ -0,0 +1,23 @@ +package at.tuwien.api.document.metadata; + +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class IdentifierDto { + + @NotNull(message = "scheme is required") + @Parameter(name = "scheme", description = "The identifier scheme.") + private IdentifierTypeDto scheme; + + @NotNull(message = "identifier is required") + @Parameter(name = "identifier", description = "Actual value of the identifier.") + private String identifier; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..282aa63be67ca5a38e6273335a5b41f219317d82 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/IdentifierTypeDto.java @@ -0,0 +1,29 @@ +package at.tuwien.api.document.metadata; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum IdentifierTypeDto { + + @JsonProperty("orcid") + ORCID("orcid"), + + @JsonProperty("gnd") + GND("gnd"), + + @JsonProperty("isni") + ISNI("isni"), + + @JsonProperty("ror") + ROR("ror"); + + private final String type; + + IdentifierTypeDto(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/MetadataDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/MetadataDto.java new file mode 100644 index 0000000000000000000000000000000000000000..835a772307ffb0a01484933f34b3874348388802 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/MetadataDto.java @@ -0,0 +1,52 @@ +package at.tuwien.api.document.metadata; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.Date; +import java.util.List; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MetadataDto { + + @JsonProperty("resource_type") + @NotNull(message = "enabled is required") + @Parameter(name = "files enabled", description = "Should (and can) files be attached to this record or not.") + private ResourceTypeDto resourceType; + + /** + * The field is compatible with 2. Creator in DataCite. In addition we are adding the possiblity of associating a + * role (like for contributors). This is specifically for cases where e.g. an editor needs to be credited for the + * work, while authors of individual articles will be listed under contributors. + */ + @NotNull(message = "creators is required") + @Parameter(name = "creators") + private List<CreatorDto> creators; + + /** + * The fields is compatible with 3. Title in DataCite. Compared to DataCite, the field does not support specifying + * the language of the title. + */ + @NotBlank(message = "title is required") + @Parameter(name = "title") + private String title; + + /** + * The field is compatible 5. PublicationYear in DataCite. In case of time intervals, the earliest date is used + * for DataCite. + */ + @JsonProperty("publication_date") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "UTC+2") + @NotNull(message = "publication date is required") + @Parameter(name = "publication date") + private Date publicationDate; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrgTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrgTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..6eb4b9c2f3c9bc3e6420dedc1321e30f0e2dce8c --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrgTypeDto.java @@ -0,0 +1,23 @@ +package at.tuwien.api.document.metadata; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum PersonOrOrgTypeDto { + + @JsonProperty("personal") + PERSONAL("personal"), + + @JsonProperty("organizational") + ORGANIZATIONAL("organizational"); + + private final String type; + + PersonOrOrgTypeDto(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrganizationDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrganizationDto.java new file mode 100644 index 0000000000000000000000000000000000000000..67a5514de17cda902ba5544d7c62029aeddf987a --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/PersonOrOrganizationDto.java @@ -0,0 +1,35 @@ +package at.tuwien.api.document.metadata; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.List; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class PersonOrOrganizationDto { + + @NotNull(message = "type is required") + @Parameter(name = "type", description = "The type of name. Either personal or organizational.") + private PersonOrOrgTypeDto type; + + @JsonProperty("given_name") + @Parameter(name = "given name", description = "Given name(s).") + private String givenName; + + @JsonProperty("family_name") + @Parameter(name = "family name", description = "Family name.") + private String familyName; + + @Parameter(name = "name", description = "The full name of the organisation. For a person, this field is generated from given_name and family_name") + private String name; + + @Parameter(name = "identifers", description = "Person or organisation identifiers.") + private List<IdentifierDto> identifiers; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/ResourceTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/ResourceTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..7b6edacf87f54eb54d4e02dc897cf41bbdc5026a --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/metadata/ResourceTypeDto.java @@ -0,0 +1,24 @@ +package at.tuwien.api.document.metadata; + +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ResourceTypeDto { + + /** + * When interfacing with Datacite, this field is converted to a format compatible with 10. Resource Type (i.e. + * type and subtype). DataCite allows free text for the subtype, however InvenioRDM requires this to come from a + * customizable controlled vocabulary. + */ + @NotNull(message = "id is required") + @Parameter(name = "id", description = "The resource type id from the controlled vocabulary.") + private String id; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessOptionsDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessOptionsDto.java new file mode 100644 index 0000000000000000000000000000000000000000..fbb501c9d31c08f1006d524b294231ccbc3378bb --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessOptionsDto.java @@ -0,0 +1,29 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class AccessOptionsDto { + + @NotNull(message = "record access type is required") + @Parameter(name = "record access type") + private AccessTypeDto record; + + @NotNull(message = "files is required") + @Parameter(name = "files") + private FileTypeDto files; + + @Parameter(name = "embargo options") + private EmbargoDto embargo; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..9816ba4f9f5967f9551c8d788ac6c27dc21c9210 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/AccessTypeDto.java @@ -0,0 +1,23 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum AccessTypeDto { + + @JsonProperty("public") + PUBLIC("public"), + + @JsonProperty("restricted") + RESTRICTED("restricted"); + + private final String type; + + AccessTypeDto(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/CreateDraftDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/CreateDraftDto.java new file mode 100644 index 0000000000000000000000000000000000000000..623286d9a2e15c633ba7995712acf696295212b8 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/CreateDraftDto.java @@ -0,0 +1,31 @@ +package at.tuwien.api.document.record; + +import at.tuwien.api.document.metadata.MetadataDto; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class CreateDraftDto { + + @NotNull(message = "access is required") + @Parameter(name = "access") + private AccessOptionsDto access; + + @NotNull(message = "files options is required") + @Parameter(name = "files options") + private FilesOptionsDto files; + + @NotNull(message = "metadata is required") + @Parameter(name = "metadata") + private MetadataDto metadata; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java new file mode 100644 index 0000000000000000000000000000000000000000..d754f22fce839fe952e855fff31903dc0194dc27 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftDto.java @@ -0,0 +1,68 @@ +package at.tuwien.api.document.record; + +import at.tuwien.api.document.links.PersistentIdentifiersDto; +import at.tuwien.api.document.metadata.MetadataDto; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.time.Instant; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DraftDto { + + @NotNull(message = "access is required") + @Parameter(name = "access") + private AccessOptionsDto access; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + private Instant created; + + @JsonProperty("expires_at") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSS", timezone = "UTC+2") + private Instant expiresAt; + + @NotNull(message = "files options is required") + @Parameter(name = "files options") + private FilesOptionsDto files; + + @NotNull(message = "id is required") + @Parameter(name = "id") + private String id; + + @JsonProperty("is_published") + @NotNull(message = "is published is required") + @Parameter(name = "is published") + private Boolean isPublished; + + @NotNull(message = "metadata is required") + @Parameter(name = "metadata") + private MetadataDto metadata; + + @JsonProperty("revision_id") + @NotNull(message = "revision id is required") + @Parameter(name = "revision id") + private Long revisionId; + + @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX", timezone = "UTC+2") + @Parameter(name = "updated date") + private Instant updated; + + @NotNull(message = "versions is required") + @Parameter(name = "revisions") + private DraftVersionsDto versions; + + @NotNull(message = "pids is required") + @Parameter(name = "pids") + private PersistentIdentifiersDto pids; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftVersionsDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftVersionsDto.java new file mode 100644 index 0000000000000000000000000000000000000000..ae3109911b5bc2123757519e05ad2427aa56bacd --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/DraftVersionsDto.java @@ -0,0 +1,30 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DraftVersionsDto { + + @Parameter(name = "index") + private Long index; + + @JsonProperty("is_latest") + @Parameter(name = "is latest version") + private Boolean isLatest; + + @JsonProperty("is_latest_draft") + @Parameter(name = "is latest draft") + private Boolean isLatestDraft; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/EmbargoDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/EmbargoDto.java new file mode 100644 index 0000000000000000000000000000000000000000..82e417393a43cab4046b82251c97955e1436aa18 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/EmbargoDto.java @@ -0,0 +1,29 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class EmbargoDto { + + @NotNull(message = "embargo active is required") + @Parameter(name = "embargo active") + private Boolean active; + + @Parameter(name = "embargo until date") + private Date until; + + @Parameter(name = "embargo explanation") + private String reason; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FileTypeDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FileTypeDto.java new file mode 100644 index 0000000000000000000000000000000000000000..97536d9081beea03428adb89b02a97d5169f063f --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FileTypeDto.java @@ -0,0 +1,23 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum FileTypeDto { + + @JsonProperty("public") + PUBLIC("public"), + + @JsonProperty("restricted") + RESTRICTED("restricted"); + + private final String type; + + FileTypeDto(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FilesOptionsDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FilesOptionsDto.java new file mode 100644 index 0000000000000000000000000000000000000000..7ccebb72a644a29c53bcd463574fe8053c3919e4 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/FilesOptionsDto.java @@ -0,0 +1,24 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class FilesOptionsDto { + + @NotNull(message = "enabled is required") + @Parameter(name = "files enabled", description = "Should (and can) files be attached to this record or not.") + private Boolean enabled; + + @Parameter(name = "files preview", description = "Filename of file to be previewed by default.") + private String default_preview; +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/ModifyDraftDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/ModifyDraftDto.java new file mode 100644 index 0000000000000000000000000000000000000000..6e1a8af30e4c04c1e69bee201a1ef2b790f1c793 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/ModifyDraftDto.java @@ -0,0 +1,22 @@ +package at.tuwien.api.document.record; + +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class ModifyDraftDto { + + @NotNull(message = "identifier is required") + @Parameter(name = "identifier", description = "Identifier of the record, e.g. 4d0ns-ntd89") + private String id; + +} diff --git a/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/UpdateDraftDto.java b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/UpdateDraftDto.java new file mode 100644 index 0000000000000000000000000000000000000000..cce7e853f013fa2b7a069b42fcd8c82f79803437 --- /dev/null +++ b/fda-metadata-db/api/src/main/java/at/tuwien/api/document/record/UpdateDraftDto.java @@ -0,0 +1,35 @@ +package at.tuwien.api.document.record; + +import at.tuwien.api.document.metadata.MetadataDto; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.Parameter; +import lombok.*; + +import javax.validation.constraints.NotNull; + +@Getter +@Setter +@ToString +@Builder +@AllArgsConstructor +@NoArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) +public class UpdateDraftDto { + + @NotNull(message = "identifier is required") + @Parameter(name = "identifier", description = "Identifier of the record, e.g. 4d0ns-ntd89") + private String id; + + @NotNull(message = "access is required") + @Parameter(name = "access") + private AccessOptionsDto access; + + @NotNull(message = "files options is required") + @Parameter(name = "files options") + private FilesOptionsDto files; + + @NotNull(message = "metadata is required") + @Parameter(name = "metadata") + private MetadataDto metadata; + +}