From be52740c5312f5c6e5de0d97e7a9382c02e07488 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 12:51:01 +0200
Subject: [PATCH 01/31] Implement create project route
---
config/checkstyle/checkstyle-ignore.xml | 18 +-
config/checkstyle/checkstyle.xml | 46 +-
gradle/wrapper/gradle-wrapper.properties | 14 +-
gradlew | 504 +++++++++---------
.../config/OpenAPIConfiguration.java | 120 ++---
.../lf8_starter/project/GetProjectDto.java | 43 ++
.../project/dto/CreateProjectAction.java | 42 ++
.../security/KeycloakLogoutHandler.java | 98 ++--
.../resources/application-test.properties | 8 +-
.../Lf8StarterApplicationTests.java | 28 +-
10 files changed, 503 insertions(+), 418 deletions(-)
create mode 100644 src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
create mode 100644 src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
diff --git a/config/checkstyle/checkstyle-ignore.xml b/config/checkstyle/checkstyle-ignore.xml
index fe3b2fe..5ec61a5 100644
--- a/config/checkstyle/checkstyle-ignore.xml
+++ b/config/checkstyle/checkstyle-ignore.xml
@@ -1,9 +1,9 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index d8f0701..3c18de8 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -1,23 +1,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index df97d72..b9ddd88 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index f5feea6..ec19934 100755
--- a/gradlew
+++ b/gradlew
@@ -1,252 +1,252 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-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
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- if ! command -v java >/dev/null 2>&1
- then
- die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+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
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 1b2282b..76a6f58 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,60 +1,60 @@
-package de.szut.lf8_starter.config;
-
-
-
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-import jakarta.servlet.ServletContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-public class OpenAPIConfiguration {
-
- private ServletContext context;
-
- public OpenAPIConfiguration(ServletContext context) {
- this.context = context;
- }
-
-
- @Bean
- public OpenAPI springShopOpenAPI(
- // @Value("${info.app.version}") String appVersion,
- ) {
- final String securitySchemeName = "bearerAuth";
-
- return new OpenAPI()
- .addServersItem(new Server().url(this.context.getContextPath()))
- .info(new Info()
- .title("LF8 project starter")
- .description("\n## Auth\n" +
- "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
- "\n" +
- "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
- "\n" +
- "\nor by CURL\n" +
- "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
- "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
-
- .version("0.1"))
- .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
- .components(
- new Components()
- .addSecuritySchemes(securitySchemeName,
- new SecurityScheme()
- .name(securitySchemeName)
- .type(SecurityScheme.Type.HTTP)
- .scheme("bearer")
- .bearerFormat("JWT")
- )
- );
- }
-
-
-}
+package de.szut.lf8_starter.config;
+
+
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import jakarta.servlet.ServletContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class OpenAPIConfiguration {
+
+ private ServletContext context;
+
+ public OpenAPIConfiguration(ServletContext context) {
+ this.context = context;
+ }
+
+
+ @Bean
+ public OpenAPI springShopOpenAPI(
+ // @Value("${info.app.version}") String appVersion,
+ ) {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .addServersItem(new Server().url(this.context.getContextPath()))
+ .info(new Info()
+ .title("LF8 project starter")
+ .description("\n## Auth\n" +
+ "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
+ "\n" +
+ "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
+ "\n" +
+ "\nor by CURL\n" +
+ "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
+ "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
+
+ .version("0.1"))
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ .components(
+ new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
new file mode 100644
index 0000000..86ce087
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
@@ -0,0 +1,43 @@
+package de.szut.lf8_starter.project;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+public class GetProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
new file mode 100644
index 0000000..f1c6cdc
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
@@ -0,0 +1,42 @@
+package de.szut.lf8_starter.project.dto;
+
+import de.szut.lf8_starter.project.GetProjectDto;
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index 8555ef9..e06f2f7 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -1,49 +1,49 @@
-package de.szut.lf8_starter.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-@Slf4j
-@Component
-public class KeycloakLogoutHandler implements LogoutHandler {
-
-
- private final RestTemplate restTemplate;
-
- public KeycloakLogoutHandler(RestTemplate restTemplate) {
- this.restTemplate = restTemplate;
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(request, auth);
- }
-
- public void logout(HttpServletRequest request, Authentication auth) {
- logoutFromKeycloak((OidcUser) auth.getPrincipal());
- }
-
- private void logoutFromKeycloak(OidcUser user) {
- String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
- UriComponentsBuilder builder = UriComponentsBuilder
- .fromUriString(endSessionEndpoint)
- .queryParam("id_token_hint", user.getIdToken().getTokenValue());
-
- ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
- if (logoutResponse.getStatusCode().is2xxSuccessful()) {
- log.info("Successfulley logged out from Keycloak");
- } else {
- log.error("Could not propagate logout to Keycloak");
- }
- }
-
-}
+package de.szut.lf8_starter.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class KeycloakLogoutHandler implements LogoutHandler {
+
+
+ private final RestTemplate restTemplate;
+
+ public KeycloakLogoutHandler(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+ logout(request, auth);
+ }
+
+ public void logout(HttpServletRequest request, Authentication auth) {
+ logoutFromKeycloak((OidcUser) auth.getPrincipal());
+ }
+
+ private void logoutFromKeycloak(OidcUser user) {
+ String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
+ UriComponentsBuilder builder = UriComponentsBuilder
+ .fromUriString(endSessionEndpoint)
+ .queryParam("id_token_hint", user.getIdToken().getTokenValue());
+
+ ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
+ if (logoutResponse.getStatusCode().is2xxSuccessful()) {
+ log.info("Successfulley logged out from Keycloak");
+ } else {
+ log.error("Could not propagate logout to Keycloak");
+ }
+ }
+
+}
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
index af21e0e..259f612 100644
--- a/src/main/resources/application-test.properties
+++ b/src/main/resources/application-test.properties
@@ -1,5 +1,5 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
index b5c7f7b..d418f1a 100644
--- a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
+++ b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
@@ -1,14 +1,14 @@
-package de.szut.lf8_starter;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
-@SpringBootTest
-class Lf8StarterApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
+package de.szut.lf8_starter;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+class Lf8StarterApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
From 2f92dd3faabcf37f5637169794e87b5ea5c16d3e Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 12:52:05 +0200
Subject: [PATCH 02/31] Rebase
---
GetBearerToken.http | 10 +-
requests/createProject.http | 28 ++---
.../GlobalExceptionHandler.java | 102 +++++++++---------
.../lf8_starter/project/GetProjectDto.java | 86 +++++++--------
.../lf8_starter/project/ProjectEntity.java | 86 +++++++--------
.../project/dto/CreateProjectAction.java | 84 +++++++--------
.../project/dto/CreateProjectDto.java | 84 +++++++--------
7 files changed, 240 insertions(+), 240 deletions(-)
diff --git a/GetBearerToken.http b/GetBearerToken.http
index f5209ca..abf7e94 100644
--- a/GetBearerToken.http
+++ b/GetBearerToken.http
@@ -1,6 +1,6 @@
-POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
-Content-Type: application/x-www-form-urlencoded
-
-grant_type=password&client_id=employee-management-service&username=user&password=test
-
+POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&client_id=employee-management-service&username=user&password=test
+
> {% client.global.set("auth_token", response.body.access_token); %}
\ No newline at end of file
diff --git a/requests/createProject.http b/requests/createProject.http
index add2394..6854828 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -1,15 +1,15 @@
-### GET request to example server
-POST http://localhost:8080/projects
-Authorization: Bearer {{auth_token}}
-Content-Type: application/json
-
-{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractorName": "Peter File",
- "comment": "goal of project",
- "startDate": "01.01.2000",
- "plannedEndDate": "01.01.2001"
+### GET request to example server
+POST http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractorName": "Peter File",
+ "comment": "goal of project",
+ "startDate": "01.01.2000",
+ "plannedEndDate": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 68a15a7..92ba734 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -1,51 +1,51 @@
-package de.szut.lf8_starter.exceptionHandling;
-
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.ConstraintViolationException;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.context.request.WebRequest;
-
-import java.util.Date;
-
-@ControllerAdvice
-@ApiResponses(value = {
- @ApiResponse(responseCode = "500", description = "invalid JSON posted",
- content = @Content)
-})
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
- return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
- }
-
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
- }
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-
- @ExceptionHandler(ConstraintViolationException.class)
- public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
- String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
-
- ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-}
+package de.szut.lf8_starter.exceptionHandling;
+
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.ConstraintViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Date;
+
+@ControllerAdvice
+@ApiResponses(value = {
+ @ApiResponse(responseCode = "500", description = "invalid JSON posted",
+ content = @Content)
+})
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
+ String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
+
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
index 86ce087..75b8c60 100644
--- a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-public class GetProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+public class GetProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
index d9c35a1..82563fe 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.springframework.data.annotation.CreatedDate;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@NoArgsConstructor
-@AllArgsConstructor
-@Getter
-@Setter
-@Entity
-@Table(name = "projects")
-public class ProjectEntity {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
-
- private String name;
-
- private long leadingEmployee;
-
- @ElementCollection
- private List employees;
-
- private long contractor;
-
- private String contractorName;
-
- private String comment;
-
- @CreatedDate
- private LocalDate startDate;
-
- private LocalDate plannedEndDate;
-
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedDate;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@Entity
+@Table(name = "projects")
+public class ProjectEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String name;
+
+ private long leadingEmployee;
+
+ @ElementCollection
+ private List employees;
+
+ private long contractor;
+
+ private String contractorName;
+
+ private String comment;
+
+ @CreatedDate
+ private LocalDate startDate;
+
+ private LocalDate plannedEndDate;
+
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
index f1c6cdc..511c5ee 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
@@ -1,42 +1,42 @@
-package de.szut.lf8_starter.project.dto;
-
-import de.szut.lf8_starter.project.GetProjectDto;
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectMapper;
-import de.szut.lf8_starter.project.ProjectService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
+package de.szut.lf8_starter.project.dto;
+
+import de.szut.lf8_starter.project.GetProjectDto;
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index 4c6ab0d..f27e7f4 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,42 +1,42 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-public class CreateProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+public class CreateProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
From a5c627ccaa2181a99d6f84099514f24e7b3313fb Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 12:56:18 +0200
Subject: [PATCH 03/31] Line ending
---
GetBearerToken.http | 10 +-
config/checkstyle/checkstyle-ignore.xml | 18 +-
config/checkstyle/checkstyle.xml | 46 +-
gradle/wrapper/gradle-wrapper.properties | 14 +-
gradlew | 504 +++++++++---------
requests/createProject.http | 28 +-
.../config/OpenAPIConfiguration.java | 120 ++---
.../GlobalExceptionHandler.java | 102 ++--
.../lf8_starter/project/GetProjectDto.java | 86 +--
.../lf8_starter/project/ProjectEntity.java | 86 +--
.../project/dto/CreateProjectAction.java | 84 +--
.../project/dto/CreateProjectDto.java | 84 +--
.../security/KeycloakLogoutHandler.java | 98 ++--
.../resources/application-test.properties | 8 +-
.../Lf8StarterApplicationTests.java | 28 +-
15 files changed, 658 insertions(+), 658 deletions(-)
diff --git a/GetBearerToken.http b/GetBearerToken.http
index abf7e94..f5209ca 100644
--- a/GetBearerToken.http
+++ b/GetBearerToken.http
@@ -1,6 +1,6 @@
-POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
-Content-Type: application/x-www-form-urlencoded
-
-grant_type=password&client_id=employee-management-service&username=user&password=test
-
+POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&client_id=employee-management-service&username=user&password=test
+
> {% client.global.set("auth_token", response.body.access_token); %}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle-ignore.xml b/config/checkstyle/checkstyle-ignore.xml
index 5ec61a5..fe3b2fe 100644
--- a/config/checkstyle/checkstyle-ignore.xml
+++ b/config/checkstyle/checkstyle-ignore.xml
@@ -1,9 +1,9 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 3c18de8..d8f0701 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -1,23 +1,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b9ddd88..df97d72 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index ec19934..f5feea6 100755
--- a/gradlew
+++ b/gradlew
@@ -1,252 +1,252 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-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
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- if ! command -v java >/dev/null 2>&1
- then
- die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+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
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/requests/createProject.http b/requests/createProject.http
index 6854828..add2394 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -1,15 +1,15 @@
-### GET request to example server
-POST http://localhost:8080/projects
-Authorization: Bearer {{auth_token}}
-Content-Type: application/json
-
-{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractorName": "Peter File",
- "comment": "goal of project",
- "startDate": "01.01.2000",
- "plannedEndDate": "01.01.2001"
+### GET request to example server
+POST http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractorName": "Peter File",
+ "comment": "goal of project",
+ "startDate": "01.01.2000",
+ "plannedEndDate": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 76a6f58..1b2282b 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,60 +1,60 @@
-package de.szut.lf8_starter.config;
-
-
-
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-import jakarta.servlet.ServletContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-public class OpenAPIConfiguration {
-
- private ServletContext context;
-
- public OpenAPIConfiguration(ServletContext context) {
- this.context = context;
- }
-
-
- @Bean
- public OpenAPI springShopOpenAPI(
- // @Value("${info.app.version}") String appVersion,
- ) {
- final String securitySchemeName = "bearerAuth";
-
- return new OpenAPI()
- .addServersItem(new Server().url(this.context.getContextPath()))
- .info(new Info()
- .title("LF8 project starter")
- .description("\n## Auth\n" +
- "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
- "\n" +
- "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
- "\n" +
- "\nor by CURL\n" +
- "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
- "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
-
- .version("0.1"))
- .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
- .components(
- new Components()
- .addSecuritySchemes(securitySchemeName,
- new SecurityScheme()
- .name(securitySchemeName)
- .type(SecurityScheme.Type.HTTP)
- .scheme("bearer")
- .bearerFormat("JWT")
- )
- );
- }
-
-
-}
+package de.szut.lf8_starter.config;
+
+
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import jakarta.servlet.ServletContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class OpenAPIConfiguration {
+
+ private ServletContext context;
+
+ public OpenAPIConfiguration(ServletContext context) {
+ this.context = context;
+ }
+
+
+ @Bean
+ public OpenAPI springShopOpenAPI(
+ // @Value("${info.app.version}") String appVersion,
+ ) {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .addServersItem(new Server().url(this.context.getContextPath()))
+ .info(new Info()
+ .title("LF8 project starter")
+ .description("\n## Auth\n" +
+ "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
+ "\n" +
+ "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
+ "\n" +
+ "\nor by CURL\n" +
+ "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
+ "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
+
+ .version("0.1"))
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ .components(
+ new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 92ba734..68a15a7 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -1,51 +1,51 @@
-package de.szut.lf8_starter.exceptionHandling;
-
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.ConstraintViolationException;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.context.request.WebRequest;
-
-import java.util.Date;
-
-@ControllerAdvice
-@ApiResponses(value = {
- @ApiResponse(responseCode = "500", description = "invalid JSON posted",
- content = @Content)
-})
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
- return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
- }
-
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
- }
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-
- @ExceptionHandler(ConstraintViolationException.class)
- public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
- String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
-
- ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-}
+package de.szut.lf8_starter.exceptionHandling;
+
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.ConstraintViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Date;
+
+@ControllerAdvice
+@ApiResponses(value = {
+ @ApiResponse(responseCode = "500", description = "invalid JSON posted",
+ content = @Content)
+})
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
+ String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
+
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
index 75b8c60..86ce087 100644
--- a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-public class GetProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+public class GetProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @NotNull
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
index 82563fe..d9c35a1 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.springframework.data.annotation.CreatedDate;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@NoArgsConstructor
-@AllArgsConstructor
-@Getter
-@Setter
-@Entity
-@Table(name = "projects")
-public class ProjectEntity {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
-
- private String name;
-
- private long leadingEmployee;
-
- @ElementCollection
- private List employees;
-
- private long contractor;
-
- private String contractorName;
-
- private String comment;
-
- @CreatedDate
- private LocalDate startDate;
-
- private LocalDate plannedEndDate;
-
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedDate;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@Entity
+@Table(name = "projects")
+public class ProjectEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String name;
+
+ private long leadingEmployee;
+
+ @ElementCollection
+ private List employees;
+
+ private long contractor;
+
+ private String contractorName;
+
+ private String comment;
+
+ @CreatedDate
+ private LocalDate startDate;
+
+ private LocalDate plannedEndDate;
+
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
index 511c5ee..f1c6cdc 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
@@ -1,42 +1,42 @@
-package de.szut.lf8_starter.project.dto;
-
-import de.szut.lf8_starter.project.GetProjectDto;
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectMapper;
-import de.szut.lf8_starter.project.ProjectService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
+package de.szut.lf8_starter.project.dto;
+
+import de.szut.lf8_starter.project.GetProjectDto;
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index f27e7f4..4c6ab0d 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,42 +1,42 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-public class CreateProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+public class CreateProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index e06f2f7..8555ef9 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -1,49 +1,49 @@
-package de.szut.lf8_starter.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-@Slf4j
-@Component
-public class KeycloakLogoutHandler implements LogoutHandler {
-
-
- private final RestTemplate restTemplate;
-
- public KeycloakLogoutHandler(RestTemplate restTemplate) {
- this.restTemplate = restTemplate;
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(request, auth);
- }
-
- public void logout(HttpServletRequest request, Authentication auth) {
- logoutFromKeycloak((OidcUser) auth.getPrincipal());
- }
-
- private void logoutFromKeycloak(OidcUser user) {
- String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
- UriComponentsBuilder builder = UriComponentsBuilder
- .fromUriString(endSessionEndpoint)
- .queryParam("id_token_hint", user.getIdToken().getTokenValue());
-
- ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
- if (logoutResponse.getStatusCode().is2xxSuccessful()) {
- log.info("Successfulley logged out from Keycloak");
- } else {
- log.error("Could not propagate logout to Keycloak");
- }
- }
-
-}
+package de.szut.lf8_starter.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class KeycloakLogoutHandler implements LogoutHandler {
+
+
+ private final RestTemplate restTemplate;
+
+ public KeycloakLogoutHandler(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+ logout(request, auth);
+ }
+
+ public void logout(HttpServletRequest request, Authentication auth) {
+ logoutFromKeycloak((OidcUser) auth.getPrincipal());
+ }
+
+ private void logoutFromKeycloak(OidcUser user) {
+ String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
+ UriComponentsBuilder builder = UriComponentsBuilder
+ .fromUriString(endSessionEndpoint)
+ .queryParam("id_token_hint", user.getIdToken().getTokenValue());
+
+ ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
+ if (logoutResponse.getStatusCode().is2xxSuccessful()) {
+ log.info("Successfulley logged out from Keycloak");
+ } else {
+ log.error("Could not propagate logout to Keycloak");
+ }
+ }
+
+}
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
index 259f612..af21e0e 100644
--- a/src/main/resources/application-test.properties
+++ b/src/main/resources/application-test.properties
@@ -1,5 +1,5 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
index d418f1a..b5c7f7b 100644
--- a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
+++ b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
@@ -1,14 +1,14 @@
-package de.szut.lf8_starter;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
-@SpringBootTest
-class Lf8StarterApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
+package de.szut.lf8_starter;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+class Lf8StarterApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
From e209379f41d3d26ab958d379d3b7404f770c4026 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 12:58:28 +0200
Subject: [PATCH 04/31] Order files
---
.../lf8_starter/project/GetProjectDto.java | 43 -------------------
.../project/dto/CreateProjectAction.java | 42 ------------------
2 files changed, 85 deletions(-)
delete mode 100644 src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
delete mode 100644 src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
diff --git a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
deleted file mode 100644
index 86ce087..0000000
--- a/src/main/java/de/szut/lf8_starter/project/GetProjectDto.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package de.szut.lf8_starter.project;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-public class GetProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @NotNull
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
deleted file mode 100644
index f1c6cdc..0000000
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectAction.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.szut.lf8_starter.project.dto;
-
-import de.szut.lf8_starter.project.GetProjectDto;
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectMapper;
-import de.szut.lf8_starter.project.ProjectService;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
From 6723b49f7dcedeba69b958c0eb66e3f6d1f00cbd Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 14:05:31 +0200
Subject: [PATCH 05/31] Write integration test
---
.../project/CreateProjectAction.java | 7 +-
.../project/CreateProjectActionTest.java | 70 +++++++++++++++++++
2 files changed, 73 insertions(+), 4 deletions(-)
create mode 100644 src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
index c41b134..d54318b 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
@@ -8,10 +8,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/projects")
@@ -30,6 +28,7 @@ public class CreateProjectAction {
@ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
@ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
@PostMapping
+ @ResponseStatus(code = HttpStatus.CREATED)
public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
diff --git a/src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java
new file mode 100644
index 0000000..b510ac7
--- /dev/null
+++ b/src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java
@@ -0,0 +1,70 @@
+package de.szut.lf8_starter.project;
+
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+public class CreateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void test() throws Exception {
+ String content = """
+ {
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractorName": "Peter File",
+ "comment": "goal of project",
+ "startDate": "01.01.2000",
+ "plannedEndDate": "01.01.2001"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leadingEmployee", is(0)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
+ .andExpect(jsonPath("contractor", is(4)))
+ .andExpect(jsonPath("contractorName", is("Peter File")))
+ .andExpect(jsonPath("comment", is("goal of project")))
+ .andExpect(jsonPath("startDate", is("01.01.2000")))
+ .andExpect(jsonPath("plannedEndDate", is("01.01.2001")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var project = this.projectRepository.findById(id);
+ assertThat(project.get().getName()).isEqualTo("name");
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(0);
+ assertThat(project.get().getContractor()).isEqualTo(4);
+ assertThat(project.get().getContractorName()).isEqualTo("Peter File");
+ assertThat(project.get().getComment()).isEqualTo("goal of project");
+ assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
+ assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
+ }
+}
From ffb1a1586a8e04f131e79321ea782249cc6783e7 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 14:16:27 +0200
Subject: [PATCH 06/31] Ensure Snake Case in JSON
---
requests/createProject.http | 6 ++--
.../project/dto/CreateProjectDto.java | 3 ++
.../project/dto/GetProjectDto.java | 17 ++--------
.../project/CreateProjectActionTest.java | 31 ++++++++++---------
4 files changed, 25 insertions(+), 32 deletions(-)
rename src/test/java/de/szut/lf8_starter/{ => integration}/project/CreateProjectActionTest.java (75%)
diff --git a/requests/createProject.http b/requests/createProject.http
index add2394..7b08e28 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -8,8 +8,8 @@ Content-Type: application/json
"leading_employee": 1,
"employees": [2, 3],
"contractor": 4,
- "contractorName": "Peter File",
+ "contractor_name": "Peter File",
"comment": "goal of project",
- "startDate": "01.01.2000",
- "plannedEndDate": "01.01.2001"
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index 4c6ab0d..ebf4393 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,6 +1,8 @@
package de.szut.lf8_starter.project.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
@@ -11,6 +13,7 @@ import java.util.List;
@Getter
@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class CreateProjectDto {
@NotBlank
private String name;
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index c90cd50..614ece1 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -1,6 +1,8 @@
package de.szut.lf8_starter.project.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
@@ -11,35 +13,22 @@ import java.util.List;
@Getter
@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class GetProjectDto {
private long id;
-
- @NotBlank
private String name;
-
- @NotNull
private long leadingEmployee;
-
private List employees;
-
- @NotNull
private long contractor;
-
- @NotBlank
private String contractorName;
-
- @NotBlank
private String comment;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate startDate;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate plannedEndDate;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate endDate;
}
diff --git a/src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
similarity index 75%
rename from src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java
rename to src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
index b510ac7..22e40f8 100644
--- a/src/test/java/de/szut/lf8_starter/project/CreateProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -1,5 +1,6 @@
-package de.szut.lf8_starter.project;
+package de.szut.lf8_starter.integration.project;
+import de.szut.lf8_starter.project.ProjectRepository;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -29,15 +30,15 @@ public class CreateProjectActionTest {
void test() throws Exception {
String content = """
{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractorName": "Peter File",
- "comment": "goal of project",
- "startDate": "01.01.2000",
- "plannedEndDate": "01.01.2001"
- }
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
+ }
""";
final var contentAsString = this.mockMvc.perform(
@@ -45,13 +46,13 @@ public class CreateProjectActionTest {
)
.andExpect(status().isCreated())
.andExpect(jsonPath("name", is("name")))
- .andExpect(jsonPath("leadingEmployee", is(0)))
+ .andExpect(jsonPath("leading_employee", is(1)))
.andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
.andExpect(jsonPath("contractor", is(4)))
- .andExpect(jsonPath("contractorName", is("Peter File")))
+ .andExpect(jsonPath("contractor_name", is("Peter File")))
.andExpect(jsonPath("comment", is("goal of project")))
- .andExpect(jsonPath("startDate", is("01.01.2000")))
- .andExpect(jsonPath("plannedEndDate", is("01.01.2001")))
+ .andExpect(jsonPath("start_date", is("01.01.2000")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
.andReturn()
.getResponse()
.getContentAsString();
@@ -60,7 +61,7 @@ public class CreateProjectActionTest {
final var project = this.projectRepository.findById(id);
assertThat(project.get().getName()).isEqualTo("name");
- assertThat(project.get().getLeadingEmployee()).isEqualTo(0);
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
assertThat(project.get().getContractor()).isEqualTo(4);
assertThat(project.get().getContractorName()).isEqualTo("Peter File");
assertThat(project.get().getComment()).isEqualTo("goal of project");
From a365c7aee32dfd08fb1c5066d55e641235d60e99 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 14:22:26 +0200
Subject: [PATCH 07/31] Fix tests
---
.gitea/workflows/release.yml | 62 +--
GetBearerToken.http | 10 +-
config/checkstyle/checkstyle-ignore.xml | 18 +-
config/checkstyle/checkstyle.xml | 46 +-
gradle/wrapper/gradle-wrapper.properties | 14 +-
gradlew | 504 +++++++++---------
release.config.cjs | 24 +-
requests/createProject.http | 28 +-
.../config/OpenAPIConfiguration.java | 120 ++---
.../GlobalExceptionHandler.java | 102 ++--
.../project/CreateProjectAction.java | 78 +--
.../lf8_starter/project/ProjectEntity.java | 86 +--
.../project/dto/CreateProjectDto.java | 90 ++--
.../project/dto/GetProjectDto.java | 68 +--
.../security/KeycloakLogoutHandler.java | 98 ++--
.../resources/application-test.properties | 8 +-
.../Lf8StarterApplicationTests.java | 28 +-
.../project/CreateProjectActionTest.java | 142 ++---
...ss.java => ProjectFindAllSuccessTest.java} | 16 +-
19 files changed, 769 insertions(+), 773 deletions(-)
rename src/test/java/de/szut/lf8_starter/integration/project/{ProjectFindAllSuccess.java => ProjectFindAllSuccessTest.java} (80%)
diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
index 1c29ae9..a04d812 100644
--- a/.gitea/workflows/release.yml
+++ b/.gitea/workflows/release.yml
@@ -1,31 +1,31 @@
-name: Release
-on:
- push:
- branches:
- - main
-
-env:
- GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
-
-permissions:
- contents: read # for checkout
-
-concurrency:
- group: ${{ github.ref }} # Ensure each branch has its own group
- cancel-in-progress: false # Prevent new runs from canceling in-progress runs
-
-jobs:
- release:
- name: Release
- runs-on: ubuntu-latest
- permissions:
- contents: write # to be able to publish a GitHub release
- issues: write # to be able to comment on released issues
- pull-requests: write # to be able to comment on released pull requests
- id-token: write # to enable use of OIDC for npm provenance
- steps:
- - name: Create Release
- uses: https://git.kjan.de/actions/semantic-release@main
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+name: Release
+on:
+ push:
+ branches:
+ - main
+
+env:
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+
+permissions:
+ contents: read # for checkout
+
+concurrency:
+ group: ${{ github.ref }} # Ensure each branch has its own group
+ cancel-in-progress: false # Prevent new runs from canceling in-progress runs
+
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write # to be able to publish a GitHub release
+ issues: write # to be able to comment on released issues
+ pull-requests: write # to be able to comment on released pull requests
+ id-token: write # to enable use of OIDC for npm provenance
+ steps:
+ - name: Create Release
+ uses: https://git.kjan.de/actions/semantic-release@main
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
diff --git a/GetBearerToken.http b/GetBearerToken.http
index f5209ca..abf7e94 100644
--- a/GetBearerToken.http
+++ b/GetBearerToken.http
@@ -1,6 +1,6 @@
-POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
-Content-Type: application/x-www-form-urlencoded
-
-grant_type=password&client_id=employee-management-service&username=user&password=test
-
+POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&client_id=employee-management-service&username=user&password=test
+
> {% client.global.set("auth_token", response.body.access_token); %}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle-ignore.xml b/config/checkstyle/checkstyle-ignore.xml
index fe3b2fe..5ec61a5 100644
--- a/config/checkstyle/checkstyle-ignore.xml
+++ b/config/checkstyle/checkstyle-ignore.xml
@@ -1,9 +1,9 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index d8f0701..3c18de8 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -1,23 +1,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index df97d72..b9ddd88 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index f5feea6..ec19934 100755
--- a/gradlew
+++ b/gradlew
@@ -1,252 +1,252 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-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
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- if ! command -v java >/dev/null 2>&1
- then
- die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+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
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/release.config.cjs b/release.config.cjs
index 375ccd5..1b62d04 100644
--- a/release.config.cjs
+++ b/release.config.cjs
@@ -1,12 +1,12 @@
-module.exports = {
-
- branches: ['main'],
- plugins: [
- '@semantic-release/commit-analyzer',
- '@semantic-release/release-notes-generator',
- '@semantic-release/changelog',
- ["@saithodev/semantic-release-gitea", {
- "giteaUrl": "https://git.kjan.de"
- }],
- ],
-};
+module.exports = {
+
+ branches: ['main'],
+ plugins: [
+ '@semantic-release/commit-analyzer',
+ '@semantic-release/release-notes-generator',
+ '@semantic-release/changelog',
+ ["@saithodev/semantic-release-gitea", {
+ "giteaUrl": "https://git.kjan.de"
+ }],
+ ],
+};
diff --git a/requests/createProject.http b/requests/createProject.http
index 7b08e28..885c49e 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -1,15 +1,15 @@
-### GET request to example server
-POST http://localhost:8080/projects
-Authorization: Bearer {{auth_token}}
-Content-Type: application/json
-
-{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
+### GET request to example server
+POST http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 1b2282b..76a6f58 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,60 +1,60 @@
-package de.szut.lf8_starter.config;
-
-
-
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-import jakarta.servlet.ServletContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-public class OpenAPIConfiguration {
-
- private ServletContext context;
-
- public OpenAPIConfiguration(ServletContext context) {
- this.context = context;
- }
-
-
- @Bean
- public OpenAPI springShopOpenAPI(
- // @Value("${info.app.version}") String appVersion,
- ) {
- final String securitySchemeName = "bearerAuth";
-
- return new OpenAPI()
- .addServersItem(new Server().url(this.context.getContextPath()))
- .info(new Info()
- .title("LF8 project starter")
- .description("\n## Auth\n" +
- "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
- "\n" +
- "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
- "\n" +
- "\nor by CURL\n" +
- "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
- "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
-
- .version("0.1"))
- .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
- .components(
- new Components()
- .addSecuritySchemes(securitySchemeName,
- new SecurityScheme()
- .name(securitySchemeName)
- .type(SecurityScheme.Type.HTTP)
- .scheme("bearer")
- .bearerFormat("JWT")
- )
- );
- }
-
-
-}
+package de.szut.lf8_starter.config;
+
+
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import jakarta.servlet.ServletContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class OpenAPIConfiguration {
+
+ private ServletContext context;
+
+ public OpenAPIConfiguration(ServletContext context) {
+ this.context = context;
+ }
+
+
+ @Bean
+ public OpenAPI springShopOpenAPI(
+ // @Value("${info.app.version}") String appVersion,
+ ) {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .addServersItem(new Server().url(this.context.getContextPath()))
+ .info(new Info()
+ .title("LF8 project starter")
+ .description("\n## Auth\n" +
+ "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
+ "\n" +
+ "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
+ "\n" +
+ "\nor by CURL\n" +
+ "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
+ "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
+
+ .version("0.1"))
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ .components(
+ new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 68a15a7..92ba734 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -1,51 +1,51 @@
-package de.szut.lf8_starter.exceptionHandling;
-
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.ConstraintViolationException;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.context.request.WebRequest;
-
-import java.util.Date;
-
-@ControllerAdvice
-@ApiResponses(value = {
- @ApiResponse(responseCode = "500", description = "invalid JSON posted",
- content = @Content)
-})
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
- return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
- }
-
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
- }
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-
- @ExceptionHandler(ConstraintViolationException.class)
- public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
- String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
-
- ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-}
+package de.szut.lf8_starter.exceptionHandling;
+
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.ConstraintViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Date;
+
+@ControllerAdvice
+@ApiResponses(value = {
+ @ApiResponse(responseCode = "500", description = "invalid JSON posted",
+ content = @Content)
+})
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
+ String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
+
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
index d54318b..4158fee 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
@@ -1,39 +1,39 @@
-package de.szut.lf8_starter.project;
-
-import de.szut.lf8_starter.project.dto.CreateProjectDto;
-import de.szut.lf8_starter.project.dto.GetProjectDto;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- @ResponseStatus(code = HttpStatus.CREATED)
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
+package de.szut.lf8_starter.project;
+
+import de.szut.lf8_starter.project.dto.CreateProjectDto;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ @ResponseStatus(code = HttpStatus.CREATED)
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
index d9c35a1..82563fe 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.springframework.data.annotation.CreatedDate;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@NoArgsConstructor
-@AllArgsConstructor
-@Getter
-@Setter
-@Entity
-@Table(name = "projects")
-public class ProjectEntity {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
-
- private String name;
-
- private long leadingEmployee;
-
- @ElementCollection
- private List employees;
-
- private long contractor;
-
- private String contractorName;
-
- private String comment;
-
- @CreatedDate
- private LocalDate startDate;
-
- private LocalDate plannedEndDate;
-
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedDate;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@Entity
+@Table(name = "projects")
+public class ProjectEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String name;
+
+ private long leadingEmployee;
+
+ @ElementCollection
+ private List employees;
+
+ private long contractor;
+
+ private String contractorName;
+
+ private String comment;
+
+ @CreatedDate
+ private LocalDate startDate;
+
+ private LocalDate plannedEndDate;
+
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index ebf4393..64d22b7 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,45 +1,45 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class CreateProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class CreateProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index 614ece1..250a6a0 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -1,34 +1,34 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class GetProjectDto {
- private long id;
- private String name;
- private long leadingEmployee;
- private List employees;
- private long contractor;
- private String contractorName;
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class GetProjectDto {
+ private long id;
+ private String name;
+ private long leadingEmployee;
+ private List employees;
+ private long contractor;
+ private String contractorName;
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index 8555ef9..e06f2f7 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -1,49 +1,49 @@
-package de.szut.lf8_starter.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-@Slf4j
-@Component
-public class KeycloakLogoutHandler implements LogoutHandler {
-
-
- private final RestTemplate restTemplate;
-
- public KeycloakLogoutHandler(RestTemplate restTemplate) {
- this.restTemplate = restTemplate;
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(request, auth);
- }
-
- public void logout(HttpServletRequest request, Authentication auth) {
- logoutFromKeycloak((OidcUser) auth.getPrincipal());
- }
-
- private void logoutFromKeycloak(OidcUser user) {
- String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
- UriComponentsBuilder builder = UriComponentsBuilder
- .fromUriString(endSessionEndpoint)
- .queryParam("id_token_hint", user.getIdToken().getTokenValue());
-
- ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
- if (logoutResponse.getStatusCode().is2xxSuccessful()) {
- log.info("Successfulley logged out from Keycloak");
- } else {
- log.error("Could not propagate logout to Keycloak");
- }
- }
-
-}
+package de.szut.lf8_starter.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class KeycloakLogoutHandler implements LogoutHandler {
+
+
+ private final RestTemplate restTemplate;
+
+ public KeycloakLogoutHandler(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+ logout(request, auth);
+ }
+
+ public void logout(HttpServletRequest request, Authentication auth) {
+ logoutFromKeycloak((OidcUser) auth.getPrincipal());
+ }
+
+ private void logoutFromKeycloak(OidcUser user) {
+ String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
+ UriComponentsBuilder builder = UriComponentsBuilder
+ .fromUriString(endSessionEndpoint)
+ .queryParam("id_token_hint", user.getIdToken().getTokenValue());
+
+ ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
+ if (logoutResponse.getStatusCode().is2xxSuccessful()) {
+ log.info("Successfulley logged out from Keycloak");
+ } else {
+ log.error("Could not propagate logout to Keycloak");
+ }
+ }
+
+}
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
index af21e0e..259f612 100644
--- a/src/main/resources/application-test.properties
+++ b/src/main/resources/application-test.properties
@@ -1,5 +1,5 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
index b5c7f7b..d418f1a 100644
--- a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
+++ b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
@@ -1,14 +1,14 @@
-package de.szut.lf8_starter;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
-@SpringBootTest
-class Lf8StarterApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
+package de.szut.lf8_starter;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+class Lf8StarterApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
index 22e40f8..06d02b6 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -1,71 +1,71 @@
-package de.szut.lf8_starter.integration.project;
-
-import de.szut.lf8_starter.project.ProjectRepository;
-import org.json.JSONObject;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@SpringBootTest
-@AutoConfigureMockMvc(addFilters = false)
-public class CreateProjectActionTest {
- @Autowired
- private MockMvc mockMvc;
- @Autowired
- private ProjectRepository projectRepository;
-
- @Test
- void test() throws Exception {
- String content = """
- {
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
- }
- """;
-
- final var contentAsString = this.mockMvc.perform(
- post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
- )
- .andExpect(status().isCreated())
- .andExpect(jsonPath("name", is("name")))
- .andExpect(jsonPath("leading_employee", is(1)))
- .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
- .andExpect(jsonPath("contractor", is(4)))
- .andExpect(jsonPath("contractor_name", is("Peter File")))
- .andExpect(jsonPath("comment", is("goal of project")))
- .andExpect(jsonPath("start_date", is("01.01.2000")))
- .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
- .andReturn()
- .getResponse()
- .getContentAsString();
-
- final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
-
- final var project = this.projectRepository.findById(id);
- assertThat(project.get().getName()).isEqualTo("name");
- assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
- assertThat(project.get().getContractor()).isEqualTo(4);
- assertThat(project.get().getContractorName()).isEqualTo("Peter File");
- assertThat(project.get().getComment()).isEqualTo("goal of project");
- assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
- assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
- }
-}
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+public class CreateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void createProjectTest() throws Exception {
+ String content = """
+ {
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leading_employee", is(1)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
+ .andExpect(jsonPath("contractor", is(4)))
+ .andExpect(jsonPath("contractor_name", is("Peter File")))
+ .andExpect(jsonPath("comment", is("goal of project")))
+ .andExpect(jsonPath("start_date", is("01.01.2000")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var project = this.projectRepository.findById(id);
+ assertThat(project.get().getName()).isEqualTo("name");
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
+ assertThat(project.get().getContractor()).isEqualTo(4);
+ assertThat(project.get().getContractorName()).isEqualTo("Peter File");
+ assertThat(project.get().getComment()).isEqualTo("goal of project");
+ assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
+ assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
similarity index 80%
rename from src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java
rename to src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
index 906b63f..8f1974a 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
@@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDate;
@@ -19,18 +18,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc(addFilters = false)
-public class ProjectFindAllSuccess {
+public class ProjectFindAllSuccessTest {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private MockMvc mockMvc;
- @Autowired
- private TestRestTemplate restTemplate;
-
@Test
- void findAllProjects() throws Exception {
+ void findAllProjectsTest() throws Exception {
var project = new ProjectEntity();
project.setId(1);
project.setComment("comment");
@@ -49,11 +45,11 @@ public class ProjectFindAllSuccess {
.andExpect(jsonPath("$[0].id").value(1))
.andExpect(jsonPath("$[0].comment").value("comment"))
.andExpect(jsonPath("$[0].contractor").value(1))
- .andExpect(jsonPath("$[0].contractorName").value("contractorName"))
- .andExpect(jsonPath("$[0].endDate").value("01.01.2024"))
- .andExpect(jsonPath("$[0].leadingEmployee").value(1))
+ .andExpect(jsonPath("$[0].contractor_name").value("contractorName"))
+ .andExpect(jsonPath("$[0].end_date").value("01.01.2024"))
+ .andExpect(jsonPath("$[0].leading_employee").value(1))
.andExpect(jsonPath("$[0].name").value("name"))
- .andExpect(jsonPath("$[0].startDate").value("01.01.2021"))
+ .andExpect(jsonPath("$[0].start_date").value("01.01.2021"))
.andExpect(jsonPath("$[0].employees").isArray())
.andExpect(jsonPath("$[0].employees", hasSize(3)));
}
From 79300c77ee17017b3b370a0dc71ca4272e1b3fde Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 14:25:55 +0200
Subject: [PATCH 08/31] Fix line endings
---
.gitea/workflows/release.yml | 62 +--
GetBearerToken.http | 10 +-
config/checkstyle/checkstyle-ignore.xml | 18 +-
config/checkstyle/checkstyle.xml | 46 +-
gradle/wrapper/gradle-wrapper.properties | 14 +-
gradlew | 504 +++++++++---------
release.config.cjs | 24 +-
requests/createProject.http | 28 +-
.../config/OpenAPIConfiguration.java | 120 ++---
.../GlobalExceptionHandler.java | 102 ++--
.../project/CreateProjectAction.java | 78 +--
.../lf8_starter/project/ProjectEntity.java | 86 +--
.../project/dto/CreateProjectDto.java | 90 ++--
.../project/dto/GetProjectDto.java | 68 +--
.../security/KeycloakLogoutHandler.java | 98 ++--
.../resources/application-test.properties | 8 +-
.../Lf8StarterApplicationTests.java | 28 +-
.../project/CreateProjectActionTest.java | 142 ++---
18 files changed, 763 insertions(+), 763 deletions(-)
diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
index a04d812..1c29ae9 100644
--- a/.gitea/workflows/release.yml
+++ b/.gitea/workflows/release.yml
@@ -1,31 +1,31 @@
-name: Release
-on:
- push:
- branches:
- - main
-
-env:
- GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
-
-permissions:
- contents: read # for checkout
-
-concurrency:
- group: ${{ github.ref }} # Ensure each branch has its own group
- cancel-in-progress: false # Prevent new runs from canceling in-progress runs
-
-jobs:
- release:
- name: Release
- runs-on: ubuntu-latest
- permissions:
- contents: write # to be able to publish a GitHub release
- issues: write # to be able to comment on released issues
- pull-requests: write # to be able to comment on released pull requests
- id-token: write # to enable use of OIDC for npm provenance
- steps:
- - name: Create Release
- uses: https://git.kjan.de/actions/semantic-release@main
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+name: Release
+on:
+ push:
+ branches:
+ - main
+
+env:
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
+
+permissions:
+ contents: read # for checkout
+
+concurrency:
+ group: ${{ github.ref }} # Ensure each branch has its own group
+ cancel-in-progress: false # Prevent new runs from canceling in-progress runs
+
+jobs:
+ release:
+ name: Release
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write # to be able to publish a GitHub release
+ issues: write # to be able to comment on released issues
+ pull-requests: write # to be able to comment on released pull requests
+ id-token: write # to enable use of OIDC for npm provenance
+ steps:
+ - name: Create Release
+ uses: https://git.kjan.de/actions/semantic-release@main
+ with:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
diff --git a/GetBearerToken.http b/GetBearerToken.http
index abf7e94..f5209ca 100644
--- a/GetBearerToken.http
+++ b/GetBearerToken.http
@@ -1,6 +1,6 @@
-POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
-Content-Type: application/x-www-form-urlencoded
-
-grant_type=password&client_id=employee-management-service&username=user&password=test
-
+POST https://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&client_id=employee-management-service&username=user&password=test
+
> {% client.global.set("auth_token", response.body.access_token); %}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle-ignore.xml b/config/checkstyle/checkstyle-ignore.xml
index 5ec61a5..fe3b2fe 100644
--- a/config/checkstyle/checkstyle-ignore.xml
+++ b/config/checkstyle/checkstyle-ignore.xml
@@ -1,9 +1,9 @@
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 3c18de8..d8f0701 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -1,23 +1,23 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index b9ddd88..df97d72 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-distributionBase=GRADLE_USER_HOME
-distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
-networkTimeout=10000
-validateDistributionUrl=true
-zipStoreBase=GRADLE_USER_HOME
-zipStorePath=wrapper/dists
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index ec19934..f5feea6 100755
--- a/gradlew
+++ b/gradlew
@@ -1,252 +1,252 @@
-#!/bin/sh
-
-#
-# Copyright © 2015-2021 the original authors.
-#
-# Licensed 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.
-#
-# SPDX-License-Identifier: Apache-2.0
-#
-
-##############################################################################
-#
-# Gradle start up script for POSIX generated by Gradle.
-#
-# Important for running:
-#
-# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
-# noncompliant, but you have some other compliant shell such as ksh or
-# bash, then to run this script, type that shell name before the whole
-# command line, like:
-#
-# ksh Gradle
-#
-# Busybox and similar reduced shells will NOT work, because this script
-# requires all of these POSIX shell features:
-# * functions;
-# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
-# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
-# * compound commands having a testable exit status, especially «case»;
-# * various built-in commands including «command», «set», and «ulimit».
-#
-# Important for patching:
-#
-# (2) This script targets any POSIX shell, so it avoids extensions provided
-# by Bash, Ksh, etc; in particular arrays are avoided.
-#
-# The "traditional" practice of packing multiple parameters into a
-# space-separated string is a well documented source of bugs and security
-# problems, so this is (mostly) avoided, by progressively accumulating
-# options in "$@", and eventually passing that to Java.
-#
-# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
-# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
-# see the in-line comments for details.
-#
-# There are tweaks for specific operating systems such as AIX, CygWin,
-# Darwin, MinGW, and NonStop.
-#
-# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
-# within the Gradle project.
-#
-# You can find Gradle at https://github.com/gradle/gradle/.
-#
-##############################################################################
-
-# Attempt to set APP_HOME
-
-# Resolve links: $0 may be a link
-app_path=$0
-
-# Need this for daisy-chained symlinks.
-while
- APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
- [ -h "$app_path" ]
-do
- ls=$( ls -ld "$app_path" )
- link=${ls#*' -> '}
- case $link in #(
- /*) app_path=$link ;; #(
- *) app_path=$APP_HOME$link ;;
- esac
-done
-
-# This is normally unused
-# shellcheck disable=SC2034
-APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
-
-# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD=maximum
-
-warn () {
- echo "$*"
-} >&2
-
-die () {
- echo
- echo "$*"
- echo
- exit 1
-} >&2
-
-# OS specific support (must be 'true' or 'false').
-cygwin=false
-msys=false
-darwin=false
-nonstop=false
-case "$( uname )" in #(
- CYGWIN* ) cygwin=true ;; #(
- Darwin* ) darwin=true ;; #(
- MSYS* | MINGW* ) msys=true ;; #(
- NONSTOP* ) nonstop=true ;;
-esac
-
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
-
-
-# Determine the Java command to use to start the JVM.
-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
- if [ ! -x "$JAVACMD" ] ; then
- die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-else
- JAVACMD=java
- if ! command -v java >/dev/null 2>&1
- then
- die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-
-Please set the JAVA_HOME variable in your environment to match the
-location of your Java installation."
- fi
-fi
-
-# Increase the maximum file descriptors if we can.
-if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
- case $MAX_FD in #(
- max*)
- # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- MAX_FD=$( ulimit -H -n ) ||
- warn "Could not query maximum file descriptor limit"
- esac
- case $MAX_FD in #(
- '' | soft) :;; #(
- *)
- # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
- ulimit -n "$MAX_FD" ||
- warn "Could not set maximum file descriptor limit to $MAX_FD"
- esac
-fi
-
-# Collect all arguments for the java command, stacking in reverse order:
-# * args from the command line
-# * the main class name
-# * -classpath
-# * -D...appname settings
-# * --module-path (only if needed)
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
-
-# For Cygwin or MSYS, switch paths to Windows format before running java
-if "$cygwin" || "$msys" ; then
- APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
-
- JAVACMD=$( cygpath --unix "$JAVACMD" )
-
- # Now convert the arguments - kludge to limit ourselves to /bin/sh
- for arg do
- if
- case $arg in #(
- -*) false ;; # don't mess with options #(
- /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
- [ -e "$t" ] ;; #(
- *) false ;;
- esac
- then
- arg=$( cygpath --path --ignore --mixed "$arg" )
- fi
- # Roll the args list around exactly as many times as the number of
- # args, so each arg winds up back in the position where it started, but
- # possibly modified.
- #
- # NB: a `for` loop captures its iteration list before it begins, so
- # changing the positional parameters here affects neither the number of
- # iterations, nor the values presented in `arg`.
- shift # remove old arg
- set -- "$@" "$arg" # push replacement arg
- done
-fi
-
-
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
-
-set -- \
- "-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
- "$@"
-
-# Stop when "xargs" is not available.
-if ! command -v xargs >/dev/null 2>&1
-then
- die "xargs is not available"
-fi
-
-# Use "xargs" to parse quoted args.
-#
-# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
-#
-# In Bash we could simply go:
-#
-# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
-# set -- "${ARGS[@]}" "$@"
-#
-# but POSIX shell has neither arrays nor command substitution, so instead we
-# post-process each arg (as a line of input to sed) to backslash-escape any
-# character that might be a shell metacharacter, then use eval to reverse
-# that process (while maintaining the separation between arguments), and wrap
-# the whole thing up as a single "set" statement.
-#
-# This will of course break if any of these variables contains a newline or
-# an unmatched quote.
-#
-
-eval "set -- $(
- printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
- xargs -n1 |
- sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
- tr '\n' ' '
- )" '"$@"'
-
-exec "$JAVACMD" "$@"
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+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
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/release.config.cjs b/release.config.cjs
index 1b62d04..375ccd5 100644
--- a/release.config.cjs
+++ b/release.config.cjs
@@ -1,12 +1,12 @@
-module.exports = {
-
- branches: ['main'],
- plugins: [
- '@semantic-release/commit-analyzer',
- '@semantic-release/release-notes-generator',
- '@semantic-release/changelog',
- ["@saithodev/semantic-release-gitea", {
- "giteaUrl": "https://git.kjan.de"
- }],
- ],
-};
+module.exports = {
+
+ branches: ['main'],
+ plugins: [
+ '@semantic-release/commit-analyzer',
+ '@semantic-release/release-notes-generator',
+ '@semantic-release/changelog',
+ ["@saithodev/semantic-release-gitea", {
+ "giteaUrl": "https://git.kjan.de"
+ }],
+ ],
+};
diff --git a/requests/createProject.http b/requests/createProject.http
index 885c49e..7b08e28 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -1,15 +1,15 @@
-### GET request to example server
-POST http://localhost:8080/projects
-Authorization: Bearer {{auth_token}}
-Content-Type: application/json
-
-{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
+### GET request to example server
+POST http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 76a6f58..1b2282b 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,60 +1,60 @@
-package de.szut.lf8_starter.config;
-
-
-
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-import jakarta.servlet.ServletContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-public class OpenAPIConfiguration {
-
- private ServletContext context;
-
- public OpenAPIConfiguration(ServletContext context) {
- this.context = context;
- }
-
-
- @Bean
- public OpenAPI springShopOpenAPI(
- // @Value("${info.app.version}") String appVersion,
- ) {
- final String securitySchemeName = "bearerAuth";
-
- return new OpenAPI()
- .addServersItem(new Server().url(this.context.getContextPath()))
- .info(new Info()
- .title("LF8 project starter")
- .description("\n## Auth\n" +
- "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
- "\n" +
- "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
- "\n" +
- "\nor by CURL\n" +
- "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
- "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
-
- .version("0.1"))
- .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
- .components(
- new Components()
- .addSecuritySchemes(securitySchemeName,
- new SecurityScheme()
- .name(securitySchemeName)
- .type(SecurityScheme.Type.HTTP)
- .scheme("bearer")
- .bearerFormat("JWT")
- )
- );
- }
-
-
-}
+package de.szut.lf8_starter.config;
+
+
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import jakarta.servlet.ServletContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class OpenAPIConfiguration {
+
+ private ServletContext context;
+
+ public OpenAPIConfiguration(ServletContext context) {
+ this.context = context;
+ }
+
+
+ @Bean
+ public OpenAPI springShopOpenAPI(
+ // @Value("${info.app.version}") String appVersion,
+ ) {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .addServersItem(new Server().url(this.context.getContextPath()))
+ .info(new Info()
+ .title("LF8 project starter")
+ .description("\n## Auth\n" +
+ "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
+ "\n" +
+ "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
+ "\n" +
+ "\nor by CURL\n" +
+ "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
+ "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
+
+ .version("0.1"))
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ .components(
+ new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 92ba734..68a15a7 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -1,51 +1,51 @@
-package de.szut.lf8_starter.exceptionHandling;
-
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.ConstraintViolationException;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.context.request.WebRequest;
-
-import java.util.Date;
-
-@ControllerAdvice
-@ApiResponses(value = {
- @ApiResponse(responseCode = "500", description = "invalid JSON posted",
- content = @Content)
-})
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
- return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
- }
-
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
- }
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-
- @ExceptionHandler(ConstraintViolationException.class)
- public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
- String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
-
- ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-}
+package de.szut.lf8_starter.exceptionHandling;
+
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.ConstraintViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Date;
+
+@ControllerAdvice
+@ApiResponses(value = {
+ @ApiResponse(responseCode = "500", description = "invalid JSON posted",
+ content = @Content)
+})
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
+ String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
+
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
index 4158fee..d54318b 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
@@ -1,39 +1,39 @@
-package de.szut.lf8_starter.project;
-
-import de.szut.lf8_starter.project.dto.CreateProjectDto;
-import de.szut.lf8_starter.project.dto.GetProjectDto;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- @ResponseStatus(code = HttpStatus.CREATED)
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
+package de.szut.lf8_starter.project;
+
+import de.szut.lf8_starter.project.dto.CreateProjectDto;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ @ResponseStatus(code = HttpStatus.CREATED)
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
index 82563fe..d9c35a1 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
@@ -1,43 +1,43 @@
-package de.szut.lf8_starter.project;
-
-import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import org.springframework.data.annotation.CreatedDate;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@NoArgsConstructor
-@AllArgsConstructor
-@Getter
-@Setter
-@Entity
-@Table(name = "projects")
-public class ProjectEntity {
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
-
- private String name;
-
- private long leadingEmployee;
-
- @ElementCollection
- private List employees;
-
- private long contractor;
-
- private String contractorName;
-
- private String comment;
-
- @CreatedDate
- private LocalDate startDate;
-
- private LocalDate plannedEndDate;
-
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.data.annotation.CreatedDate;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@Entity
+@Table(name = "projects")
+public class ProjectEntity {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String name;
+
+ private long leadingEmployee;
+
+ @ElementCollection
+ private List employees;
+
+ private long contractor;
+
+ private String contractorName;
+
+ private String comment;
+
+ @CreatedDate
+ private LocalDate startDate;
+
+ private LocalDate plannedEndDate;
+
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index 64d22b7..ebf4393 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,45 +1,45 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class CreateProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class CreateProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index 250a6a0..614ece1 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -1,34 +1,34 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class GetProjectDto {
- private long id;
- private String name;
- private long leadingEmployee;
- private List employees;
- private long contractor;
- private String contractorName;
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class GetProjectDto {
+ private long id;
+ private String name;
+ private long leadingEmployee;
+ private List employees;
+ private long contractor;
+ private String contractorName;
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index e06f2f7..8555ef9 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -1,49 +1,49 @@
-package de.szut.lf8_starter.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-@Slf4j
-@Component
-public class KeycloakLogoutHandler implements LogoutHandler {
-
-
- private final RestTemplate restTemplate;
-
- public KeycloakLogoutHandler(RestTemplate restTemplate) {
- this.restTemplate = restTemplate;
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(request, auth);
- }
-
- public void logout(HttpServletRequest request, Authentication auth) {
- logoutFromKeycloak((OidcUser) auth.getPrincipal());
- }
-
- private void logoutFromKeycloak(OidcUser user) {
- String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
- UriComponentsBuilder builder = UriComponentsBuilder
- .fromUriString(endSessionEndpoint)
- .queryParam("id_token_hint", user.getIdToken().getTokenValue());
-
- ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
- if (logoutResponse.getStatusCode().is2xxSuccessful()) {
- log.info("Successfulley logged out from Keycloak");
- } else {
- log.error("Could not propagate logout to Keycloak");
- }
- }
-
-}
+package de.szut.lf8_starter.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class KeycloakLogoutHandler implements LogoutHandler {
+
+
+ private final RestTemplate restTemplate;
+
+ public KeycloakLogoutHandler(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+ logout(request, auth);
+ }
+
+ public void logout(HttpServletRequest request, Authentication auth) {
+ logoutFromKeycloak((OidcUser) auth.getPrincipal());
+ }
+
+ private void logoutFromKeycloak(OidcUser user) {
+ String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
+ UriComponentsBuilder builder = UriComponentsBuilder
+ .fromUriString(endSessionEndpoint)
+ .queryParam("id_token_hint", user.getIdToken().getTokenValue());
+
+ ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
+ if (logoutResponse.getStatusCode().is2xxSuccessful()) {
+ log.info("Successfulley logged out from Keycloak");
+ } else {
+ log.error("Could not propagate logout to Keycloak");
+ }
+ }
+
+}
diff --git a/src/main/resources/application-test.properties b/src/main/resources/application-test.properties
index 259f612..af21e0e 100644
--- a/src/main/resources/application-test.properties
+++ b/src/main/resources/application-test.properties
@@ -1,5 +1,5 @@
-spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
-spring.datasource.driver-class-name=org.h2.Driver
-spring.datasource.username=sa
-spring.datasource.password=
+spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1
+spring.datasource.driver-class-name=org.h2.Driver
+spring.datasource.username=sa
+spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
\ No newline at end of file
diff --git a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
index d418f1a..b5c7f7b 100644
--- a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
+++ b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
@@ -1,14 +1,14 @@
-package de.szut.lf8_starter;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
-
-@SpringBootTest
-class Lf8StarterApplicationTests {
-
- @Test
- void contextLoads() {
- }
-
-}
+package de.szut.lf8_starter;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.TestPropertySource;
+
+@SpringBootTest
+class Lf8StarterApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
index 06d02b6..36eee54 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -1,71 +1,71 @@
-package de.szut.lf8_starter.integration.project;
-
-import de.szut.lf8_starter.project.ProjectRepository;
-import org.json.JSONObject;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@SpringBootTest
-@AutoConfigureMockMvc(addFilters = false)
-public class CreateProjectActionTest {
- @Autowired
- private MockMvc mockMvc;
- @Autowired
- private ProjectRepository projectRepository;
-
- @Test
- void createProjectTest() throws Exception {
- String content = """
- {
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
- }
- """;
-
- final var contentAsString = this.mockMvc.perform(
- post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
- )
- .andExpect(status().isCreated())
- .andExpect(jsonPath("name", is("name")))
- .andExpect(jsonPath("leading_employee", is(1)))
- .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
- .andExpect(jsonPath("contractor", is(4)))
- .andExpect(jsonPath("contractor_name", is("Peter File")))
- .andExpect(jsonPath("comment", is("goal of project")))
- .andExpect(jsonPath("start_date", is("01.01.2000")))
- .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
- .andReturn()
- .getResponse()
- .getContentAsString();
-
- final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
-
- final var project = this.projectRepository.findById(id);
- assertThat(project.get().getName()).isEqualTo("name");
- assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
- assertThat(project.get().getContractor()).isEqualTo(4);
- assertThat(project.get().getContractorName()).isEqualTo("Peter File");
- assertThat(project.get().getComment()).isEqualTo("goal of project");
- assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
- assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
- }
-}
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+public class CreateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void createProjectTest() throws Exception {
+ String content = """
+ {
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leading_employee", is(1)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
+ .andExpect(jsonPath("contractor", is(4)))
+ .andExpect(jsonPath("contractor_name", is("Peter File")))
+ .andExpect(jsonPath("comment", is("goal of project")))
+ .andExpect(jsonPath("start_date", is("01.01.2000")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var project = this.projectRepository.findById(id);
+ assertThat(project.get().getName()).isEqualTo("name");
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
+ assertThat(project.get().getContractor()).isEqualTo(4);
+ assertThat(project.get().getContractorName()).isEqualTo("Peter File");
+ assertThat(project.get().getComment()).isEqualTo("goal of project");
+ assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
+ assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
+ }
+}
From 013e964be65247ffb42d44f540fda88f4c03df55 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 25 Sep 2024 12:27:34 +0000
Subject: [PATCH 09/31] feat: Write Integration test for Create Project Route
and ensure using Snake Case in JSON Format (SCRUM-7) (!14)
Co-authored-by: Phan Huy Tran
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/14
Reviewed-by: Jan Gleytenhoover
---
requests/createProject.http | 6 +-
.../project/CreateProjectAction.java | 7 +-
.../project/dto/CreateProjectDto.java | 3 +
.../project/dto/GetProjectDto.java | 17 +----
.../project/CreateProjectActionTest.java | 71 +++++++++++++++++++
...ss.java => ProjectFindAllSuccessTest.java} | 16 ++---
6 files changed, 89 insertions(+), 31 deletions(-)
create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
rename src/test/java/de/szut/lf8_starter/integration/project/{ProjectFindAllSuccess.java => ProjectFindAllSuccessTest.java} (80%)
diff --git a/requests/createProject.http b/requests/createProject.http
index add2394..7b08e28 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -8,8 +8,8 @@ Content-Type: application/json
"leading_employee": 1,
"employees": [2, 3],
"contractor": 4,
- "contractorName": "Peter File",
+ "contractor_name": "Peter File",
"comment": "goal of project",
- "startDate": "01.01.2000",
- "plannedEndDate": "01.01.2001"
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
index c41b134..d54318b 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
@@ -8,10 +8,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import jakarta.validation.Valid;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/projects")
@@ -30,6 +28,7 @@ public class CreateProjectAction {
@ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
@ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
@PostMapping
+ @ResponseStatus(code = HttpStatus.CREATED)
public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index 4c6ab0d..ebf4393 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,6 +1,8 @@
package de.szut.lf8_starter.project.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
@@ -11,6 +13,7 @@ import java.util.List;
@Getter
@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class CreateProjectDto {
@NotBlank
private String name;
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index c90cd50..614ece1 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -1,6 +1,8 @@
package de.szut.lf8_starter.project.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Getter;
@@ -11,35 +13,22 @@ import java.util.List;
@Getter
@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
public class GetProjectDto {
private long id;
-
- @NotBlank
private String name;
-
- @NotNull
private long leadingEmployee;
-
private List employees;
-
- @NotNull
private long contractor;
-
- @NotBlank
private String contractorName;
-
- @NotBlank
private String comment;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate startDate;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate plannedEndDate;
- @NotNull
@JsonFormat(pattern = "dd.MM.yyyy")
private LocalDate endDate;
}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
new file mode 100644
index 0000000..36eee54
--- /dev/null
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -0,0 +1,71 @@
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+public class CreateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void createProjectTest() throws Exception {
+ String content = """
+ {
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leading_employee", is(1)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
+ .andExpect(jsonPath("contractor", is(4)))
+ .andExpect(jsonPath("contractor_name", is("Peter File")))
+ .andExpect(jsonPath("comment", is("goal of project")))
+ .andExpect(jsonPath("start_date", is("01.01.2000")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var project = this.projectRepository.findById(id);
+ assertThat(project.get().getName()).isEqualTo("name");
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
+ assertThat(project.get().getContractor()).isEqualTo(4);
+ assertThat(project.get().getContractorName()).isEqualTo("Peter File");
+ assertThat(project.get().getComment()).isEqualTo("goal of project");
+ assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
+ assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
similarity index 80%
rename from src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java
rename to src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
index 906b63f..8f1974a 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccess.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
@@ -6,7 +6,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.web.servlet.MockMvc;
import java.time.LocalDate;
@@ -19,18 +18,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc(addFilters = false)
-public class ProjectFindAllSuccess {
+public class ProjectFindAllSuccessTest {
@Autowired
private ProjectRepository projectRepository;
@Autowired
private MockMvc mockMvc;
- @Autowired
- private TestRestTemplate restTemplate;
-
@Test
- void findAllProjects() throws Exception {
+ void findAllProjectsTest() throws Exception {
var project = new ProjectEntity();
project.setId(1);
project.setComment("comment");
@@ -49,11 +45,11 @@ public class ProjectFindAllSuccess {
.andExpect(jsonPath("$[0].id").value(1))
.andExpect(jsonPath("$[0].comment").value("comment"))
.andExpect(jsonPath("$[0].contractor").value(1))
- .andExpect(jsonPath("$[0].contractorName").value("contractorName"))
- .andExpect(jsonPath("$[0].endDate").value("01.01.2024"))
- .andExpect(jsonPath("$[0].leadingEmployee").value(1))
+ .andExpect(jsonPath("$[0].contractor_name").value("contractorName"))
+ .andExpect(jsonPath("$[0].end_date").value("01.01.2024"))
+ .andExpect(jsonPath("$[0].leading_employee").value(1))
.andExpect(jsonPath("$[0].name").value("name"))
- .andExpect(jsonPath("$[0].startDate").value("01.01.2021"))
+ .andExpect(jsonPath("$[0].start_date").value("01.01.2021"))
.andExpect(jsonPath("$[0].employees").isArray())
.andExpect(jsonPath("$[0].employees", hasSize(3)));
}
From 34609a6eed1930255e3392de8f6e8dab4c1e20f6 Mon Sep 17 00:00:00 2001
From: Jan Gleytenhoover
Date: Wed, 25 Sep 2024 14:15:06 +0000
Subject: [PATCH 10/31] feat: Add sonarqube (!16)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/16
---
.gitea/workflows/build.yml | 38 ++++++++++++++++++++++++++++++++++++++
build.gradle.kts | 8 ++++++++
2 files changed, 46 insertions(+)
create mode 100644 .gitea/workflows/build.yml
diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
new file mode 100644
index 0000000..f143c2a
--- /dev/null
+++ b/.gitea/workflows/build.yml
@@ -0,0 +1,38 @@
+name: Build
+
+on:
+ push:
+ branches:
+ - main
+
+
+jobs:
+ build:
+ name: Build and analyze
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 17
+ uses: actions/setup-java@v1
+ with:
+ java-version: 17
+ - name: Cache SonarQube packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.sonar/cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+ - name: Cache Gradle packages
+ uses: actions/cache@v1
+ with:
+ path: ~/.gradle/caches
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
+ restore-keys: ${{ runner.os }}-gradle
+ - name: Build and analyze
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew build sonar --info
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 9c30a46..469dd94 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,6 +3,14 @@ plugins {
id("org.springframework.boot") version "3.3.4"
id("io.spring.dependency-management") version "1.1.6"
id("checkstyle")
+ id("org.sonarqube") version "5.0.0.4638"
+}
+
+sonar {
+ properties {
+ property("sonar.projectKey", "LF8")
+ property("sonar.projectName", "LF8")
+ }
}
tasks.withType {
From e5f7f192746db67a712085512765177c9214a6b4 Mon Sep 17 00:00:00 2001
From: Jan Gleytenhoover
Date: Wed, 25 Sep 2024 15:15:45 +0000
Subject: [PATCH 11/31] fix: Fix Sonarqube java version (!17)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/17
---
.gitea/workflows/build.yml | 10 +++++++---
Readme.md | 3 +++
build.gradle.kts | 12 +++++++++++-
3 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
index f143c2a..4321e8d 100644
--- a/.gitea/workflows/build.yml
+++ b/.gitea/workflows/build.yml
@@ -5,7 +5,6 @@ on:
branches:
- main
-
jobs:
build:
name: Build and analyze
@@ -15,10 +14,10 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v1
with:
- java-version: 17
+ java-version: 21
- name: Cache SonarQube packages
uses: actions/cache@v1
with:
@@ -31,6 +30,11 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
restore-keys: ${{ runner.os }}-gradle
+ - name: Coverage
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew test jacocoTestReport sonar
- name: Build and analyze
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
diff --git a/Readme.md b/Readme.md
index 1874b0a..8774ce3 100644
--- a/Readme.md
+++ b/Readme.md
@@ -3,6 +3,9 @@


+## Code analysis coverage issues and results of linting MAY be found here:
+https://sonarqube.kjan.de/dashboard?id=LF8&codeScope=overall
+
# Starter für das LF08 Projekt
## Requirements
diff --git a/build.gradle.kts b/build.gradle.kts
index 469dd94..12eda3d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,6 +4,15 @@ plugins {
id("io.spring.dependency-management") version "1.1.6"
id("checkstyle")
id("org.sonarqube") version "5.0.0.4638"
+ id("jacoco")
+}
+
+tasks.jacocoTestReport {
+ dependsOn(tasks.test) // Ensure tests are run before generating the report
+ reports {
+ xml.required = true
+ csv.required = true
+ }
}
sonar {
@@ -67,4 +76,5 @@ dependencies {
tasks.withType {
useJUnitPlatform()
-}
+ finalizedBy(tasks.jacocoTestReport) // Run JaCoCo report after tests
+}
\ No newline at end of file
From 921f5855984401ad50c4f1673eac9b922222f137 Mon Sep 17 00:00:00 2001
From: Renovate
Date: Thu, 26 Sep 2024 05:25:14 +0000
Subject: [PATCH 12/31] chore(deps): update actions/cache action to v4 (!19)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR contains the following updates:
| Package | Type | Update | Change |
|---|---|---|---|
| [actions/cache](https://github.com/actions/cache) | action | major | `v1` -> `v4` |
---
### Release Notes
actions/cache (actions/cache)
### [`v4`](https://github.com/actions/cache/compare/v3...v4)
[Compare Source](https://github.com/actions/cache/compare/v3...v4)
### [`v3`](https://github.com/actions/cache/compare/v2...v3)
[Compare Source](https://github.com/actions/cache/compare/v2...v3)
### [`v2`](https://github.com/actions/cache/compare/v1...v2)
[Compare Source](https://github.com/actions/cache/compare/v1...v2)
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/19
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Renovate
Co-committed-by: Renovate
---
.gitea/workflows/build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml
index 4321e8d..5e9e1cf 100644
--- a/.gitea/workflows/build.yml
+++ b/.gitea/workflows/build.yml
@@ -19,13 +19,13 @@ jobs:
with:
java-version: 21
- name: Cache SonarQube packages
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Cache Gradle packages
- uses: actions/cache@v1
+ uses: actions/cache@v4
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
From 750041a9eb8d96b79aa4fbb4488a6bce134d2556 Mon Sep 17 00:00:00 2001
From: Jan Gleytenhoover
Date: Fri, 27 Sep 2024 09:11:11 +0000
Subject: [PATCH 13/31] feat: SonarQube PR analysis (!21)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/21
---
.gitea/workflows/build-pr.yml | 45 +++++++++++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 .gitea/workflows/build-pr.yml
diff --git a/.gitea/workflows/build-pr.yml b/.gitea/workflows/build-pr.yml
new file mode 100644
index 0000000..ffb5436
--- /dev/null
+++ b/.gitea/workflows/build-pr.yml
@@ -0,0 +1,45 @@
+name: Build PR
+
+on: # test
+ pull_request:
+ types:
+ - opened
+ - reopened
+ - synchronize
+ - ready_for_review
+
+jobs:
+ build:
+ name: Build and analyze
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Set up JDK 21
+ uses: actions/setup-java@v1
+ with:
+ java-version: 21
+ - name: Cache SonarQube packages
+ uses: actions/cache@v4
+ with:
+ path: ~/.sonar/cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+ - name: Cache Gradle packages
+ uses: actions/cache@v4
+ with:
+ path: ~/.gradle/caches
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
+ restore-keys: ${{ runner.os }}-gradle
+ - name: Coverage
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew test jacocoTestReport sonar
+ - name: Build and analyze
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
+ run: ./gradlew build sonar --info -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} -Dsonar.pullrequest.base=${{ github.event.pull_request.base.ref }} -Dsonar.pullrequest.key=${{github.event.pull_request.number}}
\ No newline at end of file
From 1669b29bbd811c54f57a52a5ed39c8f2429811f1 Mon Sep 17 00:00:00 2001
From: Renovate
Date: Fri, 27 Sep 2024 11:58:17 +0000
Subject: [PATCH 14/31] chore(deps): update postgres docker tag to v17 (!22)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR contains the following updates:
| Package | Update | Change |
|---|---|---|
| postgres | major | `16.4` -> `17.0` |
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/22
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Renovate
Co-committed-by: Renovate
---
docker/local/docker-compose.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker/local/docker-compose.yml b/docker/local/docker-compose.yml
index 7b556ef..add2420 100644
--- a/docker/local/docker-compose.yml
+++ b/docker/local/docker-compose.yml
@@ -7,7 +7,7 @@ volumes:
services:
postgres_for_lf8_starter:
container_name: lf8_starter_postgres_container
- image: postgres:16.4
+ image: postgres:17.0
volumes:
- lf8_starter_postgres_data:/var/lib/postgresql/data
environment:
From e5b4e2c0120863288623a91a449f68eecba55b95 Mon Sep 17 00:00:00 2001
From: Renovate
Date: Fri, 27 Sep 2024 12:52:40 +0000
Subject: [PATCH 15/31] chore(deps): update plugin org.sonarqube to v5.1.0.4882
(!18)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR contains the following updates:
| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| org.sonarqube | `5.0.0.4638` -> `5.1.0.4882` | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) | [](https://docs.renovatebot.com/merge-confidence/) |
---
### Configuration
📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/18
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Renovate
Co-committed-by: Renovate
---
build.gradle.kts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 12eda3d..985ba1c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,7 +3,7 @@ plugins {
id("org.springframework.boot") version "3.3.4"
id("io.spring.dependency-management") version "1.1.6"
id("checkstyle")
- id("org.sonarqube") version "5.0.0.4638"
+ id("org.sonarqube") version "5.1.0.4882"
id("jacoco")
}
From 273202842c8252a570f26666200afb6f6e4b7817 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Oct 2024 08:21:10 +0200
Subject: [PATCH 16/31] IDK
---
Readme.md | 2 +-
.../GetBearerToken.http | 0
requests/createProject.http | 28 ++--
.../project/CreateProjectAction.java | 78 +++++-----
.../project/dto/CreateProjectDto.java | 90 +++++------
.../project/dto/GetProjectDto.java | 68 ++++-----
.../project/CreateProjectActionTest.java | 142 +++++++++---------
.../project/ProjectFindAllSuccessTest.java | 112 +++++++-------
8 files changed, 260 insertions(+), 260 deletions(-)
rename GetBearerToken.http => requests/GetBearerToken.http (100%)
diff --git a/Readme.md b/Readme.md
index 1874b0a..bcfc727 100644
--- a/Readme.md
+++ b/Readme.md
@@ -59,7 +59,7 @@ docker compose up
# Keycloak
### Keycloak Token
-1. Auf der Projektebene [GetBearerToken.http](GetBearerToken.http) öffnen.
+1. Auf der Projektebene [GetBearerToken.http](requests/GetBearerToken.http) öffnen.
2. Neben der Request auf den grünen Pfeil drücken
3. Aus dem Reponse das access_token kopieren
diff --git a/GetBearerToken.http b/requests/GetBearerToken.http
similarity index 100%
rename from GetBearerToken.http
rename to requests/GetBearerToken.http
diff --git a/requests/createProject.http b/requests/createProject.http
index 7b08e28..885c49e 100644
--- a/requests/createProject.http
+++ b/requests/createProject.http
@@ -1,15 +1,15 @@
-### GET request to example server
-POST http://localhost:8080/projects
-Authorization: Bearer {{auth_token}}
-Content-Type: application/json
-
-{
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
+### GET request to example server
+POST http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
index d54318b..4158fee 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
@@ -1,39 +1,39 @@
-package de.szut.lf8_starter.project;
-
-import de.szut.lf8_starter.project.dto.CreateProjectDto;
-import de.szut.lf8_starter.project.dto.GetProjectDto;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.http.HttpStatus;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@RequestMapping(value = "/projects")
-public class CreateProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
- this.projectService = projectService;
- this.projectMapper = mappingService;
- }
-
- @Operation(summary = "Creates a new Project")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
- @PostMapping
- @ResponseStatus(code = HttpStatus.CREATED)
- public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
-
- projectEntity = this.projectService.create(projectEntity);
-
- return this.projectMapper.mapToGetDto(projectEntity);
- }
-}
+package de.szut.lf8_starter.project;
+
+import de.szut.lf8_starter.project.dto.CreateProjectDto;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class CreateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public CreateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Creates a new Project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created project", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted", content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
+ @PostMapping
+ @ResponseStatus(code = HttpStatus.CREATED)
+ public GetProjectDto create(@RequestBody @Valid CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = this.projectMapper.mapCreateDtoToEntity(createProjectDto);
+
+ projectEntity = this.projectService.create(projectEntity);
+
+ return this.projectMapper.mapToGetDto(projectEntity);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
index ebf4393..64d22b7 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/CreateProjectDto.java
@@ -1,45 +1,45 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class CreateProjectDto {
- @NotBlank
- private String name;
-
- @NotNull
- private long leadingEmployee;
-
- private List employees;
-
- @NotNull
- private long contractor;
-
- @NotBlank
- private String contractorName;
-
- @NotBlank
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- @NotNull
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class CreateProjectDto {
+ @NotBlank
+ private String name;
+
+ @NotNull
+ private long leadingEmployee;
+
+ private List employees;
+
+ @NotNull
+ private long contractor;
+
+ @NotBlank
+ private String contractorName;
+
+ @NotBlank
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ @NotNull
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index 614ece1..250a6a0 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -1,34 +1,34 @@
-package de.szut.lf8_starter.project.dto;
-
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.databind.PropertyNamingStrategies;
-import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
-import lombok.Getter;
-import lombok.Setter;
-
-import java.time.LocalDate;
-import java.util.List;
-
-@Getter
-@Setter
-@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
-public class GetProjectDto {
- private long id;
- private String name;
- private long leadingEmployee;
- private List employees;
- private long contractor;
- private String contractorName;
- private String comment;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate startDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate plannedEndDate;
-
- @JsonFormat(pattern = "dd.MM.yyyy")
- private LocalDate endDate;
-}
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class GetProjectDto {
+ private long id;
+ private String name;
+ private long leadingEmployee;
+ private List employees;
+ private long contractor;
+ private String contractorName;
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
index 36eee54..06d02b6 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -1,71 +1,71 @@
-package de.szut.lf8_starter.integration.project;
-
-import de.szut.lf8_starter.project.ProjectRepository;
-import org.json.JSONObject;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.http.MediaType;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-import java.util.Arrays;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.hamcrest.Matchers.is;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@SpringBootTest
-@AutoConfigureMockMvc(addFilters = false)
-public class CreateProjectActionTest {
- @Autowired
- private MockMvc mockMvc;
- @Autowired
- private ProjectRepository projectRepository;
-
- @Test
- void createProjectTest() throws Exception {
- String content = """
- {
- "name": "name",
- "leading_employee": 1,
- "employees": [2, 3],
- "contractor": 4,
- "contractor_name": "Peter File",
- "comment": "goal of project",
- "start_date": "01.01.2000",
- "planned_end_date": "01.01.2001"
- }
- """;
-
- final var contentAsString = this.mockMvc.perform(
- post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
- )
- .andExpect(status().isCreated())
- .andExpect(jsonPath("name", is("name")))
- .andExpect(jsonPath("leading_employee", is(1)))
- .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
- .andExpect(jsonPath("contractor", is(4)))
- .andExpect(jsonPath("contractor_name", is("Peter File")))
- .andExpect(jsonPath("comment", is("goal of project")))
- .andExpect(jsonPath("start_date", is("01.01.2000")))
- .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
- .andReturn()
- .getResponse()
- .getContentAsString();
-
- final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
-
- final var project = this.projectRepository.findById(id);
- assertThat(project.get().getName()).isEqualTo("name");
- assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
- assertThat(project.get().getContractor()).isEqualTo(4);
- assertThat(project.get().getContractorName()).isEqualTo("Peter File");
- assertThat(project.get().getComment()).isEqualTo("goal of project");
- assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
- assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
- }
-}
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+public class CreateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void createProjectTest() throws Exception {
+ String content = """
+ {
+ "name": "name",
+ "leading_employee": 1,
+ "employees": [2, 3],
+ "contractor": 4,
+ "contractor_name": "Peter File",
+ "comment": "goal of project",
+ "start_date": "01.01.2000",
+ "planned_end_date": "01.01.2001"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ post("/projects").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isCreated())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leading_employee", is(1)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(2, 3))))
+ .andExpect(jsonPath("contractor", is(4)))
+ .andExpect(jsonPath("contractor_name", is("Peter File")))
+ .andExpect(jsonPath("comment", is("goal of project")))
+ .andExpect(jsonPath("start_date", is("01.01.2000")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2001")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var project = this.projectRepository.findById(id);
+ assertThat(project.get().getName()).isEqualTo("name");
+ assertThat(project.get().getLeadingEmployee()).isEqualTo(1);
+ assertThat(project.get().getContractor()).isEqualTo(4);
+ assertThat(project.get().getContractorName()).isEqualTo("Peter File");
+ assertThat(project.get().getComment()).isEqualTo("goal of project");
+ assertThat(project.get().getStartDate()).isEqualTo(LocalDate.of(2000, 1, 1));
+ assertThat(project.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2001, 1, 1));
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
index 8f1974a..22981bb 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
@@ -1,56 +1,56 @@
-package de.szut.lf8_starter.integration.project;
-
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectRepository;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-import java.util.List;
-
-import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureMockMvc(addFilters = false)
-public class ProjectFindAllSuccessTest {
- @Autowired
- private ProjectRepository projectRepository;
-
- @Autowired
- private MockMvc mockMvc;
-
- @Test
- void findAllProjectsTest() throws Exception {
- var project = new ProjectEntity();
- project.setId(1);
- project.setComment("comment");
- project.setContractor(1);
- project.setContractorName("contractorName");
- project.setEndDate(LocalDate.of(2024, 1, 1));
- project.setLeadingEmployee(1);
- project.setName("name");
- project.setStartDate(LocalDate.of(2021, 1, 1));
- project.setEmployees(List.of(1L,2L,3L));
- this.projectRepository.save(project);
-
- this.mockMvc.perform(get("/projects"))
- .andExpect(status().isOk())
- .andExpect(jsonPath("$", hasSize(1)))
- .andExpect(jsonPath("$[0].id").value(1))
- .andExpect(jsonPath("$[0].comment").value("comment"))
- .andExpect(jsonPath("$[0].contractor").value(1))
- .andExpect(jsonPath("$[0].contractor_name").value("contractorName"))
- .andExpect(jsonPath("$[0].end_date").value("01.01.2024"))
- .andExpect(jsonPath("$[0].leading_employee").value(1))
- .andExpect(jsonPath("$[0].name").value("name"))
- .andExpect(jsonPath("$[0].start_date").value("01.01.2021"))
- .andExpect(jsonPath("$[0].employees").isArray())
- .andExpect(jsonPath("$[0].employees", hasSize(3)));
- }
-}
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureMockMvc(addFilters = false)
+public class ProjectFindAllSuccessTest {
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void findAllProjectsTest() throws Exception {
+ var project = new ProjectEntity();
+ project.setId(1);
+ project.setComment("comment");
+ project.setContractor(1);
+ project.setContractorName("contractorName");
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ project.setLeadingEmployee(1);
+ project.setName("name");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setEmployees(List.of(1L,2L,3L));
+ this.projectRepository.save(project);
+
+ this.mockMvc.perform(get("/projects"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$", hasSize(1)))
+ .andExpect(jsonPath("$[0].id").value(1))
+ .andExpect(jsonPath("$[0].comment").value("comment"))
+ .andExpect(jsonPath("$[0].contractor").value(1))
+ .andExpect(jsonPath("$[0].contractor_name").value("contractorName"))
+ .andExpect(jsonPath("$[0].end_date").value("01.01.2024"))
+ .andExpect(jsonPath("$[0].leading_employee").value(1))
+ .andExpect(jsonPath("$[0].name").value("name"))
+ .andExpect(jsonPath("$[0].start_date").value("01.01.2021"))
+ .andExpect(jsonPath("$[0].employees").isArray())
+ .andExpect(jsonPath("$[0].employees", hasSize(3)));
+ }
+}
From fca0ab89ed5335b7457eb5a3db271977dca30d22 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Oct 2024 08:24:04 +0200
Subject: [PATCH 17/31] REfactor
---
requests/getAllProjects.http | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 requests/getAllProjects.http
diff --git a/requests/getAllProjects.http b/requests/getAllProjects.http
new file mode 100644
index 0000000..21a4ceb
--- /dev/null
+++ b/requests/getAllProjects.http
@@ -0,0 +1,3 @@
+### GET request to example server
+GET http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
From d047bce4ec44b300c4498c833b9a52a4034d0a93 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Oct 2024 06:34:16 +0000
Subject: [PATCH 18/31] refactor: Add and refactor http requests (!24)
Co-authored-by: Phan Huy Tran
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/24
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Phan Huy Tran
Co-committed-by: Phan Huy Tran
---
Readme.md | 2 +-
GetBearerToken.http => requests/GetBearerToken.http | 0
requests/getAllProjects.http | 3 +++
3 files changed, 4 insertions(+), 1 deletion(-)
rename GetBearerToken.http => requests/GetBearerToken.http (100%)
create mode 100644 requests/getAllProjects.http
diff --git a/Readme.md b/Readme.md
index 8774ce3..1e0c8d8 100644
--- a/Readme.md
+++ b/Readme.md
@@ -62,7 +62,7 @@ docker compose up
# Keycloak
### Keycloak Token
-1. Auf der Projektebene [GetBearerToken.http](GetBearerToken.http) öffnen.
+1. Auf der Projektebene [GetBearerToken.http](requests/GetBearerToken.http) öffnen.
2. Neben der Request auf den grünen Pfeil drücken
3. Aus dem Reponse das access_token kopieren
diff --git a/GetBearerToken.http b/requests/GetBearerToken.http
similarity index 100%
rename from GetBearerToken.http
rename to requests/GetBearerToken.http
diff --git a/requests/getAllProjects.http b/requests/getAllProjects.http
new file mode 100644
index 0000000..b56f68d
--- /dev/null
+++ b/requests/getAllProjects.http
@@ -0,0 +1,3 @@
+### GET request to example server
+GET http://localhost:8080/projects
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
From c317b226fe7131a7c7b33076232fa74da2701e9e Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Oct 2024 07:04:08 +0000
Subject: [PATCH 19/31] feat: Implement get project by ID Route (!25)
Co-authored-by: Phan Huy Tran
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/25
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Phan Huy Tran
Co-committed-by: Phan Huy Tran
---
requests/getProject.http | 3 ++
.../lf8_starter/project/ProjectService.java | 12 +++++
.../{ => action}/CreateProjectAction.java | 5 +-
.../GetAllProjectsAction.java} | 22 ++++----
.../project/action/GetProjectAction.java | 40 ++++++++++++++
.../project/FindProjectActionTest.java | 54 +++++++++++++++++++
6 files changed, 126 insertions(+), 10 deletions(-)
create mode 100644 requests/getProject.http
rename src/main/java/de/szut/lf8_starter/project/{ => action}/CreateProjectAction.java (89%)
rename src/main/java/de/szut/lf8_starter/project/{ProjectController.java => action/GetAllProjectsAction.java} (60%)
create mode 100644 src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java
diff --git a/requests/getProject.http b/requests/getProject.http
new file mode 100644
index 0000000..5758af5
--- /dev/null
+++ b/requests/getProject.http
@@ -0,0 +1,3 @@
+### GET request to example server
+GET http://localhost:8080/projects/2
+Authorization: Bearer {{auth_token}}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectService.java b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
index 4dc8688..a815350 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectService.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
@@ -1,8 +1,10 @@
package de.szut.lf8_starter.project;
+import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
import org.springframework.stereotype.Service;
import java.util.List;
+import java.util.Optional;
@Service
public class ProjectService {
@@ -19,4 +21,14 @@ public class ProjectService {
public List readAll() {
return this.projectRepository.findAll();
}
+
+ public ProjectEntity findById(Long id) {
+ Optional articleEntity = projectRepository.findById(id);
+
+ if (articleEntity.isEmpty()) {
+ throw new ResourceNotFoundException("Project with id " + id + " not found");
+ }
+
+ return articleEntity.get();
+ }
}
diff --git a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java
similarity index 89%
rename from src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
rename to src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java
index d54318b..3e636b5 100644
--- a/src/main/java/de/szut/lf8_starter/project/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java
@@ -1,5 +1,8 @@
-package de.szut.lf8_starter.project;
+package de.szut.lf8_starter.project.action;
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
import de.szut.lf8_starter.project.dto.CreateProjectDto;
import de.szut.lf8_starter.project.dto.GetProjectDto;
import io.swagger.v3.oas.annotations.Operation;
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectController.java b/src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java
similarity index 60%
rename from src/main/java/de/szut/lf8_starter/project/ProjectController.java
rename to src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java
index 61ee843..039a104 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectController.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java
@@ -1,32 +1,36 @@
-package de.szut.lf8_starter.project;
+package de.szut.lf8_starter.project.action;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
import de.szut.lf8_starter.project.dto.GetProjectDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping(value = "projects")
-public class ProjectController {
+public class GetAllProjectsAction {
private final ProjectService service;
private final ProjectMapper projectMapper;
- public ProjectController(ProjectService service, ProjectMapper projectMapper) {
+
+ public GetAllProjectsAction(ProjectService service, ProjectMapper projectMapper) {
this.service = service;
this.projectMapper = projectMapper;
}
@Operation(summary = "returns all projects")
@ApiResponses(value = {
- @ApiResponse(responseCode = "200", description = "all projects",
- content = {@Content(mediaType = "application/json",
- schema = @Schema(implementation = GetProjectDto.class))}),
- @ApiResponse(responseCode = "401", description = "not authorized",
- content = @Content)})
+ @ApiResponse(responseCode = "200", description = "all projects", content = {
+ @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
+ }),
+ @ApiResponse(responseCode = "401", description = "not authorized", content = @Content)})
@GetMapping
public List findAll() {
return this.service
diff --git a/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
new file mode 100644
index 0000000..d04ac20
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
@@ -0,0 +1,40 @@
+package de.szut.lf8_starter.project.action;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping(value = "projects")
+public class GetProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public GetProjectAction(ProjectService projectService, ProjectMapper projectMapper) {
+ this.projectService = projectService;
+ this.projectMapper = projectMapper;
+ }
+
+ @Operation(summary = "Find project by ID")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Project found", content = {
+ @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
+ }),
+ @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
+ })
+ @GetMapping("/{id}")
+ public ResponseEntity findArticleById(@PathVariable Long id) {
+ ProjectEntity project = this.projectService.findById(id);
+
+ return new ResponseEntity<>(this.projectMapper.mapToGetDto(project), HttpStatus.OK);
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java
new file mode 100644
index 0000000..dacb171
--- /dev/null
+++ b/src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java
@@ -0,0 +1,54 @@
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+class FindProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void createProjectTest() throws Exception {
+ var project = new ProjectEntity();
+ project.setId(1);
+ project.setComment("comment");
+ project.setContractor(1);
+ project.setContractorName("contractorName");
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ project.setLeadingEmployee(1);
+ project.setName("name");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setEmployees(List.of(1L, 2L, 3L));
+ this.projectRepository.save(project);
+
+ this.mockMvc.perform(get("/projects/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("id").value(1))
+ .andExpect(jsonPath("comment").value("comment"))
+ .andExpect(jsonPath("contractor").value(1))
+ .andExpect(jsonPath("contractor_name").value("contractorName"))
+ .andExpect(jsonPath("end_date").value("01.01.2024"))
+ .andExpect(jsonPath("leading_employee").value(1))
+ .andExpect(jsonPath("name").value("name"))
+ .andExpect(jsonPath("start_date").value("01.01.2021"))
+ .andExpect(jsonPath("employees").isArray())
+ .andExpect(jsonPath("employees", hasSize(3)));
+ }
+}
From a04a1807120e790bd78943eb50a324771fa4346e Mon Sep 17 00:00:00 2001
From: Jan Klattenhoff
Date: Wed, 2 Oct 2024 07:48:32 +0000
Subject: [PATCH 20/31] refactor: Fix some code smells (!26)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/26
Reviewed-by: Phan Huy Tran
Co-authored-by: Jan Klattenhoff
Co-committed-by: Jan Klattenhoff
---
.../exceptionHandling/GlobalExceptionHandler.java | 2 +-
.../lf8_starter/security/KeycloakSecurityConfig.java | 6 +++---
.../de/szut/lf8_starter/welcome/WelcomeController.java | 10 ++++------
3 files changed, 8 insertions(+), 10 deletions(-)
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 68a15a7..8ee2aaf 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -21,7 +21,7 @@ import java.util.Date;
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity> handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ public ResponseEntity handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
index 8ab3fd8..7ff32cc 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
@@ -83,9 +83,9 @@ class KeycloakSecurityConfig {
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
List grantedAuthorities = new ArrayList<>();
- Map realmAccess = jwt.getClaim("realm_access");
- if (realmAccess != null && realmAccess.containsKey("roles")) {
- List roles = (List) realmAccess.get("roles");
+ Map realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
+ if (realmAccess != null && realmAccess.containsKey(ROLES_CLAIM)) {
+ List roles = (List) realmAccess.get(ROLES_CLAIM);
for (String role : roles) {
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
}
diff --git a/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java b/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
index 6ed067b..4effa6b 100644
--- a/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
+++ b/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
@@ -1,14 +1,12 @@
package de.szut.lf8_starter.welcome;
-
-
import org.springframework.http.ResponseEntity;
-import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
-import java.security.Principal;
+import java.util.Collection;
@RestController
public class WelcomeController {
@@ -19,8 +17,8 @@ public class WelcomeController {
}
@GetMapping("/roles")
- public ResponseEntity> getRoles(Authentication authentication) {
- return ResponseEntity.ok(authentication.getAuthorities());
+ public ResponseEntity> getRoles(Authentication authentication) {
+ return ResponseEntity.ok((Collection) authentication.getAuthorities());
}
From cbb77cc1ca3d5550aee36e41b59e4b273afed5a7 Mon Sep 17 00:00:00 2001
From: Jan Klattenhoff
Date: Wed, 2 Oct 2024 08:43:01 +0000
Subject: [PATCH 21/31] refactor: Fix yellow code smells (!27)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/27
Reviewed-by: Phan Huy Tran
Co-authored-by: Jan Klattenhoff
Co-committed-by: Jan Klattenhoff
---
build.gradle.kts | 17 ++++++---
.../config/OpenAPIConfiguration.java | 37 ++++++++++++++-----
.../lf8_starter/hello/HelloController.java | 34 -----------------
.../security/KeycloakLogoutHandler.java | 4 +-
.../security/KeycloakSecurityConfig.java | 6 +--
5 files changed, 41 insertions(+), 57 deletions(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index 985ba1c..d15cf48 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -58,20 +58,25 @@ repositories {
mavenCentral()
}
+val springDocVersion = "2.6.0"
+val oauth2Version = "3.3.4"
+
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-validation")
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocVersion")
+ implementation("org.springframework.boot:spring-boot-starter-security")
+ implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$oauth2Version")
+ implementation("org.springframework.boot:spring-boot-starter-oauth2-client:$oauth2Version")
+
+ testImplementation("com.h2database:h2")
+ testImplementation("org.springframework.boot:spring-boot-starter-test")
+
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
- testImplementation("org.springframework.boot:spring-boot-starter-test")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
- implementation("org.springframework.boot:spring-boot-starter-security")
- implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.3.4")
- implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.3.4")
runtimeOnly("org.postgresql:postgresql")
- implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0")
- testImplementation("com.h2database:h2")
}
tasks.withType {
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 1b2282b..3c782d3 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,7 +1,6 @@
package de.szut.lf8_starter.config;
-
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
@@ -33,15 +32,33 @@ public class OpenAPIConfiguration {
.addServersItem(new Server().url(this.context.getContextPath()))
.info(new Info()
.title("LF8 project starter")
- .description("\n## Auth\n" +
- "\n## Authentication\n" + "\nThis Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:\n\n" +
- "\n" +
- "```\nPOST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token\nContent-Type: application/x-www-form-urlencoded\ngrant_type=password&client_id=employee-management-service&username=user&password=test\n```\n" +
- "\n" +
- "\nor by CURL\n" +
- "```\ncurl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'\n--header 'Content-Type: application/x-www-form-urlencoded'\n--data-urlencode 'grant_type=password'\n--data-urlencode 'client_id=employee-management-service'\n--data-urlencode 'username=user'\n--data-urlencode 'password=test'\n```\n" +
- "\nTo get a bearer-token in Postman, you have to follow the instructions in \n [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).")
-
+ .description("""
+ ## Auth
+
+ ## Authentication
+
+ This Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:
+
+ ```
+ POST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+ Content-Type: application/x-www-form-urlencoded
+ grant_type=password&client_id=employee-management-service&username=user&password=test
+ ```
+
+ or by CURL:
+
+ ```
+ curl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'
+ --header 'Content-Type: application/x-www-form-urlencoded'
+ --data-urlencode 'grant_type=password'
+ --data-urlencode 'client_id=employee-management-service'
+ --data-urlencode 'username=user'
+ --data-urlencode 'password=test'
+ ```
+
+ To get a bearer-token in Postman, you have to follow the instructions in
+ [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).
+ """)
.version("0.1"))
.addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
.components(
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloController.java b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
index 0f665f2..2ca47da 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloController.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
@@ -45,22 +45,6 @@ public class HelloController {
return this.helloMapper.mapToGetDto(helloEntity);
}
- @Operation(summary = "delivers a list of hellos")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "200", description = "list of hellos",
- content = {@Content(mediaType = "application/json",
- schema = @Schema(implementation = HelloGetDto.class))}),
- @ApiResponse(responseCode = "401", description = "not authorized",
- content = @Content)})
- @GetMapping
- public List findAll() {
- return this.service
- .readAll()
- .stream()
- .map(e -> this.helloMapper.mapToGetDto(e))
- .collect(Collectors.toList());
- }
-
@Operation(summary = "deletes a Hello by id")
@ApiResponses(value = {
@ApiResponse(responseCode = "204", description = "delete successful"),
@@ -78,22 +62,4 @@ public class HelloController {
this.service.delete(entity);
}
}
-
- @Operation(summary = "find hellos by message")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "200", description = "List of hellos who have the given message",
- content = {@Content(mediaType = "application/json",
- schema = @Schema(implementation = HelloGetDto.class))}),
- @ApiResponse(responseCode = "404", description = "qualification description does not exist",
- content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized",
- content = @Content)})
- @GetMapping("/findByMessage")
- public List findAllEmployeesByQualification(@RequestParam String message) {
- return this.service
- .findByMessage(message)
- .stream()
- .map(e -> this.helloMapper.mapToGetDto(e))
- .collect(Collectors.toList());
- }
}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index 8555ef9..3051a80 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -25,10 +25,10 @@ public class KeycloakLogoutHandler implements LogoutHandler {
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(request, auth);
+ logout(auth);
}
- public void logout(HttpServletRequest request, Authentication auth) {
+ public void logout(Authentication auth) {
logoutFromKeycloak((OidcUser) auth.getPrincipal());
}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
index 7ff32cc..f64bdd6 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
@@ -29,14 +29,10 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@EnableWebSecurity
class KeycloakSecurityConfig {
- private static final String GROUPS = "groups";
private static final String REALM_ACCESS_CLAIM = "realm_access";
private static final String ROLES_CLAIM = "roles";
- private final KeycloakLogoutHandler keycloakLogoutHandler;
-
- KeycloakSecurityConfig(KeycloakLogoutHandler keycloakLogoutHandler) {
- this.keycloakLogoutHandler = keycloakLogoutHandler;
+ KeycloakSecurityConfig() {
}
@Bean
From 4eb7626c109d1cf888d9f9d207c8cd8f9d133e47 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Oct 2024 08:52:19 +0000
Subject: [PATCH 22/31] feat: Implement Update Project Route (SCRUM-11) (!28)
Co-authored-by: Phan Huy Tran
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/28
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Phan Huy Tran
Co-committed-by: Phan Huy Tran
---
build.gradle.kts | 168 ++++++++--------
requests/getProject.http | 6 +-
requests/updateProject.http | 15 ++
.../config/OpenAPIConfiguration.java | 154 +++++++-------
.../lf8_starter/config/SampleDataCreator.java | 66 +++---
.../GlobalExceptionHandler.java | 110 +++++-----
.../lf8_starter/hello/HelloController.java | 130 ++++++------
.../szut/lf8_starter/hello/HelloEntity.java | 54 ++---
.../szut/lf8_starter/hello/HelloMapper.java | 40 ++--
.../lf8_starter/hello/HelloRepository.java | 24 +--
.../szut/lf8_starter/hello/HelloService.java | 80 ++++----
.../lf8_starter/hello/dto/HelloCreateDto.java | 40 ++--
.../lf8_starter/hello/dto/HelloGetDto.java | 34 ++--
.../lf8_starter/project/ProjectMapper.java | 102 ++++++----
.../lf8_starter/project/ProjectService.java | 67 +++----
.../project/action/GetProjectAction.java | 86 ++++----
.../project/action/UpdateProjectAction.java | 50 +++++
.../project/dto/UpdateProjectDto.java | 36 ++++
.../security/KeycloakLogoutHandler.java | 98 ++++-----
.../security/KeycloakSecurityConfig.java | 188 +++++++++---------
.../welcome/WelcomeController.java | 50 ++---
...ionTest.java => GetProjectActionTest.java} | 113 ++++++-----
.../project/UpdateProjectActionTest.java | 140 +++++++++++++
23 files changed, 1065 insertions(+), 786 deletions(-)
create mode 100644 requests/updateProject.http
create mode 100644 src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java
create mode 100644 src/main/java/de/szut/lf8_starter/project/dto/UpdateProjectDto.java
rename src/test/java/de/szut/lf8_starter/integration/project/{FindProjectActionTest.java => GetProjectActionTest.java} (87%)
create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java
diff --git a/build.gradle.kts b/build.gradle.kts
index d15cf48..0488a79 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,85 +1,85 @@
-plugins {
- java
- id("org.springframework.boot") version "3.3.4"
- id("io.spring.dependency-management") version "1.1.6"
- id("checkstyle")
- id("org.sonarqube") version "5.1.0.4882"
- id("jacoco")
-}
-
-tasks.jacocoTestReport {
- dependsOn(tasks.test) // Ensure tests are run before generating the report
- reports {
- xml.required = true
- csv.required = true
- }
-}
-
-sonar {
- properties {
- property("sonar.projectKey", "LF8")
- property("sonar.projectName", "LF8")
- }
-}
-
-tasks.withType {
- reports {
- // Disable HTML report
- html.required.set(false)
-
- // Disable XML report
- xml.required.set(false)
- }
-}
-
-group = "de.szut"
-version = "0.0.1-SNAPSHOT"
-
-tasks.test {
- useJUnitPlatform()
-
- // Activate the 'test' profile for Spring during tests
- systemProperty("spring.profiles.active", "test")
-}
-
-java {
- toolchain {
- languageVersion = JavaLanguageVersion.of(21)
- }
-}
-
-configurations {
- compileOnly {
- extendsFrom(configurations.annotationProcessor.get())
- }
-}
-
-repositories {
- mavenCentral()
-}
-
-val springDocVersion = "2.6.0"
-val oauth2Version = "3.3.4"
-
-dependencies {
- implementation("org.springframework.boot:spring-boot-starter-data-jpa")
- implementation("org.springframework.boot:spring-boot-starter-web")
- implementation("org.springframework.boot:spring-boot-starter-validation")
- implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocVersion")
- implementation("org.springframework.boot:spring-boot-starter-security")
- implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$oauth2Version")
- implementation("org.springframework.boot:spring-boot-starter-oauth2-client:$oauth2Version")
-
- testImplementation("com.h2database:h2")
- testImplementation("org.springframework.boot:spring-boot-starter-test")
-
- compileOnly("org.projectlombok:lombok")
- annotationProcessor("org.projectlombok:lombok")
- testRuntimeOnly("org.junit.platform:junit-platform-launcher")
- runtimeOnly("org.postgresql:postgresql")
-}
-
-tasks.withType {
- useJUnitPlatform()
- finalizedBy(tasks.jacocoTestReport) // Run JaCoCo report after tests
+plugins {
+ java
+ id("org.springframework.boot") version "3.3.4"
+ id("io.spring.dependency-management") version "1.1.6"
+ id("checkstyle")
+ id("org.sonarqube") version "5.1.0.4882"
+ id("jacoco")
+}
+
+tasks.jacocoTestReport {
+ dependsOn(tasks.test) // Ensure tests are run before generating the report
+ reports {
+ xml.required = true
+ csv.required = true
+ }
+}
+
+sonar {
+ properties {
+ property("sonar.projectKey", "LF8")
+ property("sonar.projectName", "LF8")
+ }
+}
+
+tasks.withType {
+ reports {
+ // Disable HTML report
+ html.required.set(false)
+
+ // Disable XML report
+ xml.required.set(false)
+ }
+}
+
+group = "de.szut"
+version = "0.0.1-SNAPSHOT"
+
+tasks.test {
+ useJUnitPlatform()
+
+ // Activate the 'test' profile for Spring during tests
+ systemProperty("spring.profiles.active", "test")
+}
+
+java {
+ toolchain {
+ languageVersion = JavaLanguageVersion.of(21)
+ }
+}
+
+configurations {
+ compileOnly {
+ extendsFrom(configurations.annotationProcessor.get())
+ }
+}
+
+repositories {
+ mavenCentral()
+}
+
+val springDocVersion = "2.6.0"
+val oauth2Version = "3.3.4"
+
+dependencies {
+ implementation("org.springframework.boot:spring-boot-starter-data-jpa")
+ implementation("org.springframework.boot:spring-boot-starter-web")
+ implementation("org.springframework.boot:spring-boot-starter-validation")
+ implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:$springDocVersion")
+ implementation("org.springframework.boot:spring-boot-starter-security")
+ implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:$oauth2Version")
+ implementation("org.springframework.boot:spring-boot-starter-oauth2-client:$oauth2Version")
+
+ testImplementation("com.h2database:h2")
+ testImplementation("org.springframework.boot:spring-boot-starter-test")
+
+ compileOnly("org.projectlombok:lombok")
+ annotationProcessor("org.projectlombok:lombok")
+ testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+ runtimeOnly("org.postgresql:postgresql")
+}
+
+tasks.withType {
+ useJUnitPlatform()
+ finalizedBy(tasks.jacocoTestReport) // Run JaCoCo report after tests
}
\ No newline at end of file
diff --git a/requests/getProject.http b/requests/getProject.http
index 5758af5..1074d4a 100644
--- a/requests/getProject.http
+++ b/requests/getProject.http
@@ -1,3 +1,3 @@
-### GET request to example server
-GET http://localhost:8080/projects/2
-Authorization: Bearer {{auth_token}}
+### GET request to example server
+GET http://localhost:8080/projects/1
+Authorization: Bearer {{auth_token}}
diff --git a/requests/updateProject.http b/requests/updateProject.http
new file mode 100644
index 0000000..13bf006
--- /dev/null
+++ b/requests/updateProject.http
@@ -0,0 +1,15 @@
+### GET request to example server
+PUT http://localhost:8080/projects/1
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "name": "newName",
+ "leading_employee": 2,
+ "employees": [],
+ "contractor": 9,
+ "contractor_name": "New Contractor name",
+ "comment": "new goal of project",
+ "start_date": "01.01.2010",
+ "planned_end_date": "01.01.2021"
+}
\ No newline at end of file
diff --git a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
index 3c782d3..17f6bda 100644
--- a/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
+++ b/src/main/java/de/szut/lf8_starter/config/OpenAPIConfiguration.java
@@ -1,77 +1,77 @@
-package de.szut.lf8_starter.config;
-
-
-import io.swagger.v3.oas.models.Components;
-import io.swagger.v3.oas.models.OpenAPI;
-import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
-import io.swagger.v3.oas.models.security.SecurityScheme;
-import io.swagger.v3.oas.models.servers.Server;
-import jakarta.servlet.ServletContext;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-
-@Configuration
-public class OpenAPIConfiguration {
-
- private ServletContext context;
-
- public OpenAPIConfiguration(ServletContext context) {
- this.context = context;
- }
-
-
- @Bean
- public OpenAPI springShopOpenAPI(
- // @Value("${info.app.version}") String appVersion,
- ) {
- final String securitySchemeName = "bearerAuth";
-
- return new OpenAPI()
- .addServersItem(new Server().url(this.context.getContextPath()))
- .info(new Info()
- .title("LF8 project starter")
- .description("""
- ## Auth
-
- ## Authentication
-
- This Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:
-
- ```
- POST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
- Content-Type: application/x-www-form-urlencoded
- grant_type=password&client_id=employee-management-service&username=user&password=test
- ```
-
- or by CURL:
-
- ```
- curl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'
- --header 'Content-Type: application/x-www-form-urlencoded'
- --data-urlencode 'grant_type=password'
- --data-urlencode 'client_id=employee-management-service'
- --data-urlencode 'username=user'
- --data-urlencode 'password=test'
- ```
-
- To get a bearer-token in Postman, you have to follow the instructions in
- [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).
- """)
- .version("0.1"))
- .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
- .components(
- new Components()
- .addSecuritySchemes(securitySchemeName,
- new SecurityScheme()
- .name(securitySchemeName)
- .type(SecurityScheme.Type.HTTP)
- .scheme("bearer")
- .bearerFormat("JWT")
- )
- );
- }
-
-
-}
+package de.szut.lf8_starter.config;
+
+
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import io.swagger.v3.oas.models.servers.Server;
+import jakarta.servlet.ServletContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+
+@Configuration
+public class OpenAPIConfiguration {
+
+ private ServletContext context;
+
+ public OpenAPIConfiguration(ServletContext context) {
+ this.context = context;
+ }
+
+
+ @Bean
+ public OpenAPI springShopOpenAPI(
+ // @Value("${info.app.version}") String appVersion,
+ ) {
+ final String securitySchemeName = "bearerAuth";
+
+ return new OpenAPI()
+ .addServersItem(new Server().url(this.context.getContextPath()))
+ .info(new Info()
+ .title("LF8 project starter")
+ .description("""
+ ## Auth
+
+ ## Authentication
+
+ This Hello service uses JWTs to authenticate requests. You will receive a bearer token by making a POST-Request in IntelliJ on:
+
+ ```
+ POST http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token
+ Content-Type: application/x-www-form-urlencoded
+ grant_type=password&client_id=employee-management-service&username=user&password=test
+ ```
+
+ or by CURL:
+
+ ```
+ curl -X POST 'http://keycloak.szut.dev/auth/realms/szut/protocol/openid-connect/token'
+ --header 'Content-Type: application/x-www-form-urlencoded'
+ --data-urlencode 'grant_type=password'
+ --data-urlencode 'client_id=employee-management-service'
+ --data-urlencode 'username=user'
+ --data-urlencode 'password=test'
+ ```
+
+ To get a bearer-token in Postman, you have to follow the instructions in
+ [Postman-Documentation](https://documenter.getpostman.com/view/7294517/SzmfZHnd).
+ """)
+ .version("0.1"))
+ .addSecurityItem(new SecurityRequirement().addList(securitySchemeName))
+ .components(
+ new Components()
+ .addSecuritySchemes(securitySchemeName,
+ new SecurityScheme()
+ .name(securitySchemeName)
+ .type(SecurityScheme.Type.HTTP)
+ .scheme("bearer")
+ .bearerFormat("JWT")
+ )
+ );
+ }
+
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/config/SampleDataCreator.java b/src/main/java/de/szut/lf8_starter/config/SampleDataCreator.java
index 9a7b889..373ea11 100644
--- a/src/main/java/de/szut/lf8_starter/config/SampleDataCreator.java
+++ b/src/main/java/de/szut/lf8_starter/config/SampleDataCreator.java
@@ -1,33 +1,33 @@
-package de.szut.lf8_starter.config;
-
-
-import de.szut.lf8_starter.hello.HelloEntity;
-import de.szut.lf8_starter.hello.HelloRepository;
-import org.springframework.boot.ApplicationArguments;
-import org.springframework.boot.ApplicationRunner;
-import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-
-@Component
-public class SampleDataCreator implements ApplicationRunner {
-
- private HelloRepository repository;
-
- public SampleDataCreator(HelloRepository repository) {
- this.repository = repository;
- }
-
- public void run(ApplicationArguments args) {
- repository.save(new HelloEntity("Hallo Welt!"));
- repository.save(new HelloEntity("Schöner Tag heute"));
- repository.save(new HelloEntity("FooBar"));
-
- }
-
- @Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
-
-}
+package de.szut.lf8_starter.config;
+
+
+import de.szut.lf8_starter.hello.HelloEntity;
+import de.szut.lf8_starter.hello.HelloRepository;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+@Component
+public class SampleDataCreator implements ApplicationRunner {
+
+ private HelloRepository repository;
+
+ public SampleDataCreator(HelloRepository repository) {
+ this.repository = repository;
+ }
+
+ public void run(ApplicationArguments args) {
+ repository.save(new HelloEntity("Hallo Welt!"));
+ repository.save(new HelloEntity("Schöner Tag heute"));
+ repository.save(new HelloEntity("FooBar"));
+
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
index 8ee2aaf..f6415b5 100644
--- a/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
+++ b/src/main/java/de/szut/lf8_starter/exceptionHandling/GlobalExceptionHandler.java
@@ -1,51 +1,59 @@
-package de.szut.lf8_starter.exceptionHandling;
-
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.ConstraintViolationException;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.annotation.ControllerAdvice;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.context.request.WebRequest;
-
-import java.util.Date;
-
-@ControllerAdvice
-@ApiResponses(value = {
- @ApiResponse(responseCode = "500", description = "invalid JSON posted",
- content = @Content)
-})
-public class GlobalExceptionHandler {
-
- @ExceptionHandler(ResourceNotFoundException.class)
- public ResponseEntity handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
- return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
- }
-
- @ExceptionHandler(Exception.class)
- public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
- }
-
- @ExceptionHandler(MethodArgumentNotValidException.class)
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
- ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-
- @ExceptionHandler(ConstraintViolationException.class)
- public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
- String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
-
- ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
-
- return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
- }
-}
+package de.szut.lf8_starter.exceptionHandling;
+
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.ConstraintViolationException;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.Date;
+
+@ControllerAdvice
+@ApiResponses(value = {
+ @ApiResponse(responseCode = "500", description = "invalid JSON posted",
+ content = @Content)
+})
+public class GlobalExceptionHandler {
+
+ @ExceptionHandler(ResourceNotFoundException.class)
+ public ResponseEntity handleHelloEntityNotFoundException(ResourceNotFoundException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleAllOtherExceptions(Exception ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getClass() + " " + ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+ }
+
+ @ExceptionHandler(MethodArgumentNotValidException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(HttpMessageNotReadableException.class)
+ public ResponseEntity handleHttpMessageNotReadableException(HttpMessageNotReadableException ex, WebRequest request) {
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleConstraintViolationException(ConstraintViolationException ex, WebRequest request) {
+ String errorMessage = ex.getConstraintViolations().stream().findFirst().get().getMessage();
+
+ ErrorDetails errorDetails = new ErrorDetails(new Date(), errorMessage, request.getDescription(false));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloController.java b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
index 2ca47da..3a4a993 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloController.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
@@ -1,65 +1,65 @@
-package de.szut.lf8_starter.hello;
-
-
-import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
-import de.szut.lf8_starter.hello.dto.HelloCreateDto;
-import de.szut.lf8_starter.hello.dto.HelloGetDto;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import jakarta.validation.Valid;
-import org.springframework.http.HttpStatus;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-@RestController
-@RequestMapping(value = "hello")
-@PreAuthorize("hasAnyAuthority('user')")
-public class HelloController {
- private final HelloService service;
- private final HelloMapper helloMapper;
-
- public HelloController(HelloService service, HelloMapper mappingService) {
- this.service = service;
- this.helloMapper = mappingService;
- }
-
- @Operation(summary = "creates a new hello with its id and message")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "201", description = "created hello",
- content = {@Content(mediaType = "application/json",
- schema = @Schema(implementation = HelloGetDto.class))}),
- @ApiResponse(responseCode = "400", description = "invalid JSON posted",
- content = @Content),
- @ApiResponse(responseCode = "401", description = "not authorized",
- content = @Content)})
- @PostMapping
- public HelloGetDto create(@RequestBody @Valid HelloCreateDto helloCreateDto) {
- HelloEntity helloEntity = this.helloMapper.mapCreateDtoToEntity(helloCreateDto);
- helloEntity = this.service.create(helloEntity);
- return this.helloMapper.mapToGetDto(helloEntity);
- }
-
- @Operation(summary = "deletes a Hello by id")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "204", description = "delete successful"),
- @ApiResponse(responseCode = "401", description = "not authorized",
- content = @Content),
- @ApiResponse(responseCode = "404", description = "resource not found",
- content = @Content)})
- @DeleteMapping("/{id}")
- @ResponseStatus(code = HttpStatus.NO_CONTENT)
- public void deleteHelloById(@PathVariable long id) {
- var entity = this.service.readById(id);
- if (entity == null) {
- throw new ResourceNotFoundException("HelloEntity not found on id = " + id);
- } else {
- this.service.delete(entity);
- }
- }
-}
+package de.szut.lf8_starter.hello;
+
+
+import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
+import de.szut.lf8_starter.hello.dto.HelloCreateDto;
+import de.szut.lf8_starter.hello.dto.HelloGetDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping(value = "hello")
+@PreAuthorize("hasAnyAuthority('user')")
+public class HelloController {
+ private final HelloService service;
+ private final HelloMapper helloMapper;
+
+ public HelloController(HelloService service, HelloMapper mappingService) {
+ this.service = service;
+ this.helloMapper = mappingService;
+ }
+
+ @Operation(summary = "creates a new hello with its id and message")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "201", description = "created hello",
+ content = {@Content(mediaType = "application/json",
+ schema = @Schema(implementation = HelloGetDto.class))}),
+ @ApiResponse(responseCode = "400", description = "invalid JSON posted",
+ content = @Content),
+ @ApiResponse(responseCode = "401", description = "not authorized",
+ content = @Content)})
+ @PostMapping
+ public HelloGetDto create(@RequestBody @Valid HelloCreateDto helloCreateDto) {
+ HelloEntity helloEntity = this.helloMapper.mapCreateDtoToEntity(helloCreateDto);
+ helloEntity = this.service.create(helloEntity);
+ return this.helloMapper.mapToGetDto(helloEntity);
+ }
+
+ @Operation(summary = "deletes a Hello by id")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "204", description = "delete successful"),
+ @ApiResponse(responseCode = "401", description = "not authorized",
+ content = @Content),
+ @ApiResponse(responseCode = "404", description = "resource not found",
+ content = @Content)})
+ @DeleteMapping("/{id}")
+ @ResponseStatus(code = HttpStatus.NO_CONTENT)
+ public void deleteHelloById(@PathVariable long id) {
+ var entity = this.service.readById(id);
+ if (entity == null) {
+ throw new ResourceNotFoundException("HelloEntity not found on id = " + id);
+ } else {
+ this.service.delete(entity);
+ }
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloEntity.java b/src/main/java/de/szut/lf8_starter/hello/HelloEntity.java
index 1b42cfc..f238e2f 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloEntity.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloEntity.java
@@ -1,27 +1,27 @@
-package de.szut.lf8_starter.hello;
-
-import jakarta.persistence.*;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-
-@NoArgsConstructor
-@AllArgsConstructor
-@Getter
-@Setter
-@Entity
-@Table(name = "hello")
-public class HelloEntity {
-
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- private long id;
-
- private String message;
-
- public HelloEntity(String message) {
- this.message = message;
- }
-}
-
+package de.szut.lf8_starter.hello;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@NoArgsConstructor
+@AllArgsConstructor
+@Getter
+@Setter
+@Entity
+@Table(name = "hello")
+public class HelloEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private long id;
+
+ private String message;
+
+ public HelloEntity(String message) {
+ this.message = message;
+ }
+}
+
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloMapper.java b/src/main/java/de/szut/lf8_starter/hello/HelloMapper.java
index d4feb7e..5639671 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloMapper.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloMapper.java
@@ -1,20 +1,20 @@
-package de.szut.lf8_starter.hello;
-
-
-import de.szut.lf8_starter.hello.dto.HelloCreateDto;
-import de.szut.lf8_starter.hello.dto.HelloGetDto;
-import org.springframework.stereotype.Service;
-
-@Service
-public class HelloMapper {
-
- public HelloGetDto mapToGetDto(HelloEntity entity) {
- return new HelloGetDto(entity.getId(), entity.getMessage());
- }
-
- public HelloEntity mapCreateDtoToEntity(HelloCreateDto dto) {
- var entity = new HelloEntity();
- entity.setMessage(dto.getMessage());
- return entity;
- }
-}
+package de.szut.lf8_starter.hello;
+
+
+import de.szut.lf8_starter.hello.dto.HelloCreateDto;
+import de.szut.lf8_starter.hello.dto.HelloGetDto;
+import org.springframework.stereotype.Service;
+
+@Service
+public class HelloMapper {
+
+ public HelloGetDto mapToGetDto(HelloEntity entity) {
+ return new HelloGetDto(entity.getId(), entity.getMessage());
+ }
+
+ public HelloEntity mapCreateDtoToEntity(HelloCreateDto dto) {
+ var entity = new HelloEntity();
+ entity.setMessage(dto.getMessage());
+ return entity;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloRepository.java b/src/main/java/de/szut/lf8_starter/hello/HelloRepository.java
index 77c76e4..a030a27 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloRepository.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloRepository.java
@@ -1,12 +1,12 @@
-package de.szut.lf8_starter.hello;
-
-
-import org.springframework.data.jpa.repository.JpaRepository;
-
-import java.util.List;
-
-public interface HelloRepository extends JpaRepository {
-
-
- List findByMessage(String message);
-}
+package de.szut.lf8_starter.hello;
+
+
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.List;
+
+public interface HelloRepository extends JpaRepository {
+
+
+ List findByMessage(String message);
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloService.java b/src/main/java/de/szut/lf8_starter/hello/HelloService.java
index eb254e8..b608ee2 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloService.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloService.java
@@ -1,40 +1,40 @@
-package de.szut.lf8_starter.hello;
-
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Optional;
-
-@Service
-public class HelloService {
- private final HelloRepository repository;
-
- public HelloService(HelloRepository repository) {
- this.repository = repository;
- }
-
- public HelloEntity create(HelloEntity entity) {
- return this.repository.save(entity);
- }
-
- public List readAll() {
- return this.repository.findAll();
- }
-
- public HelloEntity readById(long id) {
- Optional optionalQualification = this.repository.findById(id);
- if (optionalQualification.isEmpty()) {
- return null;
- }
- return optionalQualification.get();
- }
-
-
- public void delete(HelloEntity entity) {
- this.repository.delete(entity);
- }
-
- public List findByMessage(String message) {
- return this.repository.findByMessage(message);
- }
-}
+package de.szut.lf8_starter.hello;
+
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class HelloService {
+ private final HelloRepository repository;
+
+ public HelloService(HelloRepository repository) {
+ this.repository = repository;
+ }
+
+ public HelloEntity create(HelloEntity entity) {
+ return this.repository.save(entity);
+ }
+
+ public List readAll() {
+ return this.repository.findAll();
+ }
+
+ public HelloEntity readById(long id) {
+ Optional optionalQualification = this.repository.findById(id);
+ if (optionalQualification.isEmpty()) {
+ return null;
+ }
+ return optionalQualification.get();
+ }
+
+
+ public void delete(HelloEntity entity) {
+ this.repository.delete(entity);
+ }
+
+ public List findByMessage(String message) {
+ return this.repository.findByMessage(message);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/dto/HelloCreateDto.java b/src/main/java/de/szut/lf8_starter/hello/dto/HelloCreateDto.java
index fe47d1e..e0622d5 100644
--- a/src/main/java/de/szut/lf8_starter/hello/dto/HelloCreateDto.java
+++ b/src/main/java/de/szut/lf8_starter/hello/dto/HelloCreateDto.java
@@ -1,20 +1,20 @@
-package de.szut.lf8_starter.hello.dto;
-
-import com.fasterxml.jackson.annotation.JsonCreator;
-import jakarta.validation.constraints.Size;
-import lombok.Getter;
-import lombok.Setter;
-
-
-@Getter
-@Setter
-public class HelloCreateDto {
-
- @Size(min = 3, message = "at least length of 3")
- private String message;
-
- @JsonCreator
- public HelloCreateDto(String message) {
- this.message = message;
- }
-}
+package de.szut.lf8_starter.hello.dto;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import jakarta.validation.constraints.Size;
+import lombok.Getter;
+import lombok.Setter;
+
+
+@Getter
+@Setter
+public class HelloCreateDto {
+
+ @Size(min = 3, message = "at least length of 3")
+ private String message;
+
+ @JsonCreator
+ public HelloCreateDto(String message) {
+ this.message = message;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/hello/dto/HelloGetDto.java b/src/main/java/de/szut/lf8_starter/hello/dto/HelloGetDto.java
index babac4f..1cc51b2 100644
--- a/src/main/java/de/szut/lf8_starter/hello/dto/HelloGetDto.java
+++ b/src/main/java/de/szut/lf8_starter/hello/dto/HelloGetDto.java
@@ -1,17 +1,17 @@
-package de.szut.lf8_starter.hello.dto;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.Setter;
-
-@AllArgsConstructor
-@Getter
-@Setter
-public class HelloGetDto {
-
- private long id;
-
- private String message;
-
-}
-
+package de.szut.lf8_starter.hello.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
+@AllArgsConstructor
+@Getter
+@Setter
+public class HelloGetDto {
+
+ private long id;
+
+ private String message;
+
+}
+
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java b/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java
index fa60491..cb43b84 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectMapper.java
@@ -1,41 +1,61 @@
-package de.szut.lf8_starter.project;
-
-import de.szut.lf8_starter.project.dto.CreateProjectDto;
-import de.szut.lf8_starter.project.dto.GetProjectDto;
-import org.springframework.stereotype.Service;
-
-@Service
-public class ProjectMapper {
- public ProjectEntity mapCreateDtoToEntity(CreateProjectDto createProjectDto) {
- ProjectEntity projectEntity = new ProjectEntity();
-
- projectEntity.setName(createProjectDto.getName());
- projectEntity.setComment(createProjectDto.getComment());
- projectEntity.setLeadingEmployee(createProjectDto.getLeadingEmployee());
- projectEntity.setEmployees(createProjectDto.getEmployees());
- projectEntity.setContractor(createProjectDto.getContractor());
- projectEntity.setContractorName(createProjectDto.getContractorName());
- projectEntity.setStartDate(createProjectDto.getStartDate());
- projectEntity.setPlannedEndDate(createProjectDto.getPlannedEndDate());
- projectEntity.setEndDate(createProjectDto.getEndDate());
-
- return projectEntity;
- }
-
- public GetProjectDto mapToGetDto(ProjectEntity projectEntity) {
- GetProjectDto getProjectDto = new GetProjectDto();
-
- getProjectDto.setId(projectEntity.getId());
- getProjectDto.setName(projectEntity.getName());
- getProjectDto.setComment(projectEntity.getComment());
- getProjectDto.setLeadingEmployee(projectEntity.getLeadingEmployee());
- getProjectDto.setEmployees(projectEntity.getEmployees());
- getProjectDto.setContractor(projectEntity.getContractor());
- getProjectDto.setContractorName(projectEntity.getContractorName());
- getProjectDto.setStartDate(projectEntity.getStartDate());
- getProjectDto.setPlannedEndDate(projectEntity.getPlannedEndDate());
- getProjectDto.setEndDate(projectEntity.getEndDate());
-
- return getProjectDto;
- }
-}
+package de.szut.lf8_starter.project;
+
+import de.szut.lf8_starter.project.dto.CreateProjectDto;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import de.szut.lf8_starter.project.dto.UpdateProjectDto;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ProjectMapper {
+ public ProjectEntity mapCreateDtoToEntity(CreateProjectDto createProjectDto) {
+ ProjectEntity projectEntity = new ProjectEntity();
+
+ projectEntity.setName(createProjectDto.getName());
+ projectEntity.setComment(createProjectDto.getComment());
+ projectEntity.setLeadingEmployee(createProjectDto.getLeadingEmployee());
+ projectEntity.setEmployees(createProjectDto.getEmployees());
+ projectEntity.setContractor(createProjectDto.getContractor());
+ projectEntity.setContractorName(createProjectDto.getContractorName());
+ projectEntity.setStartDate(createProjectDto.getStartDate());
+ projectEntity.setPlannedEndDate(createProjectDto.getPlannedEndDate());
+ projectEntity.setEndDate(createProjectDto.getEndDate());
+
+ return projectEntity;
+ }
+
+ public GetProjectDto mapToGetDto(ProjectEntity projectEntity) {
+ GetProjectDto getProjectDto = new GetProjectDto();
+
+ getProjectDto.setId(projectEntity.getId());
+ getProjectDto.setName(projectEntity.getName());
+ getProjectDto.setComment(projectEntity.getComment());
+ getProjectDto.setLeadingEmployee(projectEntity.getLeadingEmployee());
+ getProjectDto.setEmployees(projectEntity.getEmployees());
+ getProjectDto.setContractor(projectEntity.getContractor());
+ getProjectDto.setContractorName(projectEntity.getContractorName());
+ getProjectDto.setStartDate(projectEntity.getStartDate());
+ getProjectDto.setPlannedEndDate(projectEntity.getPlannedEndDate());
+ getProjectDto.setEndDate(projectEntity.getEndDate());
+
+ return getProjectDto;
+ }
+
+ public ProjectEntity mapUpdateDtoToEntity(UpdateProjectDto updateProjectDto, ProjectEntity projectEntity) {
+ projectEntity.setName(updateProjectDto.getName() != null ? updateProjectDto.getName() : projectEntity.getName());
+ projectEntity.setLeadingEmployee(updateProjectDto.getLeadingEmployee() != null ? updateProjectDto.getLeadingEmployee() : projectEntity.getLeadingEmployee());
+ projectEntity.setContractor(updateProjectDto.getContractor() != null ? updateProjectDto.getContractor() : projectEntity.getContractor());
+ projectEntity.setContractorName(updateProjectDto.getContractorName() != null ? updateProjectDto.getContractorName() : projectEntity.getContractorName());
+ projectEntity.setComment(updateProjectDto.getComment() != null ? updateProjectDto.getComment() : projectEntity.getComment());
+ projectEntity.setStartDate(updateProjectDto.getStartDate() != null ? updateProjectDto.getStartDate() : projectEntity.getStartDate());
+ projectEntity.setPlannedEndDate(updateProjectDto.getPlannedEndDate() != null ? updateProjectDto.getPlannedEndDate() : projectEntity.getPlannedEndDate());
+ projectEntity.setEndDate(updateProjectDto.getEndDate() != null ? updateProjectDto.getEndDate() : projectEntity.getEndDate());
+
+ if (updateProjectDto.getEmployees() != null) {
+ projectEntity.getEmployees().clear();
+
+ projectEntity.setEmployees(updateProjectDto.getEmployees());
+ }
+
+ return projectEntity;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectService.java b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
index a815350..917607f 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectService.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
@@ -1,34 +1,33 @@
-package de.szut.lf8_starter.project;
-
-import de.szut.lf8_starter.exceptionHandling.ResourceNotFoundException;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.Optional;
-
-@Service
-public class ProjectService {
- private final ProjectRepository projectRepository;
-
- public ProjectService(ProjectRepository projectRepository) {
- this.projectRepository = projectRepository;
- }
-
- public ProjectEntity create(ProjectEntity projectEntity) {
- return this.projectRepository.save(projectEntity);
- }
-
- public List readAll() {
- return this.projectRepository.findAll();
- }
-
- public ProjectEntity findById(Long id) {
- Optional articleEntity = projectRepository.findById(id);
-
- if (articleEntity.isEmpty()) {
- throw new ResourceNotFoundException("Project with id " + id + " not found");
- }
-
- return articleEntity.get();
- }
-}
+package de.szut.lf8_starter.project;
+
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class ProjectService {
+ private final ProjectRepository projectRepository;
+
+ public ProjectService(ProjectRepository projectRepository) {
+ this.projectRepository = projectRepository;
+ }
+
+ public ProjectEntity create(ProjectEntity projectEntity) {
+ return this.projectRepository.save(projectEntity);
+ }
+
+ public List readAll() {
+ return this.projectRepository.findAll();
+ }
+
+ public Optional findById(Long id) {
+ return projectRepository.findById(id);
+ }
+
+ public ProjectEntity update(ProjectEntity project) {
+ this.projectRepository.save(project);
+
+ return project;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
index d04ac20..d8e4207 100644
--- a/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
@@ -1,40 +1,46 @@
-package de.szut.lf8_starter.project.action;
-
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectMapper;
-import de.szut.lf8_starter.project.ProjectService;
-import de.szut.lf8_starter.project.dto.GetProjectDto;
-import io.swagger.v3.oas.annotations.Operation;
-import io.swagger.v3.oas.annotations.media.Content;
-import io.swagger.v3.oas.annotations.media.Schema;
-import io.swagger.v3.oas.annotations.responses.ApiResponse;
-import io.swagger.v3.oas.annotations.responses.ApiResponses;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
-
-@RestController
-@RequestMapping(value = "projects")
-public class GetProjectAction {
- private final ProjectService projectService;
- private final ProjectMapper projectMapper;
-
- public GetProjectAction(ProjectService projectService, ProjectMapper projectMapper) {
- this.projectService = projectService;
- this.projectMapper = projectMapper;
- }
-
- @Operation(summary = "Find project by ID")
- @ApiResponses(value = {
- @ApiResponse(responseCode = "200", description = "Project found", content = {
- @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
- }),
- @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
- })
- @GetMapping("/{id}")
- public ResponseEntity findArticleById(@PathVariable Long id) {
- ProjectEntity project = this.projectService.findById(id);
-
- return new ResponseEntity<>(this.projectMapper.mapToGetDto(project), HttpStatus.OK);
- }
-}
+package de.szut.lf8_starter.project.action;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Optional;
+
+@RestController
+@RequestMapping(value = "projects")
+public class GetProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public GetProjectAction(ProjectService projectService, ProjectMapper projectMapper) {
+ this.projectService = projectService;
+ this.projectMapper = projectMapper;
+ }
+
+ @Operation(summary = "Find project by ID")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Project found", content = {
+ @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))
+ }),
+ @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
+ })
+ @GetMapping("/{id}")
+ public ResponseEntity findArticleById(@PathVariable Long id) {
+ Optional project = this.projectService.findById(id);
+
+ if (project.isEmpty()) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+
+ return new ResponseEntity<>(this.projectMapper.mapToGetDto(project.get()), HttpStatus.OK);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java
new file mode 100644
index 0000000..9c174e3
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java
@@ -0,0 +1,50 @@
+package de.szut.lf8_starter.project.action;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectMapper;
+import de.szut.lf8_starter.project.ProjectService;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import de.szut.lf8_starter.project.dto.UpdateProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Optional;
+
+@RestController
+@RequestMapping(value = "/projects")
+public class UpdateProjectAction {
+ private final ProjectService projectService;
+ private final ProjectMapper projectMapper;
+
+ public UpdateProjectAction(ProjectService projectService, ProjectMapper mappingService) {
+ this.projectService = projectService;
+ this.projectMapper = mappingService;
+ }
+
+ @Operation(summary = "Update a project by ID")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "Project updated successfully",
+ content = @Content(mediaType = "application/json", schema = @Schema(implementation = GetProjectDto.class))),
+ @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
+ })
+ @PutMapping("/{id}")
+ public ResponseEntity updateSupplier(@PathVariable Long id, @Valid @RequestBody UpdateProjectDto updateProjectDto) {
+ Optional project = this.projectService.findById(id);
+
+ if (project.isEmpty()) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+
+ ProjectEntity updatedProject = this.projectMapper.mapUpdateDtoToEntity(updateProjectDto, project.get());
+ this.projectService.update(updatedProject);
+
+ return new ResponseEntity<>(this.projectMapper.mapToGetDto(updatedProject), HttpStatus.OK);
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/UpdateProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/UpdateProjectDto.java
new file mode 100644
index 0000000..6d94232
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/dto/UpdateProjectDto.java
@@ -0,0 +1,36 @@
+package de.szut.lf8_starter.project.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.PropertyNamingStrategies;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Getter
+@Setter
+@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
+public class UpdateProjectDto {
+ private String name;
+
+ private Long leadingEmployee;
+
+ private List employees;
+
+ private Long contractor;
+
+ private String contractorName;
+
+ private String comment;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate startDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate plannedEndDate;
+
+ @JsonFormat(pattern = "dd.MM.yyyy")
+ private LocalDate endDate;
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
index 3051a80..b35df69 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakLogoutHandler.java
@@ -1,49 +1,49 @@
-package de.szut.lf8_starter.security;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.oauth2.core.oidc.user.OidcUser;
-import org.springframework.security.web.authentication.logout.LogoutHandler;
-import org.springframework.stereotype.Component;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.UriComponentsBuilder;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-
-@Slf4j
-@Component
-public class KeycloakLogoutHandler implements LogoutHandler {
-
-
- private final RestTemplate restTemplate;
-
- public KeycloakLogoutHandler(RestTemplate restTemplate) {
- this.restTemplate = restTemplate;
- }
-
- @Override
- public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
- logout(auth);
- }
-
- public void logout(Authentication auth) {
- logoutFromKeycloak((OidcUser) auth.getPrincipal());
- }
-
- private void logoutFromKeycloak(OidcUser user) {
- String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
- UriComponentsBuilder builder = UriComponentsBuilder
- .fromUriString(endSessionEndpoint)
- .queryParam("id_token_hint", user.getIdToken().getTokenValue());
-
- ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
- if (logoutResponse.getStatusCode().is2xxSuccessful()) {
- log.info("Successfulley logged out from Keycloak");
- } else {
- log.error("Could not propagate logout to Keycloak");
- }
- }
-
-}
+package de.szut.lf8_starter.security;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.web.authentication.logout.LogoutHandler;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+@Slf4j
+@Component
+public class KeycloakLogoutHandler implements LogoutHandler {
+
+
+ private final RestTemplate restTemplate;
+
+ public KeycloakLogoutHandler(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ @Override
+ public void logout(HttpServletRequest request, HttpServletResponse response, Authentication auth) {
+ logout(auth);
+ }
+
+ public void logout(Authentication auth) {
+ logoutFromKeycloak((OidcUser) auth.getPrincipal());
+ }
+
+ private void logoutFromKeycloak(OidcUser user) {
+ String endSessionEndpoint = user.getIssuer() + "/protocol/openid-connect/logout";
+ UriComponentsBuilder builder = UriComponentsBuilder
+ .fromUriString(endSessionEndpoint)
+ .queryParam("id_token_hint", user.getIdToken().getTokenValue());
+
+ ResponseEntity logoutResponse = restTemplate.getForEntity(builder.toUriString(), String.class);
+ if (logoutResponse.getStatusCode().is2xxSuccessful()) {
+ log.info("Successfulley logged out from Keycloak");
+ } else {
+ log.error("Could not propagate logout to Keycloak");
+ }
+ }
+
+}
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
index f64bdd6..cd03823 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
@@ -1,94 +1,94 @@
-package de.szut.lf8_starter.security;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Profile;
-import org.springframework.http.HttpMethod;
-import org.springframework.security.config.Customizer;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
-import org.springframework.security.core.session.SessionRegistry;
-import org.springframework.security.core.session.SessionRegistryImpl;
-import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
-import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
-import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
-import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
-import org.springframework.security.web.SecurityFilterChain;
-import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
-import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
-import org.springframework.security.web.session.HttpSessionEventPublisher;
-import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
-
-@Configuration
-@EnableWebSecurity
-class KeycloakSecurityConfig {
-
- private static final String REALM_ACCESS_CLAIM = "realm_access";
- private static final String ROLES_CLAIM = "roles";
-
- KeycloakSecurityConfig() {
- }
-
- @Bean
- public SessionRegistry sessionRegistry() {
- return new SessionRegistryImpl();
- }
-
- @Bean
- protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
- return new RegisterSessionAuthenticationStrategy(sessionRegistry());
- }
-
- @Bean
- public HttpSessionEventPublisher httpSessionEventPublisher() {
- return new HttpSessionEventPublisher();
- }
-
-
- @Bean
- public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
-
- http.authorizeHttpRequests(auth -> auth
- .requestMatchers(new AntPathRequestMatcher("/welcome"))
- .permitAll()
- .requestMatchers(
- new AntPathRequestMatcher("/swagger"),
- new AntPathRequestMatcher("/swagger-ui/**"),
- new AntPathRequestMatcher("/v3/api-docs/**"))
- .permitAll()
- .requestMatchers(new AntPathRequestMatcher("/hello/**"))
- .hasRole("user")
- .requestMatchers(new AntPathRequestMatcher("/roles"))
- .authenticated()
- .requestMatchers(new AntPathRequestMatcher("/"))
- .permitAll()
- .anyRequest()
- .authenticated()).oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()));
- return http.build();
- }
-
- @Bean
- public JwtAuthenticationConverter jwtAuthenticationConverter() {
- JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
- jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
- List grantedAuthorities = new ArrayList<>();
-
- Map realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
- if (realmAccess != null && realmAccess.containsKey(ROLES_CLAIM)) {
- List roles = (List) realmAccess.get(ROLES_CLAIM);
- for (String role : roles) {
- grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
- }
- }
-
- return grantedAuthorities;
- });
- return jwtAuthenticationConverter;
- }
-}
+package de.szut.lf8_starter.security;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.Customizer;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
+import org.springframework.security.core.session.SessionRegistry;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
+import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.security.web.session.HttpSessionEventPublisher;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+
+@Configuration
+@EnableWebSecurity
+class KeycloakSecurityConfig {
+
+ private static final String REALM_ACCESS_CLAIM = "realm_access";
+ private static final String ROLES_CLAIM = "roles";
+
+ KeycloakSecurityConfig() {
+ }
+
+ @Bean
+ public SessionRegistry sessionRegistry() {
+ return new SessionRegistryImpl();
+ }
+
+ @Bean
+ protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+ return new RegisterSessionAuthenticationStrategy(sessionRegistry());
+ }
+
+ @Bean
+ public HttpSessionEventPublisher httpSessionEventPublisher() {
+ return new HttpSessionEventPublisher();
+ }
+
+
+ @Bean
+ public SecurityFilterChain resourceServerFilterChain(HttpSecurity http) throws Exception {
+
+ http.authorizeHttpRequests(auth -> auth
+ .requestMatchers(new AntPathRequestMatcher("/welcome"))
+ .permitAll()
+ .requestMatchers(
+ new AntPathRequestMatcher("/swagger"),
+ new AntPathRequestMatcher("/swagger-ui/**"),
+ new AntPathRequestMatcher("/v3/api-docs/**"))
+ .permitAll()
+ .requestMatchers(new AntPathRequestMatcher("/hello/**"))
+ .hasRole("user")
+ .requestMatchers(new AntPathRequestMatcher("/roles"))
+ .authenticated()
+ .requestMatchers(new AntPathRequestMatcher("/"))
+ .permitAll()
+ .anyRequest()
+ .authenticated()).oauth2ResourceServer(spec -> spec.jwt(Customizer.withDefaults()));
+ return http.build();
+ }
+
+ @Bean
+ public JwtAuthenticationConverter jwtAuthenticationConverter() {
+ JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
+ jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwt -> {
+ List grantedAuthorities = new ArrayList<>();
+
+ Map realmAccess = jwt.getClaim(REALM_ACCESS_CLAIM);
+ if (realmAccess != null && realmAccess.containsKey(ROLES_CLAIM)) {
+ List roles = (List) realmAccess.get(ROLES_CLAIM);
+ for (String role : roles) {
+ grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role));
+ }
+ }
+
+ return grantedAuthorities;
+ });
+ return jwtAuthenticationConverter;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java b/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
index 4effa6b..41293bc 100644
--- a/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
+++ b/src/main/java/de/szut/lf8_starter/welcome/WelcomeController.java
@@ -1,25 +1,25 @@
-package de.szut.lf8_starter.welcome;
-
-import org.springframework.http.ResponseEntity;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.Collection;
-
-@RestController
-public class WelcomeController {
-
- @GetMapping("/welcome")
- public String welcome() {
- return "welcome to lf8_starter";
- }
-
- @GetMapping("/roles")
- public ResponseEntity> getRoles(Authentication authentication) {
- return ResponseEntity.ok((Collection) authentication.getAuthorities());
- }
-
-
-}
+package de.szut.lf8_starter.welcome;
+
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collection;
+
+@RestController
+public class WelcomeController {
+
+ @GetMapping("/welcome")
+ public String welcome() {
+ return "welcome to lf8_starter";
+ }
+
+ @GetMapping("/roles")
+ public ResponseEntity> getRoles(Authentication authentication) {
+ return ResponseEntity.ok((Collection) authentication.getAuthorities());
+ }
+
+
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/GetProjectActionTest.java
similarity index 87%
rename from src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java
rename to src/test/java/de/szut/lf8_starter/integration/project/GetProjectActionTest.java
index dacb171..751d002 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/FindProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/GetProjectActionTest.java
@@ -1,54 +1,59 @@
-package de.szut.lf8_starter.integration.project;
-
-import de.szut.lf8_starter.project.ProjectEntity;
-import de.szut.lf8_starter.project.ProjectRepository;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.web.servlet.MockMvc;
-
-import java.time.LocalDate;
-import java.util.List;
-
-import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-@SpringBootTest
-@AutoConfigureMockMvc(addFilters = false)
-class FindProjectActionTest {
- @Autowired
- private MockMvc mockMvc;
- @Autowired
- private ProjectRepository projectRepository;
-
- @Test
- void createProjectTest() throws Exception {
- var project = new ProjectEntity();
- project.setId(1);
- project.setComment("comment");
- project.setContractor(1);
- project.setContractorName("contractorName");
- project.setEndDate(LocalDate.of(2024, 1, 1));
- project.setLeadingEmployee(1);
- project.setName("name");
- project.setStartDate(LocalDate.of(2021, 1, 1));
- project.setEmployees(List.of(1L, 2L, 3L));
- this.projectRepository.save(project);
-
- this.mockMvc.perform(get("/projects/1"))
- .andExpect(status().isOk())
- .andExpect(jsonPath("id").value(1))
- .andExpect(jsonPath("comment").value("comment"))
- .andExpect(jsonPath("contractor").value(1))
- .andExpect(jsonPath("contractor_name").value("contractorName"))
- .andExpect(jsonPath("end_date").value("01.01.2024"))
- .andExpect(jsonPath("leading_employee").value(1))
- .andExpect(jsonPath("name").value("name"))
- .andExpect(jsonPath("start_date").value("01.01.2021"))
- .andExpect(jsonPath("employees").isArray())
- .andExpect(jsonPath("employees", hasSize(3)));
- }
-}
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+class GetProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void getProjectTest() throws Exception {
+ var project = new ProjectEntity();
+ project.setId(1);
+ project.setComment("comment");
+ project.setContractor(1);
+ project.setContractorName("contractorName");
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ project.setLeadingEmployee(1);
+ project.setName("name");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setEmployees(List.of(1L, 2L, 3L));
+ this.projectRepository.save(project);
+
+ this.mockMvc.perform(get("/projects/1"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("id").value(1))
+ .andExpect(jsonPath("comment").value("comment"))
+ .andExpect(jsonPath("contractor").value(1))
+ .andExpect(jsonPath("contractor_name").value("contractorName"))
+ .andExpect(jsonPath("end_date").value("01.01.2024"))
+ .andExpect(jsonPath("leading_employee").value(1))
+ .andExpect(jsonPath("name").value("name"))
+ .andExpect(jsonPath("start_date").value("01.01.2021"))
+ .andExpect(jsonPath("employees").isArray())
+ .andExpect(jsonPath("employees", hasSize(3)));
+ }
+
+ @Test
+ void getProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception {
+ this.mockMvc.perform(get("/projects/2")).andExpect(status().isNotFound());
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java
new file mode 100644
index 0000000..4e53c8c
--- /dev/null
+++ b/src/test/java/de/szut/lf8_starter/integration/project/UpdateProjectActionTest.java
@@ -0,0 +1,140 @@
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.json.JSONObject;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+class UpdateProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void updateProjectShouldUpdateProject() throws Exception {
+ ProjectEntity project = new ProjectEntity();
+ project.setId(1);
+ project.setComment("comment");
+ project.setContractor(1);
+ project.setContractorName("contractorName");
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ project.setLeadingEmployee(1);
+ project.setName("name");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setEmployees(List.of(1L, 2L, 3L));
+ this.projectRepository.save(project);
+
+ String content = """
+ {
+ "name": "updatedName",
+ "leading_employee": 2,
+ "employees": [3, 4, 5],
+ "contractor": 6,
+ "contractor_name": "Updated Contractor name",
+ "comment": "new goal of project",
+ "start_date": "01.01.2021",
+ "planned_end_date": "01.01.2022"
+ }
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ put("/projects/1").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("name", is("updatedName")))
+ .andExpect(jsonPath("leading_employee", is(2)))
+ .andExpect(jsonPath("employees", is(Arrays.asList(3, 4, 5))))
+ .andExpect(jsonPath("contractor", is(6)))
+ .andExpect(jsonPath("contractor_name", is("Updated Contractor name")))
+ .andExpect(jsonPath("comment", is("new goal of project")))
+ .andExpect(jsonPath("start_date", is("01.01.2021")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2022")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var existingProject = this.projectRepository.findById(id);
+ assertThat(existingProject.get().getName()).isEqualTo("updatedName");
+ assertThat(existingProject.get().getLeadingEmployee()).isEqualTo(2);
+ assertThat(existingProject.get().getContractor()).isEqualTo(6);
+ assertThat(existingProject.get().getContractorName()).isEqualTo("Updated Contractor name");
+ assertThat(existingProject.get().getComment()).isEqualTo("new goal of project");
+ assertThat(existingProject.get().getStartDate()).isEqualTo(LocalDate.of(2021, 1, 1));
+ assertThat(existingProject.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2022, 1, 1));
+
+ }
+
+ @Test
+ void updateProjectShouldUpdateProjectPartially() throws Exception {
+ ProjectEntity project = new ProjectEntity();
+ project.setId(1);
+ project.setName("name");
+ project.setLeadingEmployee(1);
+ project.setContractor(1);
+ project.setComment("comment");
+ project.setEmployees(List.of(1L, 2L, 3L));
+ project.setContractorName("contractorName");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setPlannedEndDate(LocalDate.of(2023, 1, 1));
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ this.projectRepository.save(project);
+
+ String content = """
+ {}
+ """;
+
+ final var contentAsString = this.mockMvc.perform(
+ put("/projects/1").content(content).contentType(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("name", is("name")))
+ .andExpect(jsonPath("leading_employee", is(1)))
+ .andExpect(jsonPath("employees", is(List.of(1,2,3))))
+ .andExpect(jsonPath("contractor", is(1)))
+ .andExpect(jsonPath("contractor_name", is("contractorName")))
+ .andExpect(jsonPath("comment", is("comment")))
+ .andExpect(jsonPath("start_date", is("01.01.2021")))
+ .andExpect(jsonPath("planned_end_date", is("01.01.2023")))
+ .andExpect(jsonPath("end_date", is("01.01.2024")))
+ .andReturn()
+ .getResponse()
+ .getContentAsString();
+
+ final var id = Long.parseLong(new JSONObject(contentAsString).get("id").toString());
+
+ final var existingProject = this.projectRepository.findById(id);
+ assertThat(existingProject.get().getName()).isEqualTo("name");
+ assertThat(existingProject.get().getLeadingEmployee()).isEqualTo(1);
+ assertThat(existingProject.get().getContractor()).isEqualTo(1);
+ assertThat(existingProject.get().getContractorName()).isEqualTo("contractorName");
+ assertThat(existingProject.get().getComment()).isEqualTo("comment");
+ assertThat(existingProject.get().getStartDate()).isEqualTo(LocalDate.of(2021, 1, 1));
+ assertThat(existingProject.get().getPlannedEndDate()).isEqualTo(LocalDate.of(2023, 1, 1));
+ assertThat(existingProject.get().getEndDate()).isEqualTo(LocalDate.of(2024, 1, 1));
+ }
+
+ @Test
+ void updateProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception {
+ this.mockMvc.perform(put("/projects/2").content("{}").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isNotFound());
+ }
+}
From b2ef8ce2abe610ca7263e82fc14bc8fec12ec23d Mon Sep 17 00:00:00 2001
From: Jan Klattenhoff
Date: Wed, 2 Oct 2024 09:43:10 +0000
Subject: [PATCH 23/31] feat(project): Delete project (SCRUM-35) (!29)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/29
Reviewed-by: Phan Huy Tran
Co-authored-by: Jan Klattenhoff
Co-committed-by: Jan Klattenhoff
---
.../lf8_starter/project/ProjectService.java | 4 ++
.../project/action/RemoveProjectAction.java | 40 ++++++++++++++++
.../project/DeleteProjectActionTest.java | 47 +++++++++++++++++++
3 files changed, 91 insertions(+)
create mode 100644 src/main/java/de/szut/lf8_starter/project/action/RemoveProjectAction.java
create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectService.java b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
index 917607f..31efbec 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectService.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
@@ -30,4 +30,8 @@ public class ProjectService {
return project;
}
+
+ public void delete(Long id) {
+ this.projectRepository.deleteById(id);
+ }
}
diff --git a/src/main/java/de/szut/lf8_starter/project/action/RemoveProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/RemoveProjectAction.java
new file mode 100644
index 0000000..d14dbee
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/action/RemoveProjectAction.java
@@ -0,0 +1,40 @@
+package de.szut.lf8_starter.project.action;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectService;
+import de.szut.lf8_starter.project.dto.GetProjectDto;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Optional;
+
+@RestController
+@RequestMapping(value = "projects")
+public class RemoveProjectAction {
+ private final ProjectService projectService;
+
+ public RemoveProjectAction(ProjectService projectService) {
+ this.projectService = projectService;
+ }
+
+ @Operation(summary = "Remove project by ID")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "204", description = "Project deleted", content = {}),
+ @ApiResponse(responseCode = "404", description = "Project not found", content = @Content)
+ })
+ @DeleteMapping("/{id}")
+ public ResponseEntity findArticleById(@PathVariable Long id) {
+ Optional project = this.projectService.findById(id);
+ if (project.isEmpty()) {
+ return new ResponseEntity<>(HttpStatus.NOT_FOUND);
+ }
+
+ this.projectService.delete(id);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+}
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java
new file mode 100644
index 0000000..93285ab
--- /dev/null
+++ b/src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java
@@ -0,0 +1,47 @@
+package de.szut.lf8_starter.integration.project;
+
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectRepository;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+
+import java.time.LocalDate;
+import java.util.List;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+@SpringBootTest
+@AutoConfigureMockMvc(addFilters = false)
+class RemoveProjectActionTest {
+ @Autowired
+ private MockMvc mockMvc;
+ @Autowired
+ private ProjectRepository projectRepository;
+
+ @Test
+ void deleteProjectTest() throws Exception {
+ var project = new ProjectEntity();
+ project.setComment("comment");
+ project.setContractor(1);
+ project.setContractorName("contractorName");
+ project.setEndDate(LocalDate.of(2024, 1, 1));
+ project.setLeadingEmployee(1);
+ project.setName("name");
+ project.setStartDate(LocalDate.of(2021, 1, 1));
+ project.setEmployees(List.of(1L, 2L, 3L));
+ this.projectRepository.save(project);
+
+ this.mockMvc.perform(delete("/projects/" + project.getId()))
+ .andExpect(status().isNoContent());
+ }
+
+ @Test
+ void deleteProjectShouldReturnNotFoundResponseWhenProjectIsNotFound() throws Exception {
+ this.mockMvc.perform(get("/projects/2987")).andExpect(status().isNotFound());
+ }
+}
From 8230337839677c146bd53a6ce14d4378d53368e6 Mon Sep 17 00:00:00 2001
From: Jan Klattenhoff
Date: Wed, 2 Oct 2024 10:09:07 +0000
Subject: [PATCH 24/31] refactor: remove unused imports and clean up code (!30)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/30
Reviewed-by: Phan Huy Tran
Co-authored-by: Jan Klattenhoff
Co-committed-by: Jan Klattenhoff
---
.../java/de/szut/lf8_starter/hello/HelloController.java | 3 ---
.../de/szut/lf8_starter/project/dto/GetProjectDto.java | 2 --
.../szut/lf8_starter/security/KeycloakSecurityConfig.java | 7 -------
.../de/szut/lf8_starter/Lf8StarterApplicationTests.java | 1 -
.../project/ProjectFindAllNotAuthenticated.java | 5 -----
...ProjectActionTest.java => RemoveProjectActionTest.java} | 0
6 files changed, 18 deletions(-)
rename src/test/java/de/szut/lf8_starter/integration/project/{DeleteProjectActionTest.java => RemoveProjectActionTest.java} (100%)
diff --git a/src/main/java/de/szut/lf8_starter/hello/HelloController.java b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
index 3a4a993..f6baab4 100644
--- a/src/main/java/de/szut/lf8_starter/hello/HelloController.java
+++ b/src/main/java/de/szut/lf8_starter/hello/HelloController.java
@@ -14,9 +14,6 @@ import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
-import java.util.List;
-import java.util.stream.Collectors;
-
@RestController
@RequestMapping(value = "hello")
@PreAuthorize("hasAnyAuthority('user')")
diff --git a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
index 614ece1..90ebe5e 100644
--- a/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
+++ b/src/main/java/de/szut/lf8_starter/project/dto/GetProjectDto.java
@@ -3,8 +3,6 @@ package de.szut.lf8_starter.project.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.annotation.JsonNaming;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotNull;
import lombok.Getter;
import lombok.Setter;
diff --git a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
index cd03823..99fbc5d 100644
--- a/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
+++ b/src/main/java/de/szut/lf8_starter/security/KeycloakSecurityConfig.java
@@ -1,24 +1,17 @@
package de.szut.lf8_starter.security;
import java.util.*;
-import java.util.stream.Collectors;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.Profile;
-import org.springframework.http.HttpMethod;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
-import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
-import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
-import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
diff --git a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
index b5c7f7b..942f2cb 100644
--- a/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
+++ b/src/test/java/de/szut/lf8_starter/Lf8StarterApplicationTests.java
@@ -2,7 +2,6 @@ package de.szut.lf8_starter;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.context.TestPropertySource;
@SpringBootTest
class Lf8StarterApplicationTests {
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
index 8c62848..307ad4d 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
@@ -1,6 +1,5 @@
package de.szut.lf8_starter.integration.project;
-import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -9,12 +8,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.test.web.servlet.MockMvc;
-import java.time.LocalDate;
-import java.util.List;
-import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/RemoveProjectActionTest.java
similarity index 100%
rename from src/test/java/de/szut/lf8_starter/integration/project/DeleteProjectActionTest.java
rename to src/test/java/de/szut/lf8_starter/integration/project/RemoveProjectActionTest.java
From 1e38efaa63f8b640c0b7ee99b8d5d07ab0bc5866 Mon Sep 17 00:00:00 2001
From: Jan Klattenhoff
Date: Wed, 2 Oct 2024 10:29:39 +0000
Subject: [PATCH 25/31] refactor(test): remove access modifiers from test
classes (!31)
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/31
Reviewed-by: Phan Huy Tran
Co-authored-by: Jan Klattenhoff
Co-committed-by: Jan Klattenhoff
---
.../integration/project/CreateProjectActionTest.java | 2 +-
.../integration/project/ProjectFindAllNotAuthenticated.java | 2 +-
.../integration/project/ProjectFindAllSuccessTest.java | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
index 36eee54..af10c64 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/CreateProjectActionTest.java
@@ -20,7 +20,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest
@AutoConfigureMockMvc(addFilters = false)
-public class CreateProjectActionTest {
+class CreateProjectActionTest {
@Autowired
private MockMvc mockMvc;
@Autowired
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
index 307ad4d..bda3c51 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllNotAuthenticated.java
@@ -14,7 +14,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc(addFilters = true)
-public class ProjectFindAllNotAuthenticated {
+class ProjectFindAllNotAuthenticated {
@Autowired
private ProjectRepository projectRepository;
diff --git a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
index 8f1974a..3fa8bd8 100644
--- a/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
+++ b/src/test/java/de/szut/lf8_starter/integration/project/ProjectFindAllSuccessTest.java
@@ -18,7 +18,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc(addFilters = false)
-public class ProjectFindAllSuccessTest {
+class ProjectFindAllSuccessTest {
@Autowired
private ProjectRepository projectRepository;
From 1008278fde124a5f4e345261f2b013be2414e96f Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 23 Oct 2024 08:39:25 +0000
Subject: [PATCH 26/31] feat: Implement add employee to project route (SCRUM-2)
(!32)
Co-authored-by: Phan Huy Tran
Reviewed-on: https://git.kjan.de/jank/LF8/pulls/32
Reviewed-by: Jan Gleytenhoover
Co-authored-by: Phan Huy Tran
Co-committed-by: Phan Huy Tran
---
requests/employee/createEmployee.http | 12 +++
requests/employee/deleteEmployee.http | 2 +
requests/employee/getAllEmployees.http | 2 +
requests/employee/getEmployee.http | 2 +
requests/project/addEmployeeToProject.http | 2 +
requests/{ => project}/createProject.http | 0
requests/{ => project}/getAllProjects.http | 0
requests/{ => project}/getProject.http | 0
requests/{ => project}/updateProject.http | 0
.../lf8_starter/employee/EmployeeService.java | 34 ++++++++
.../lf8_starter/project/ProjectEntity.java | 2 +-
.../lf8_starter/project/ProjectService.java | 4 +-
.../{ => crud}/CreateProjectAction.java | 2 +-
.../{ => crud}/GetAllProjectsAction.java | 2 +-
.../action/{ => crud}/GetProjectAction.java | 7 +-
.../{ => crud}/UpdateProjectAction.java | 2 +-
.../employee/AddEmployeeToProjectAction.java | 55 +++++++++++++
.../lf8_starter/project/dto/EmployeeDto.java | 22 ++++++
.../project/AddEmployeeToProjectTest.java | 77 +++++++++++++++++++
.../project/CreateProjectActionTest.java | 28 +++----
.../project/GetProjectActionTest.java | 4 +-
.../project/ProjectFindAllSuccessTest.java | 4 +-
.../project/RemoveProjectActionTest.java | 2 +-
.../project/UpdateProjectActionTest.java | 15 ++--
24 files changed, 246 insertions(+), 34 deletions(-)
create mode 100644 requests/employee/createEmployee.http
create mode 100644 requests/employee/deleteEmployee.http
create mode 100644 requests/employee/getAllEmployees.http
create mode 100644 requests/employee/getEmployee.http
create mode 100644 requests/project/addEmployeeToProject.http
rename requests/{ => project}/createProject.http (100%)
rename requests/{ => project}/getAllProjects.http (100%)
rename requests/{ => project}/getProject.http (100%)
rename requests/{ => project}/updateProject.http (100%)
create mode 100644 src/main/java/de/szut/lf8_starter/employee/EmployeeService.java
rename src/main/java/de/szut/lf8_starter/project/action/{ => crud}/CreateProjectAction.java (97%)
rename src/main/java/de/szut/lf8_starter/project/action/{ => crud}/GetAllProjectsAction.java (97%)
rename src/main/java/de/szut/lf8_starter/project/action/{ => crud}/GetProjectAction.java (83%)
rename src/main/java/de/szut/lf8_starter/project/action/{ => crud}/UpdateProjectAction.java (95%)
create mode 100644 src/main/java/de/szut/lf8_starter/project/action/employee/AddEmployeeToProjectAction.java
create mode 100644 src/main/java/de/szut/lf8_starter/project/dto/EmployeeDto.java
create mode 100644 src/test/java/de/szut/lf8_starter/integration/project/AddEmployeeToProjectTest.java
diff --git a/requests/employee/createEmployee.http b/requests/employee/createEmployee.http
new file mode 100644
index 0000000..a170fe2
--- /dev/null
+++ b/requests/employee/createEmployee.http
@@ -0,0 +1,12 @@
+POST https://employee.szut.dev/employees
+Authorization: Bearer {{auth_token}}
+Content-Type: application/json
+
+{
+ "firstName": "Jan",
+ "lastName": "Klattenhoff",
+ "street": "Pirolweg 17",
+ "postcode": "27777",
+ "city": "Gandakersee",
+ "phone": "017684984816"
+}
\ No newline at end of file
diff --git a/requests/employee/deleteEmployee.http b/requests/employee/deleteEmployee.http
new file mode 100644
index 0000000..cf1d827
--- /dev/null
+++ b/requests/employee/deleteEmployee.http
@@ -0,0 +1,2 @@
+DELETE https://employee.szut.dev/employees/310
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
diff --git a/requests/employee/getAllEmployees.http b/requests/employee/getAllEmployees.http
new file mode 100644
index 0000000..c3911be
--- /dev/null
+++ b/requests/employee/getAllEmployees.http
@@ -0,0 +1,2 @@
+GET https://employee.szut.dev/employees
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
diff --git a/requests/employee/getEmployee.http b/requests/employee/getEmployee.http
new file mode 100644
index 0000000..eddf4d9
--- /dev/null
+++ b/requests/employee/getEmployee.http
@@ -0,0 +1,2 @@
+GET https://employee.szut.dev/employees/312
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
diff --git a/requests/project/addEmployeeToProject.http b/requests/project/addEmployeeToProject.http
new file mode 100644
index 0000000..981839a
--- /dev/null
+++ b/requests/project/addEmployeeToProject.http
@@ -0,0 +1,2 @@
+POST http://localhost:8080/projects/1/employees/312
+Authorization: Bearer {{auth_token}}
\ No newline at end of file
diff --git a/requests/createProject.http b/requests/project/createProject.http
similarity index 100%
rename from requests/createProject.http
rename to requests/project/createProject.http
diff --git a/requests/getAllProjects.http b/requests/project/getAllProjects.http
similarity index 100%
rename from requests/getAllProjects.http
rename to requests/project/getAllProjects.http
diff --git a/requests/getProject.http b/requests/project/getProject.http
similarity index 100%
rename from requests/getProject.http
rename to requests/project/getProject.http
diff --git a/requests/updateProject.http b/requests/project/updateProject.http
similarity index 100%
rename from requests/updateProject.http
rename to requests/project/updateProject.http
diff --git a/src/main/java/de/szut/lf8_starter/employee/EmployeeService.java b/src/main/java/de/szut/lf8_starter/employee/EmployeeService.java
new file mode 100644
index 0000000..a78f76b
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/employee/EmployeeService.java
@@ -0,0 +1,34 @@
+package de.szut.lf8_starter.employee;
+
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestTemplate;
+
+@Service
+public class EmployeeService {
+ private final RestTemplate restTemplate;
+
+ public EmployeeService(RestTemplate restTemplate) {
+ this.restTemplate = restTemplate;
+ }
+
+ public boolean employeeExists(String accessToken, Long employeeId) {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setBearerAuth(accessToken.replace("Bearer ", ""));
+
+ HttpEntity requestEntity = new HttpEntity<>(headers);
+
+ String url = "https://employee.szut.dev/employees/" + employeeId;
+
+ try {
+ restTemplate.exchange(url, HttpMethod.GET, requestEntity, String.class);
+ } catch (HttpClientErrorException.NotFound e) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
index d9c35a1..6aa7127 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectEntity.java
@@ -25,7 +25,7 @@ public class ProjectEntity {
private long leadingEmployee;
- @ElementCollection
+ @ElementCollection(fetch = FetchType.EAGER)
private List employees;
private long contractor;
diff --git a/src/main/java/de/szut/lf8_starter/project/ProjectService.java b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
index 31efbec..17afcea 100644
--- a/src/main/java/de/szut/lf8_starter/project/ProjectService.java
+++ b/src/main/java/de/szut/lf8_starter/project/ProjectService.java
@@ -25,10 +25,8 @@ public class ProjectService {
return projectRepository.findById(id);
}
- public ProjectEntity update(ProjectEntity project) {
+ public void update(ProjectEntity project) {
this.projectRepository.save(project);
-
- return project;
}
public void delete(Long id) {
diff --git a/src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/crud/CreateProjectAction.java
similarity index 97%
rename from src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java
rename to src/main/java/de/szut/lf8_starter/project/action/crud/CreateProjectAction.java
index 3e636b5..f21646d 100644
--- a/src/main/java/de/szut/lf8_starter/project/action/CreateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/crud/CreateProjectAction.java
@@ -1,4 +1,4 @@
-package de.szut.lf8_starter.project.action;
+package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectMapper;
diff --git a/src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java b/src/main/java/de/szut/lf8_starter/project/action/crud/GetAllProjectsAction.java
similarity index 97%
rename from src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java
rename to src/main/java/de/szut/lf8_starter/project/action/crud/GetAllProjectsAction.java
index 039a104..5fb346a 100644
--- a/src/main/java/de/szut/lf8_starter/project/action/GetAllProjectsAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/crud/GetAllProjectsAction.java
@@ -1,4 +1,4 @@
-package de.szut.lf8_starter.project.action;
+package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.project.ProjectMapper;
import de.szut.lf8_starter.project.ProjectService;
diff --git a/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/crud/GetProjectAction.java
similarity index 83%
rename from src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
rename to src/main/java/de/szut/lf8_starter/project/action/crud/GetProjectAction.java
index d8e4207..eba31c1 100644
--- a/src/main/java/de/szut/lf8_starter/project/action/GetProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/crud/GetProjectAction.java
@@ -1,4 +1,4 @@
-package de.szut.lf8_starter.project.action;
+package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectMapper;
@@ -11,7 +11,10 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
diff --git a/src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/crud/UpdateProjectAction.java
similarity index 95%
rename from src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java
rename to src/main/java/de/szut/lf8_starter/project/action/crud/UpdateProjectAction.java
index 9c174e3..29a4ad5 100644
--- a/src/main/java/de/szut/lf8_starter/project/action/UpdateProjectAction.java
+++ b/src/main/java/de/szut/lf8_starter/project/action/crud/UpdateProjectAction.java
@@ -1,4 +1,4 @@
-package de.szut.lf8_starter.project.action;
+package de.szut.lf8_starter.project.action.crud;
import de.szut.lf8_starter.project.ProjectEntity;
import de.szut.lf8_starter.project.ProjectMapper;
diff --git a/src/main/java/de/szut/lf8_starter/project/action/employee/AddEmployeeToProjectAction.java b/src/main/java/de/szut/lf8_starter/project/action/employee/AddEmployeeToProjectAction.java
new file mode 100644
index 0000000..1e14ae0
--- /dev/null
+++ b/src/main/java/de/szut/lf8_starter/project/action/employee/AddEmployeeToProjectAction.java
@@ -0,0 +1,55 @@
+package de.szut.lf8_starter.project.action.employee;
+
+import de.szut.lf8_starter.employee.EmployeeService;
+import de.szut.lf8_starter.project.ProjectEntity;
+import de.szut.lf8_starter.project.ProjectService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Optional;
+
+@RestController
+public class AddEmployeeToProjectAction {
+ private final ProjectService projectService;
+ private final EmployeeService employeeService;
+
+ public AddEmployeeToProjectAction(ProjectService projectService, EmployeeService employeeService) {
+ this.projectService = projectService;
+ this.employeeService = employeeService;
+ }
+
+ @Operation(summary = "Add an employee to a project")
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "204", description = "Employee added to project"),
+ @ApiResponse(responseCode = "404", description = "Project or employee not found", content = @Content)
+ })
+ @PostMapping("/projects/{projectId}/employees/{employeeId}")
+ public ResponseEntity