diff --git a/.aliases b/.aliases
index ae9ceaf0..9477474d 100644
--- a/.aliases
+++ b/.aliases
@@ -44,7 +44,7 @@ alias podman-stop='systemctl --user disable --now podman.socket && systemctl --u
alias podman-use='export DOCKER_HOST="unix:///run/user/$UID/podman/podman.sock"; export TESTCONTAINERS_RYUK_DISABLED=true'
alias gw=gradleWrapper
-alias pg-sql-run='docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye'
+alias pg-sql-run='docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:15.5-bookworm'
alias pg-sql-stop='docker stop hsadmin-ng-postgres'
alias pg-sql-start='docker container start hsadmin-ng-postgres'
alias pg-sql-remove='docker rm hsadmin-ng-postgres'
diff --git a/README.md b/README.md
index 73c9e84d..87860527 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@ For architecture consider the files in the `doc` and `adr` folder.
- [Directory and Package Structure](#directory-and-package-structure)
- [General Directory Structure](#general-directory-structure)
- [Source Code Package Structure](#source-code-package-structure)
+ - [Run Tests from Command Line](#run-tests-from-command-line)
- [Spotless Code Formatting](#spotless-code-formatting)
- [JaCoCo Test Code Coverage Check](#jacoco-test-code-coverage-check)
- [PiTest Mutation Testing](#pitest-mutation-testing)
@@ -39,6 +40,7 @@ For architecture consider the files in the `doc` and `adr` folder.
- [How to Use a Persistent Database for Integration Tests?](#how-to-use-a-persistent-database-for-integration-tests?)
- [How to Amend Liquibase SQL Changesets?](#how-to-amend-liquibase-sql-changesets?)
- [How to Re-Generate Spring-Controller-Interfaces from OpenAPI specs?](#how-to-re-generate-spring-controller-interfaces-from-openapi-specs?)
+ - [How to Generate Database Table Diagrams?](#how-to-generate-database-table-diagrams?)
- [Further Documentation](#further-documentation)
@@ -49,25 +51,28 @@ Everything is tested on _Ubuntu Linux 22.04_ and _MacOS Monterey (12.4)_.
To be able to build and run the Java Spring Boot application, you need the following tools:
-- Docker 20.x (on MacOS you also need *Docker Desktop* or similar)
-- PostgreSQL Server 13.7-bullseye
+- Docker 20.x (on MacOS you also need *Docker Desktop* or similar) or Podman
+- PostgreSQL Server 15.5-bookworm
(see instructions below to install and run in Docker)
- Java JDK at least recent enough to run Gradle
(JDK 17.x will be automatically installed by Gradle toolchain support)
-- Gradle in some not too outdated version (7.4 will be installed via wrapper)
-You also might need an IDE (e.g. *IntelliJ IDEA* or *Eclipse* or *VS Code* with *[STS](https://spring.io/tools)* and a GUI Frontend for *PostgreSQL* like *Postbird*.
+We recommend to use an IDE (e.g. *IntelliJ IDEA* or *Eclipse* or *VS Code* with *[STS](https://spring.io/tools)* and optionally a GUI Frontend for *PostgreSQL* like *Postbird*.
-If you have at least Docker, the Java JDK and Gradle installed in appropriate versions and in your `PATH`, then you can start like this:
+If you have at least Docker and the Java JDK installed in appropriate versions and in your `PATH`, then you can start like this:
cd your-hsadmin-ng-directory
- gradle wrapper # downloads the configured Gradle version into the project
- source .aliases # creates some comforable bash aliases, e.g. 'gw'='./gradlew'
+ source .aliases # creates some comfortable bash aliases, e.g. 'gw'='./gradlew'
+ gw # initially downloads the configured Gradle version into the project
gw test # compiles and runs unit- and integration-tests
+ # if the container has not been built yet, run this:
pg-sql-run # downloads + runs PostgreSQL in a Docker container on localhost:5432
+ # if the container has been built already, run this:
+ pg-sql-start
+
gw bootRun # compiles and runs the application on localhost:8080
# the following command should reply with "pong":
@@ -130,14 +135,14 @@ But the easiest way to run PostgreSQL is via Docker.
Initially, pull an image compatible to current PostgreSQL version of Hostsharing:
- docker pull postgres:13.7-bullseye
+ docker pull postgres:15.5-bookworm
**⚠**
If we switch the version, please also amend the documentation as well as the aliases file. Thanks!
Create and run a container with the given PostgreSQL version:
- docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:13.7-bullseye
+ docker run --name hsadmin-ng-postgres -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres:15.5-bookworm
# or via alias:
pg-sql-run
@@ -196,7 +201,7 @@ To generate the TOC (Table of Contents), a little bash script from a
Given this is in PATH as `md-toc`, use:
```shell
-md-toc ^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$
CVE-2022-42003
+
+
+ ^pkg:maven/org\.eclipse\.angus/angus\-activation@.*$
+ cpe:/a:eclipse:eclipse_ide
+
+
+
+ ^pkg:maven/jakarta\.activation/jakarta\.activation\-api@.*$
+ cpe:/a:eclipse:eclipse_ide
+
+
+
+ ^pkg:maven/com\.fasterxml\.jackson\.core/jackson\-databind@.*$
+ cpe:/a:fasterxml:jackson-databind
+
+
+
+ ^pkg:maven/com\.jayway\.jsonpath/json\-path@.*$
+ CVE-2023-51074
+
+
+
+ ^pkg:maven/org\.pitest/pitest\-command\-line@.*$
+ cpe:/a:line:line
+
+
+
+ ^pkg:maven/org\.yaml/snakeyaml@.*$
+ CVE-2022-1471
+
diff --git a/gradle.properties b/gradle.properties
index a033d0d3..433cede1 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,8 @@
+# Gradle Java Toolchain-support
+org.gradle.java.installations.auto-detect=true
+org.gradle.java.installations.auto-download=true
+# org.gradle.jvm.toolchain.install.adoptopenjdk.baseUri
+# org.gradle.java.installations.paths -- uncomment and set if needed
# Spring BOM overrides
# currently none necessary
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 41d9927a..d64cd491 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 8049c684..1af9e093 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 1b6c7873..1aa94a42 100755
--- a/gradlew
+++ b/gradlew
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac
done
-APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
-
-APP_NAME="Gradle"
+# This is normally unused
+# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-
-# 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"'
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
- which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+ 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
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done
fi
-# Collect all arguments for the java command;
-# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
-# shell script including quotes and variable substitutions, so put them in
-# double quotes to make sure that they get re-expanded; and
-# * put everything else in single quotes, so that it's not re-expanded.
+
+# 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" \
@@ -205,6 +214,12 @@ set -- \
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.
diff --git a/gradlew.bat b/gradlew.bat
index 107acd32..93e3f59f 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/settings.gradle b/settings.gradle
index 8c454c71..09d09d6f 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -7,4 +7,32 @@ pluginManagement {
}
}
+plugins {
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
+}
+
+dependencyResolutionManagement {
+ components {
+ all {
+ allVariants {
+ withDependencies {
+ removeAll {
+ // Spring Boot 3.1.x has a transient dependency to snakeyaml 1.3
+ // which contains a severe vulnerability.
+ // Here we remove this transient dependency and in build.gradle
+ // we add an explicit dependency to snakeyaml 2.2,
+ // which does not have this vulnerability anymore.
+ //
+ // TODO: Check Once we are on SpringBoot 3.2.x, check if this exclude
+ // is still neccessary. If not:
+ // Remove it // as well as the related explicit dependency in build.gradle
+ // and the dependency suppression in owasp-dependency-check-suppression.xml.
+ it.module in [ 'snakeyaml' ]
+ }
+ }
+ }
+ }
+ }
+}
+
rootProject.name = 'hsadmin-ng'
diff --git a/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java b/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java
index 9cd2ec70..3c66716d 100644
--- a/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java
+++ b/src/main/java/net/hostsharing/hsadminng/config/PostgresCustomDialect.java
@@ -8,7 +8,7 @@ import static org.hibernate.dialect.DatabaseVersion.make;
public class PostgresCustomDialect extends PostgreSQLDialect {
public PostgresCustomDialect() {
- super(make(13, 7));
+ super(make(15, 5));
}
}
diff --git a/src/main/java/net/hostsharing/hsadminng/context/Context.java b/src/main/java/net/hostsharing/hsadminng/context/Context.java
index f7f6f827..2730147d 100644
--- a/src/main/java/net/hostsharing/hsadminng/context/Context.java
+++ b/src/main/java/net/hostsharing/hsadminng/context/Context.java
@@ -15,9 +15,11 @@ import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.function.Predicate.not;
+import static net.hostsharing.hsadminng.mapper.PostgresArray.fromPostgresArray;
import static org.springframework.transaction.annotation.Propagation.MANDATORY;
@Service
@@ -81,11 +83,14 @@ public class Context {
}
public String[] getAssumedRoles() {
- return (String[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
+ final byte[] result = (byte[]) em.createNativeQuery("select assumedRoles() as roles", String[].class).getSingleResult();
+ return fromPostgresArray(result, String.class, Function.identity());
}
public UUID[] currentSubjectsUuids() {
- return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
+ final byte[] result = (byte[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class)
+ .getSingleResult();
+ return fromPostgresArray(result, UUID.class, UUID::fromString);
}
public static String getCallerMethodNameFromStackFrame(final int skipFrames) {
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java
index a39acbfa..309c3a57 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepository.java
@@ -14,7 +14,7 @@ public interface HsOfficeContactRepository extends Repository findContactByOptionalLabelLike(String label);
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java
index 9955f6f1..e699fb5c 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionEntity.java
@@ -1,13 +1,11 @@
package net.hostsharing.hsadminng.hs.office.coopassets;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator;
-import org.hibernate.annotations.Type;
import jakarta.persistence.*;
import java.math.BigDecimal;
@@ -47,7 +45,6 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable {
@Column(name = "transactiontype")
@Enumerated(EnumType.STRING)
- @Type(PostgreSQLEnumType.class)
private HsOfficeCoopAssetsTransactionType transactionType;
@Column(name = "valuedate")
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java
index 1a14abde..256933b9 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopassets/HsOfficeCoopAssetsTransactionRepository.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.coopassets;
-import net.hostsharing.hsadminng.hs.office.coopshares.HsOfficeCoopSharesTransactionEntity;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java
index 1b5d1cc5..b5d4979b 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionEntity.java
@@ -1,12 +1,10 @@
package net.hostsharing.hsadminng.hs.office.coopshares;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
-import org.hibernate.annotations.Type;
import jakarta.persistence.*;
import java.time.LocalDate;
@@ -43,7 +41,6 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable {
@Column(name = "transactiontype")
@Enumerated(EnumType.STRING)
- @Type(PostgreSQLEnumType.class)
private HsOfficeCoopSharesTransactionType transactionType;
@Column(name = "valuedate")
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java
index 27cb6f92..f0013ef9 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorRepository.java
@@ -19,15 +19,15 @@ public interface HsOfficeDebitorRepository extends Repository findDebitorByOptionalNameLike(String name);
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java
index 7a3e1a20..671ae7f7 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipEntity.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.membership;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
import com.vladmihalcea.hibernate.type.range.PostgreSQLRangeType;
import com.vladmihalcea.hibernate.type.range.Range;
import lombok.*;
@@ -61,7 +60,6 @@ public class HsOfficeMembershipEntity implements Stringifyable {
@Column(name = "reasonfortermination")
@Enumerated(EnumType.STRING)
- @Type(PostgreSQLEnumType.class)
private HsOfficeReasonForTermination reasonForTermination;
public void setValidFrom(final LocalDate validFrom) {
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java
index 222dcaed..6c7a158c 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepository.java
@@ -13,14 +13,14 @@ public interface HsOfficePartnerRepository extends Repository findPartnerByOptionalNameLike(String name);
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java
index cdc695f0..a76d4130 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonEntity.java
@@ -1,13 +1,11 @@
package net.hostsharing.hsadminng.hs.office.person;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.apache.commons.lang3.StringUtils;
-import org.hibernate.annotations.Type;
import jakarta.persistence.*;
import java.util.UUID;
@@ -37,7 +35,6 @@ public class HsOfficePersonEntity implements Stringifyable {
@Column(name = "persontype")
@Enumerated(EnumType.STRING)
- @Type(PostgreSQLEnumType.class)
private HsOfficePersonType personType;
@Column(name = "tradename")
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java
index 538ffaf1..f7481339 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepository.java
@@ -14,9 +14,9 @@ public interface HsOfficePersonRepository extends Repository findPersonByOptionalNameLike(String name);
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipController.java
index 3d6332e3..98c6bccf 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipController.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipController.java
@@ -51,7 +51,7 @@ public class HsOfficeRelationshipController implements HsOfficeRelationshipsApi
final HsOfficeRelationshipTypeResource relationshipType) {
context.define(currentUser, assumedRoles);
- final var entities = relationshipRepo.findRelationshipRelatedToPersonUuid(personUuid,
+ final var entities = relationshipRepo.findRelationshipRelatedToPersonUuidAndRelationshipType(personUuid,
mapper.map(relationshipType, HsOfficeRelationshipType.class));
final var resources = mapper.mapList(entities, HsOfficeRelationshipResource.class,
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java
index 9e7fb5d9..383c6853 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipEntity.java
@@ -1,12 +1,10 @@
package net.hostsharing.hsadminng.hs.office.relationship;
-import com.vladmihalcea.hibernate.type.basic.PostgreSQLEnumType;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.stringify.Stringify;
-import org.hibernate.annotations.Type;
import jakarta.persistence.*;
import java.util.UUID;
@@ -47,7 +45,6 @@ public class HsOfficeRelationshipEntity {
@Column(name = "reltype")
@Enumerated(EnumType.STRING)
- @Type(PostgreSQLEnumType.class)
private HsOfficeRelationshipType relType;
@Override
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepository.java
index 8b9e10fe..d34caa8c 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipRepository.java
@@ -12,8 +12,8 @@ public interface HsOfficeRelationshipRepository extends Repository findByUuid(UUID id);
- default List findRelationshipRelatedToPersonUuid(@NotNull UUID personUuid, HsOfficeRelationshipType relationshipType) {
- return findRelationshipRelatedToPersonUuid(personUuid, relationshipType.toString());
+ default List findRelationshipRelatedToPersonUuidAndRelationshipType(@NotNull UUID personUuid, HsOfficeRelationshipType relationshipType) {
+ return findRelationshipRelatedToPersonUuidAndRelationshipTypeString(personUuid, relationshipType.toString());
}
@Query(value = """
@@ -27,7 +27,7 @@ public interface HsOfficeRelationshipRepository extends Repository findRelationshipRelatedToPersonUuid(@NotNull UUID personUuid, String relationshipType);
+ List findRelationshipRelatedToPersonUuidAndRelationshipTypeString(@NotNull UUID personUuid, String relationshipType);
HsOfficeRelationshipEntity save(final HsOfficeRelationshipEntity entity);
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java
index db31adcb..84264bd6 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntity.java
@@ -54,6 +54,7 @@ public class HsOfficeSepaMandateEntity implements Stringifyable {
@Column(name = "validity", columnDefinition = "daterange")
@Type(PostgreSQLRangeType.class)
+ @Builder.Default
private Range validity = Range.infinite(LocalDate.class);
public void setValidFrom(final LocalDate validFrom) {
diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java
index d243a716..aab53bae 100644
--- a/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepository.java
@@ -14,7 +14,7 @@ public interface HsOfficeSepaMandateRepository extends Repository findSepaMandateByOptionalIban(String iban);
diff --git a/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java b/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java
new file mode 100644
index 00000000..e1e1d056
--- /dev/null
+++ b/src/main/java/net/hostsharing/hsadminng/mapper/PostgresArray.java
@@ -0,0 +1,58 @@
+package net.hostsharing.hsadminng.mapper;
+
+import lombok.experimental.UtilityClass;
+import org.postgresql.util.PGtokenizer;
+
+import java.lang.reflect.Array;
+import java.nio.charset.StandardCharsets;
+import java.util.function.Function;
+
+@UtilityClass
+public class PostgresArray {
+
+ /**
+ * Converts a byte[], as returned for a Postgres-array by native queries, to a Java array.
+ *
+ * This example code worked with Hibernate 5 (Spring Boot 3.0.x):
+ *
+ * return (UUID[]) em.createNativeQuery("select currentSubjectsUuids() as uuids", UUID[].class).getSingleResult();
+ *
+ *
+ *
+ * With Hibernate 6 (Spring Boot 3.1.x), this utility method can be used like such:
+ *
+ * final byte[] result = (byte[]) em.createNativeQuery("select * from currentSubjectsUuids() as uuids", UUID[].class)
+ * .getSingleResult();
+ * return fromPostgresArray(result, UUID.class, UUID::fromString);
+ *
+ *
+ *
+ * @param pgArray the byte[] returned by a native query containing as rendered for a Postgres array
+ * @param elementClass the class of a single element of the Java array to be returned
+ * @param itemParser converts a string element to the specified elementClass
+ * @return a Java array containing the data from pgArray
+ * @param type of a single element of the Java array
+ */
+ public static T[] fromPostgresArray(final byte[] pgArray, final Class elementClass, final Function itemParser) {
+ final var pgArrayLiteral = new String(pgArray, StandardCharsets.UTF_8);
+ if (pgArrayLiteral.length() == 2) {
+ return newGenericArray(elementClass, 0);
+ }
+ final PGtokenizer tokenizer = new PGtokenizer(pgArrayLiteral.substring(1, pgArrayLiteral.length()-1), ',');
+ tokenizer.remove("\"", "\"");
+ final T[] array = newGenericArray(elementClass, tokenizer.getSize()); // Create a new array of the specified type and length
+ for ( int n = 0; n < tokenizer.getSize(); ++n ) {
+ final String token = tokenizer.getToken(n);
+ if ( !"NULL".equals(token) ) {
+ array[n] = itemParser.apply(token.trim().replace("\\\"", "\""));
+ }
+ }
+ return array;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T[] newGenericArray(final Class elementClass, final int length) {
+ return (T[]) Array.newInstance(elementClass, length);
+ }
+
+}
diff --git a/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java b/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java
index bfe11a19..0c1a168b 100644
--- a/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepository.java
@@ -11,7 +11,7 @@ public interface RbacUserRepository extends Repository {
@Query("""
select u from RbacUserEntity u
- where :userName is null or u.name like concat(:userName, '%')
+ where :userName is null or u.name like concat(cast(:userName as text), '%')
order by u.name
""")
List findByOptionalNameLike(String userName);
diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java
index 530a7006..1bd000ba 100644
--- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java
+++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerController.java
@@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import java.util.List;
-import java.util.UUID;
@RestController
public class TestCustomerController implements TestCustomersApi {
diff --git a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java
index a882b304..2dc298ea 100644
--- a/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/test/cust/TestCustomerRepository.java
@@ -12,7 +12,7 @@ public interface TestCustomerRepository extends Repository findByUuid(UUID id);
- @Query("SELECT c FROM TestCustomerEntity c WHERE :prefix is null or c.prefix like concat(:prefix, '%')")
+ @Query("SELECT c FROM TestCustomerEntity c WHERE :prefix is null or c.prefix like concat(cast(:prefix as text), '%')")
List findCustomerByOptionalPrefixLike(String prefix);
TestCustomerEntity save(final TestCustomerEntity entity);
diff --git a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java
index 610d8fdc..f8538465 100644
--- a/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java
+++ b/src/main/java/net/hostsharing/hsadminng/test/pac/TestPackageRepository.java
@@ -8,7 +8,7 @@ import java.util.UUID;
public interface TestPackageRepository extends Repository {
- @Query("SELECT p FROM TestPackageEntity p WHERE :name is null or p.name like concat(:name, '%')")
+ @Query("SELECT p FROM TestPackageEntity p WHERE :name is null or p.name like concat(cast(:name as text), '%')")
List findAllByOptionalNameLike(final String name);
TestPackageEntity findByUuid(UUID packageUuid);
diff --git a/src/main/resources/db/changelog/206-hs-office-contact-migration.sql b/src/main/resources/db/changelog/206-hs-office-contact-migration.sql
new file mode 100644
index 00000000..79cdd3bf
--- /dev/null
+++ b/src/main/resources/db/changelog/206-hs-office-contact-migration.sql
@@ -0,0 +1,96 @@
+--liquibase formatted sql
+
+-- TODO: These changesets are just for the external remote views to simulate the legacy tables.
+-- Once we don't need the external remote views anymore, create revert changesets.
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-mapping:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE TABLE hs_office_contact_legacy_id
+(
+ uuid uuid NOT NULL REFERENCES hs_office_contact(uuid),
+ contact_id integer NOT NULL
+);
+--//
+
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-sequence:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE SEQUENCE IF NOT EXISTS hs_office_contact_legacy_id_seq
+ AS integer
+ START 1000000000
+ OWNED BY hs_office_contact_legacy_id.contact_id;
+--//
+
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-default:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+ALTER TABLE hs_office_contact_legacy_id
+ ALTER COLUMN contact_id
+ SET DEFAULT nextVal('hs_office_contact_legacy_id_seq');
+
+--/
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-insert:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CALL defineContext('schema-migration');
+INSERT INTO hs_office_contact_legacy_id(uuid, contact_id)
+ SELECT uuid, nextVal('hs_office_contact_legacy_id_seq') FROM hs_office_contact;
+--/
+
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-insert-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function insertContactLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'INSERT' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ INSERT INTO hs_office_contact_legacy_id VALUES
+ (NEW.uuid, nextVal('hs_office_contact_legacy_id_seq'));
+
+ return NEW;
+end; $$;
+
+create trigger createContactLegacyIdMapping
+ after insert on hs_office_contact
+ for each row
+ execute procedure insertContactLegacyIdMapping();
+--/
+
+
+-- ============================================================================
+--changeset hs-office-contact-MIGRATION-delete-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function deleteContactLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'DELETE' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ DELETE FROM hs_office_contact_legacy_id
+ WHERE uuid = OLD.uuid;
+
+ return OLD;
+end; $$;
+
+create trigger removeContactLegacyIdMapping
+ before delete on hs_office_contact
+ for each row
+ execute procedure deleteContactLegacyIdMapping();
+--/
diff --git a/src/main/resources/db/changelog/226-hs-office-partner-migration.sql b/src/main/resources/db/changelog/226-hs-office-partner-migration.sql
new file mode 100644
index 00000000..f48e99d5
--- /dev/null
+++ b/src/main/resources/db/changelog/226-hs-office-partner-migration.sql
@@ -0,0 +1,95 @@
+--liquibase formatted sql
+
+-- TODO: These changesets are just for the external remote views to simulate the legacy tables.
+-- Once we don't need the external remote views anymore, create revert changesets.
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-mapping:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE TABLE hs_office_partner_legacy_id
+(
+ uuid uuid NOT NULL REFERENCES hs_office_partner(uuid),
+ bp_id integer NOT NULL
+);
+--//
+
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-sequence:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE SEQUENCE IF NOT EXISTS hs_office_partner_legacy_id_seq
+ AS integer
+ START 1000000000
+ OWNED BY hs_office_partner_legacy_id.bp_id;
+--//
+
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-default:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+ALTER TABLE hs_office_partner_legacy_id
+ ALTER COLUMN bp_id
+ SET DEFAULT nextVal('hs_office_partner_legacy_id_seq');
+--/
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-insert:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CALL defineContext('schema-migration');
+INSERT INTO hs_office_partner_legacy_id(uuid, bp_id)
+ SELECT uuid, nextVal('hs_office_partner_legacy_id_seq') FROM hs_office_partner;
+--/
+
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-insert-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function insertPartnerLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'INSERT' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ INSERT INTO hs_office_partner_legacy_id VALUES
+ (NEW.uuid, nextVal('hs_office_partner_legacy_id_seq'));
+
+ return NEW;
+end; $$;
+
+create trigger createPartnerLegacyIdMapping
+ after insert on hs_office_partner
+ for each row
+ execute procedure insertPartnerLegacyIdMapping();
+--/
+
+
+-- ============================================================================
+--changeset hs-office-partner-MIGRATION-delete-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function deletePartnerLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'DELETE' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ DELETE FROM hs_office_partner_legacy_id
+ WHERE uuid = OLD.uuid;
+
+ return OLD;
+end; $$;
+
+create trigger removePartnerLegacyIdMapping
+ before delete on hs_office_partner
+ for each row
+ execute procedure deletePartnerLegacyIdMapping();
+--/
diff --git a/src/main/resources/db/changelog/256-hs-office-sepamandate-migration.sql b/src/main/resources/db/changelog/256-hs-office-sepamandate-migration.sql
new file mode 100644
index 00000000..fe43706c
--- /dev/null
+++ b/src/main/resources/db/changelog/256-hs-office-sepamandate-migration.sql
@@ -0,0 +1,97 @@
+--liquibase formatted sql
+
+-- TODO: These changesets are just for the external remote views to simulate the legacy tables.
+-- Once we don't need the external remote views anymore, create revert changesets.
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-mapping:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE TABLE hs_office_sepamandate_legacy_id
+(
+ uuid uuid NOT NULL REFERENCES hs_office_sepamandate(uuid),
+ sepa_mandat_id integer NOT NULL
+);
+--//
+
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-sequence:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE SEQUENCE IF NOT EXISTS hs_office_sepamandate_legacy_id_seq
+ AS integer
+ START 1000000000
+ OWNED BY hs_office_sepamandate_legacy_id.sepa_mandat_id;
+--//
+
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-default:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+ALTER TABLE hs_office_sepamandate_legacy_id
+ ALTER COLUMN sepa_mandat_id
+ SET DEFAULT nextVal('hs_office_sepamandate_legacy_id_seq');
+
+--/
+
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-insert:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CALL defineContext('schema-migration');
+INSERT INTO hs_office_sepamandate_legacy_id(uuid, sepa_mandat_id)
+ SELECT uuid, nextVal('hs_office_sepamandate_legacy_id_seq') FROM hs_office_sepamandate;
+--/
+
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-insert-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function insertSepaMandateLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'INSERT' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ INSERT INTO hs_office_sepamandate_legacy_id VALUES
+ (NEW.uuid, nextVal('hs_office_sepamandate_legacy_id_seq'));
+
+ return NEW;
+end; $$;
+
+create trigger createSepaMandateLegacyIdMapping
+ after insert on hs_office_sepamandate
+ for each row
+ execute procedure insertSepaMandateLegacyIdMapping();
+--/
+
+
+-- ============================================================================
+--changeset hs-office-sepamandate-MIGRATION-delete-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function deleteSepaMandateLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'DELETE' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ DELETE FROM hs_office_sepamandate_legacy_id
+ WHERE uuid = OLD.uuid;
+
+ return OLD;
+end; $$;
+
+create trigger removeSepaMandateLegacyIdMapping
+ before delete on hs_office_sepamandate
+ for each row
+ execute procedure deleteSepaMandateLegacyIdMapping();
+--/
diff --git a/src/main/resources/db/changelog/316-hs-office-coopshares-migration.sql b/src/main/resources/db/changelog/316-hs-office-coopshares-migration.sql
new file mode 100644
index 00000000..dd64356e
--- /dev/null
+++ b/src/main/resources/db/changelog/316-hs-office-coopshares-migration.sql
@@ -0,0 +1,96 @@
+--liquibase formatted sql
+
+-- TODO: These changesets are just for the external remote views to simulate the legacy tables.
+-- Once we don't need the external remote views anymore, create revert changesets.
+
+-- ============================================================================
+--changeset hs-office-coopshares-MIGRATION-mapping:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE TABLE hs_office_coopsharestransaction_legacy_id
+(
+ uuid uuid NOT NULL REFERENCES hs_office_coopsharestransaction(uuid),
+ member_share_id integer NOT NULL
+);
+--//
+
+
+-- ============================================================================
+--changeset hs-office-coopshares-MIGRATION-sequence:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE SEQUENCE IF NOT EXISTS hs_office_coopsharestransaction_legacy_id_seq
+ AS integer
+ START 1000000000
+ OWNED BY hs_office_coopsharestransaction_legacy_id.member_share_id;
+--//
+
+
+-- ============================================================================
+--changeset hs-office-coopshares-MIGRATION-default:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+ALTER TABLE hs_office_coopsharestransaction_legacy_id
+ ALTER COLUMN member_share_id
+ SET DEFAULT nextVal('hs_office_coopsharestransaction_legacy_id_seq');
+
+--/
+
+-- ============================================================================
+--changeset hs-office-coopshares-MIGRATION-insert:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CALL defineContext('schema-migration');
+INSERT INTO hs_office_coopsharestransaction_legacy_id(uuid, member_share_id)
+ SELECT uuid, nextVal('hs_office_coopsharestransaction_legacy_id_seq') FROM hs_office_coopsharestransaction;
+--/
+
+
+-- ============================================================================
+--changeset hs-office-coopShares-MIGRATION-insert-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function insertCoopSharesLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'INSERT' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ INSERT INTO hs_office_coopsharestransaction_legacy_id VALUES
+ (NEW.uuid, nextVal('hs_office_coopsharestransaction_legacy_id_seq'));
+
+ return NEW;
+end; $$;
+
+create trigger createCoopSharesLegacyIdMapping
+ after insert on hs_office_coopsharestransaction
+ for each row
+ execute procedure insertCoopSharesLegacyIdMapping();
+--/
+
+
+-- ============================================================================
+--changeset hs-office-coopShares-MIGRATION-delete-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function deleteCoopSharesLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'DELETE' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ DELETE FROM hs_office_coopsharestransaction_legacy_id
+ WHERE uuid = OLD.uuid;
+
+ return OLD;
+end; $$;
+
+create trigger removeCoopSharesLegacyIdMapping
+ before delete on hs_office_coopsharestransaction
+ for each row
+ execute procedure deleteCoopSharesLegacyIdMapping();
+--/
diff --git a/src/main/resources/db/changelog/326-hs-office-coopassets-migration.sql b/src/main/resources/db/changelog/326-hs-office-coopassets-migration.sql
new file mode 100644
index 00000000..8c346566
--- /dev/null
+++ b/src/main/resources/db/changelog/326-hs-office-coopassets-migration.sql
@@ -0,0 +1,96 @@
+--liquibase formatted sql
+
+-- TODO: These changesets are just for the external remote views to simulate the legacy tables.
+-- Once we don't need the external remote views anymore, create revert changesets.
+
+-- ============================================================================
+--changeset hs-office-coopassets-MIGRATION-mapping:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE TABLE hs_office_coopassetstransaction_legacy_id
+(
+ uuid uuid NOT NULL REFERENCES hs_office_coopassetstransaction(uuid),
+ member_asset_id integer NOT NULL
+);
+--//
+
+
+-- ============================================================================
+--changeset hs-office-coopassets-MIGRATION-sequence:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CREATE SEQUENCE IF NOT EXISTS hs_office_coopassetstransaction_legacy_id_seq
+ AS integer
+ START 1000000000
+ OWNED BY hs_office_coopassetstransaction_legacy_id.member_asset_id;
+--//
+
+
+-- ============================================================================
+--changeset hs-office-coopassets-MIGRATION-default:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+ALTER TABLE hs_office_coopassetstransaction_legacy_id
+ ALTER COLUMN member_asset_id
+ SET DEFAULT nextVal('hs_office_coopassetstransaction_legacy_id_seq');
+--/
+
+
+-- ============================================================================
+--changeset hs-office-coopassets-MIGRATION-insert:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+
+CALL defineContext('schema-migration');
+INSERT INTO hs_office_coopassetstransaction_legacy_id(uuid, member_asset_id)
+ SELECT uuid, nextVal('hs_office_coopassetstransaction_legacy_id_seq') FROM hs_office_coopassetstransaction;
+--/
+
+
+-- ============================================================================
+--changeset hs-office-coopAssets-MIGRATION-insert-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function insertCoopAssetsLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'INSERT' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ INSERT INTO hs_office_coopassetstransaction_legacy_id VALUES
+ (NEW.uuid, nextVal('hs_office_coopassetstransaction_legacy_id_seq'));
+
+ return NEW;
+end; $$;
+
+create trigger createCoopAssetsLegacyIdMapping
+ after insert on hs_office_coopassetstransaction
+ for each row
+ execute procedure insertCoopAssetsLegacyIdMapping();
+--/
+
+
+-- ============================================================================
+--changeset hs-office-coopAssets-MIGRATION-delete-trigger:1 endDelimiter:--//
+-- ----------------------------------------------------------------------------
+create or replace function deleteCoopAssetsLegacyIdMapping()
+ returns trigger
+ language plpgsql
+ strict as $$
+begin
+ if TG_OP <> 'DELETE' then
+ raise exception 'invalid usage of trigger';
+ end if;
+
+ DELETE FROM hs_office_coopassetstransaction_legacy_id
+ WHERE uuid = OLD.uuid;
+
+ return OLD;
+end; $$;
+
+create trigger removeCoopAssetsLegacyIdMapping
+ before delete on hs_office_coopassetstransaction
+ for each row
+ execute procedure deleteCoopAssetsLegacyIdMapping();
+--/
diff --git a/src/main/resources/db/changelog/db.changelog-master.yaml b/src/main/resources/db/changelog/db.changelog-master.yaml
index 3a1bb533..68719b66 100644
--- a/src/main/resources/db/changelog/db.changelog-master.yaml
+++ b/src/main/resources/db/changelog/db.changelog-master.yaml
@@ -53,6 +53,8 @@ databaseChangeLog:
file: db/changelog/200-hs-office-contact.sql
- include:
file: db/changelog/203-hs-office-contact-rbac.sql
+ - include:
+ file: db/changelog/206-hs-office-contact-migration.sql
- include:
file: db/changelog/208-hs-office-contact-test-data.sql
- include:
@@ -67,6 +69,8 @@ databaseChangeLog:
file: db/changelog/223-hs-office-partner-rbac.sql
- include:
file: db/changelog/224-hs-office-partner-details-rbac.sql
+ - include:
+ file: db/changelog/226-hs-office-partner-migration.sql
- include:
file: db/changelog/228-hs-office-partner-test-data.sql
- include:
@@ -80,7 +84,7 @@ databaseChangeLog:
- include:
file: db/changelog/243-hs-office-bankaccount-rbac.sql
- include:
- file: db/changelog/248-hs-office-bankaccount-test-data.sql
+ file: db/changelog/248-hs-office-bankaccount-test-data.sql
- include:
file: db/changelog/270-hs-office-debitor.sql
- include:
@@ -91,6 +95,8 @@ databaseChangeLog:
file: db/changelog/250-hs-office-sepamandate.sql
- include:
file: db/changelog/253-hs-office-sepamandate-rbac.sql
+ - include:
+ file: db/changelog/256-hs-office-sepamandate-migration.sql
- include:
file: db/changelog/258-hs-office-sepamandate-test-data.sql
- include:
@@ -103,11 +109,15 @@ databaseChangeLog:
file: db/changelog/310-hs-office-coopshares.sql
- include:
file: db/changelog/313-hs-office-coopshares-rbac.sql
+ - include:
+ file: db/changelog/316-hs-office-coopshares-migration.sql
- include:
file: db/changelog/318-hs-office-coopshares-test-data.sql
- include:
file: db/changelog/320-hs-office-coopassets.sql
- include:
file: db/changelog/323-hs-office-coopassets-rbac.sql
+ - include:
+ file: db/changelog/326-hs-office-coopassets-migration.sql
- include:
file: db/changelog/328-hs-office-coopassets-test-data.sql
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java
index a54ca5c6..d870ca1a 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/HsOfficeBankAccountControllerRestTest.java
@@ -83,7 +83,7 @@ class HsOfficeBankAccountControllerRestTest {
enum InvalidBicTestCase {
TOO_SHORT("BEVODEB", "Bic length must be 8 or 11"),
TOO_LONG("BEVODEBBX", "Bic length must be 8 or 11"),
- INVALID_CHARACTER("BEV-ODEB", "Bank code must contain only letters.");
+ INVALID_CHARACTER("BEV-ODEB", "Bank code must contain only alphanumeric.");
private final String givenBic;
private final String expectedErrorMessage;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java
index 7bb7de7e..7b7505f4 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/bankaccount/TestHsOfficeBankAccount.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.bankaccount;
-import java.util.UUID;
public class TestHsOfficeBankAccount {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
index a58aa824..0308c31d 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/HsOfficeContactRepositoryIntegrationTest.java
@@ -28,7 +28,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@@ -237,10 +236,6 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest {
final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll());
final var givenContact = givenSomeTemporaryContact("selfregistered-user-drew@hostsharing.org");
- assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created")
- .isEqualTo(initialRoleNames.size() + 3);
- assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created")
- .isEqualTo(initialGrantNames.size() + 7);
// when
final var result = jpaAttempt.transacted(() -> {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java
index 58284258..b42ef8e5 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/contact/TestHsOfficeContact.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.contact;
-import java.util.UUID;
public class TestHsOfficeContact {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
index 22001cb2..76d6758f 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/HsOfficeDebitorControllerAcceptanceTest.java
@@ -26,7 +26,6 @@ import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
import static org.hamcrest.Matchers.*;
@SpringBootTest(
@@ -481,7 +480,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
void contactAdminUser_canNotDeleteRelatedDebitor() {
context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor();
- assumeThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact");
+ assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact");
RestAssured // @formatter:off
.given()
@@ -501,7 +500,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
void normalUser_canNotDeleteUnrelatedDebitor() {
context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor();
- assumeThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact");
+ assertThat(givenDebitor.getBillingContact().getLabel()).isEqualTo("forth contact");
RestAssured // @formatter:off
.given()
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java
index 9d2c6b7f..d9d482ba 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/debitor/TestHsOfficeDebitor.java
@@ -2,7 +2,6 @@ package net.hostsharing.hsadminng.hs.office.debitor;
import lombok.experimental.UtilityClass;
-import java.util.UUID;
import static net.hostsharing.hsadminng.hs.office.contact.TestHsOfficeContact.TEST_CONTACT;
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
index 42f61495..c85a9b13 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/HsOfficeMembershipRepositoryIntegrationTest.java
@@ -32,7 +32,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@@ -327,7 +326,7 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", "hs_office_debitor#10003ThirdOHG-thirdcontact.admin");
- assumeThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent();
+ assertThat(membershipRepo.findByUuid(givenMembership.getUuid())).isPresent();
membershipRepo.deleteByUuid(givenMembership.getUuid());
});
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java
index 1b40a4ce..d9245fc8 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/membership/TestHsMembership.java
@@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.membership;
import com.vladmihalcea.hibernate.type.range.Range;
import java.time.LocalDate;
-import java.util.UUID;
import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TEST_PARTNER;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java
index 899b151d..053b03e1 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java
@@ -24,7 +24,6 @@ import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
@@ -408,7 +407,7 @@ class HsOfficePartnerControllerAcceptanceTest {
void contactAdminUser_canNotDeleteRelatedPartner() {
context.define("superuser-alex@hostsharing.net");
final var givenPartner = givenSomeTemporaryPartnerBessler();
- assumeThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact");
+ assertThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact");
RestAssured // @formatter:off
.given()
@@ -428,7 +427,7 @@ class HsOfficePartnerControllerAcceptanceTest {
void normalUser_canNotDeleteUnrelatedPartner() {
context.define("superuser-alex@hostsharing.net");
final var givenPartner = givenSomeTemporaryPartnerBessler();
- assumeThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact");
+ assertThat(givenPartner.getContact().getLabel()).isEqualTo("forth contact");
RestAssured // @formatter:off
.given()
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
index 6b035f5b..e03d8cbe 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerRepositoryIntegrationTest.java
@@ -29,7 +29,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@@ -330,7 +329,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = jpaAttempt.transacted(() -> {
context("person-ErbenBesslerMelBessler@example.com");
- assumeThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent();
+ assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent();
partnerRepo.deleteByUuid(givenPartner.getUuid());
});
@@ -352,10 +351,6 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
final var initialRoleNames = Array.from(roleNamesOf(rawRoleRepo.findAll()));
final var initialGrantNames = Array.from(grantDisplaysOf(rawGrantRepo.findAll()));
final var givenPartner = givenSomeTemporaryPartnerBessler("twelfth");
- assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created")
- .isEqualTo(initialRoleNames.length + 3);
- assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created")
- .isEqualTo(initialGrantNames.length + 10);
// when
final var result = jpaAttempt.transacted(() -> {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java
index 21756b6d..19235167 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/TestHsOfficePartner.java
@@ -3,7 +3,6 @@ package net.hostsharing.hsadminng.hs.office.partner;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
-import java.util.UUID;
import static net.hostsharing.hsadminng.hs.office.person.HsOfficePersonType.LEGAL;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
index 6c75434e..2405b237 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/HsOfficePersonRepositoryIntegrationTest.java
@@ -27,7 +27,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@@ -244,10 +243,6 @@ class HsOfficePersonRepositoryIntegrationTest extends ContextBasedTest {
final var initialRoleNames = roleNamesOf(rawRoleRepo.findAll());
final var initialGrantNames = grantDisplaysOf(rawGrantRepo.findAll());
final var givenPerson = givenSomeTemporaryPerson("selfregistered-user-drew@hostsharing.org");
- assumeThat(rawRoleRepo.findAll().size()).as("unexpected number of roles created")
- .isEqualTo(initialRoleNames.size() + 3);
- assumeThat(rawGrantRepo.findAll().size()).as("unexpected number of grants created")
- .isEqualTo(initialGrantNames.size() + 7);
// when
final var result = jpaAttempt.transacted(() -> {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java b/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java
index f4d10fda..d394ee56 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/person/TestHsOfficePerson.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.person;
-import java.util.UUID;
public class TestHsOfficePerson {
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java
index 6288bb4c..f090295b 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/relationship/HsOfficeRelationshipControllerAcceptanceTest.java
@@ -25,7 +25,6 @@ import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
import static net.hostsharing.test.JsonMatcher.lenientlyEquals;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java
index 7ba77e0e..5d8fa5b5 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateEntityUnitTest.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.sepamandate;
-import com.vladmihalcea.hibernate.type.range.Range;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import org.junit.jupiter.api.Test;
diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
index cbc8bfbc..8e5f5c79 100644
--- a/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/hs/office/sepamandate/HsOfficeSepaMandateRepositoryIntegrationTest.java
@@ -31,7 +31,6 @@ import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantD
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import({ Context.class, JpaAttempt.class })
@@ -346,7 +345,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = jpaAttempt.transacted(() -> {
context("bankaccount-admin@ThirdOHG.example.com");
- assumeThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent();
+ assertThat(sepaMandateRepo.findByUuid(givenSepaMandate.getUuid())).isPresent();
sepaMandateRepo.deleteByUuid(givenSepaMandate.getUuid());
});
diff --git a/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java
new file mode 100644
index 00000000..c76141b1
--- /dev/null
+++ b/src/test/java/net/hostsharing/hsadminng/mapper/PostgresArrayIntegrationTest.java
@@ -0,0 +1,88 @@
+package net.hostsharing.hsadminng.mapper;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
+
+import jakarta.persistence.EntityManager;
+
+import java.util.UUID;
+import java.util.function.Function;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@DataJpaTest
+class PostgresArrayIntegrationTest {
+
+ @Autowired
+ EntityManager em;
+
+ @Test
+ void shouldCreateEmptyArray() {
+ em.createNativeQuery("""
+ create or replace function returnEmptyArray()
+ returns text[]
+ stable leakproof
+ language plpgsql as $$
+ declare
+ emptyArray text[] = '{}';
+ begin
+ return emptyArray;
+ end; $$;
+ """).executeUpdate();
+ final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnEmptyArray()", String[].class).getSingleResult();
+
+ final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ void shouldCreateStringArray() {
+ em.createNativeQuery("""
+ create or replace function returnStringArray()
+ returns varchar(63)[]
+ stable leakproof
+ language plpgsql as $$
+ declare
+ text1 text = 'one';
+ text2 text = 'two, three';
+ text3 text = 'four; five';
+ text4 text = 'say "Hello" to me';
+ begin
+ return array[text1, text2, text3, null, text4];
+ end; $$;
+ """).executeUpdate();
+ final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnStringArray()", String[].class).getSingleResult();
+
+ final String[] result = PostgresArray.fromPostgresArray(pgArray, String.class, Function.identity());
+
+ assertThat(result).containsExactly("one", "two, three", "four; five", null, "say \"Hello\" to me");
+ }
+
+ @Test
+ void shouldCreateUUidArray() {
+ em.createNativeQuery("""
+ create or replace function returnUuidArray()
+ returns uuid[]
+ stable leakproof
+ language plpgsql as $$
+ declare
+ uuid1 UUID = 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
+ uuid2 UUID = '6ba7b810-9dad-11d1-80b4-00c04fd430c8';
+ uuid3 UUID = '01234567-89ab-cdef-0123-456789abcdef';
+ begin
+ return ARRAY[uuid1, uuid2, null, uuid3];
+ end; $$;
+ """).executeUpdate();
+ final byte[] pgArray = (byte[]) em.createNativeQuery("SELECT returnUuidArray()", UUID[].class).getSingleResult();
+
+ final UUID[] result = PostgresArray.fromPostgresArray(pgArray, UUID.class, UUID::fromString);
+
+ assertThat(result).containsExactly(
+ UUID.fromString("f47ac10b-58cc-4372-a567-0e02b2c3d479"),
+ UUID.fromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
+ null,
+ UUID.fromString("01234567-89ab-cdef-0123-456789abcdef"));
+ }
+}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
index 0402dbfe..6f0abc93 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantControllerAcceptanceTest.java
@@ -26,7 +26,6 @@ import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.*;
@@ -343,7 +342,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
}
private void assumeCreated(final ValidatableResponse response) {
- assumeThat(response.extract().response().statusCode()).isEqualTo(201);
+ assertThat(response.extract().response().statusCode()).isEqualTo(201);
}
class Subject {
@@ -479,7 +478,7 @@ class RbacGrantControllerAcceptanceTest extends ContextBasedTest {
}
private void assumeGrantExists(final Subject grantingSubject, final String expectedGrant) {
- assumeThat(findAllGrantsOf(grantingSubject))
+ assertThat(findAllGrantsOf(grantingSubject))
.extracting(RbacGrantEntity::toDisplay)
.contains(expectedGrant);
}
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
index 3ff9eda0..3b09e861 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacgrant/RbacGrantRepositoryIntegrationTest.java
@@ -25,7 +25,6 @@ import java.util.UUID;
import static net.hostsharing.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@@ -186,9 +185,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// when
context("customer-admin@xxx.example.com", "test_customer#xxx.admin");
- final var revokeAttempt = attempt(em, () -> {
- rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId());
- });
+ final var revokeAttempt = attempt(em, () ->
+ rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
context("customer-admin@xxx.example.com", "test_customer#xxx.admin");
@@ -208,9 +206,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// when
context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00.admin");
- final var revokeAttempt = attempt(em, () -> {
- rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId());
- });
+ final var revokeAttempt = attempt(em, () ->
+ rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
assertThat(revokeAttempt.caughtExceptionsRootCause()).isNull();
@@ -230,9 +227,8 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
// when
context("pac-admin-xxx00@xxx.example.com", "test_package#xxx00.admin");
- final var revokeAttempt = attempt(em, () -> {
- rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId());
- });
+ final var revokeAttempt = attempt(em, () ->
+ rbacGrantRepository.deleteByRbacGrantId(grant.getRbacGrantId()));
// then
revokeAttempt.assertExceptionWithRootCauseMessage(
@@ -255,10 +251,10 @@ class RbacGrantRepositoryIntegrationTest extends ContextBasedTest {
rbacGrantRepository.save(grant)
);
- assumeThat(grantAttempt.caughtException()).isNull();
- assumeThat(rawRbacGrantRepository.findAll())
+ assertThat(grantAttempt.caughtException()).isNull();
+ assertThat(rawRbacGrantRepository.findAll())
.extracting(RawRbacGrantEntity::toDisplay)
- .contains("{ grant role %s to user %s by role %s and assume }".formatted(
+ .contains("{ grant role %s to user %s by %s and assume }".formatted(
with.grantedRole, with.granteeUserName, with.assumedRole
));
diff --git a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
index bd2257ef..ea0a3109 100644
--- a/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/rbac/rbacuser/RbacUserRepositoryIntegrationTest.java
@@ -61,11 +61,6 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
assertThat(result.returnedValue()).isNotNull()
.extracting(RbacUserEntity::getUuid).isEqualTo(givenUuid);
assertThat(rbacUserRepository.findByName(result.returnedValue().getName())).isNotNull();
- // jpaAttempt.transacted(() -> {
- // context(givenUser.getName());
- // assertThat(em.find(RbacUserEntity.class, givenUser.getUuid()))
- // .isNotNull().extracting(RbacUserEntity::getName).isEqualTo(givenUser.getName());
- // }).assertSuccessful();
}
}
@@ -87,9 +82,6 @@ class RbacUserRepositoryIntegrationTest extends ContextBasedTest {
// then the user is deleted
result.assertSuccessful();
assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull();
- // jpaAttempt.transacted(() -> {
- // assertThat(rbacUserRepository.findByName(givenUser.getName())).isNull();
- // }).assertSuccessful();
}
}
diff --git a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java
index 7d5b0b43..bb00975f 100644
--- a/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java
+++ b/src/test/java/net/hostsharing/hsadminng/test/cust/TestCustomer.java
@@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.test.cust;
-import static java.util.UUID.randomUUID;
public class TestCustomer {
diff --git a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java
index e8cfc5bb..fd51ebf8 100644
--- a/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java
+++ b/src/test/java/net/hostsharing/hsadminng/test/pac/TestPackageControllerAcceptanceTest.java
@@ -16,7 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;
import static java.lang.String.format;
-import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@@ -85,7 +85,8 @@ class TestPackageControllerAcceptanceTest {
@Test
void withDescriptionUpdatesDescription() {
- assumeThat(getDescriptionOfPackage("xxx00"))
+ assertThat(getDescriptionOfPackage("xxx00"))
+ .as("precondition failed")
.isEqualTo("Here you can add your own description of package xxx00.");
final var randomDescription = RandomStringUtils.randomAlphanumeric(80);
@@ -117,7 +118,8 @@ class TestPackageControllerAcceptanceTest {
@Test
void withNullDescriptionUpdatesDescriptionToNull() {
- assumeThat(getDescriptionOfPackage("xxx01"))
+ assertThat(getDescriptionOfPackage("xxx01"))
+ .as("precondition failed")
.isEqualTo("Here you can add your own description of package xxx01.");
// @formatter:off
@@ -146,7 +148,8 @@ class TestPackageControllerAcceptanceTest {
@Test
void withoutDescriptionDoesNothing() {
- assumeThat(getDescriptionOfPackage("xxx02"))
+ assertThat(getDescriptionOfPackage("xxx02"))
+ .as("precondition failed")
.isEqualTo("Here you can add your own description of package xxx02.");
// @formatter:off
diff --git a/src/test/java/net/hostsharing/test/JpaAttempt.java b/src/test/java/net/hostsharing/test/JpaAttempt.java
index a7244e37..589049bb 100644
--- a/src/test/java/net/hostsharing/test/JpaAttempt.java
+++ b/src/test/java/net/hostsharing/test/JpaAttempt.java
@@ -12,7 +12,6 @@ import java.util.Optional;
import java.util.function.Supplier;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
/**
* Wraps the 'when' part of a DataJpaTest to improve readability of tests.
@@ -138,7 +137,7 @@ public class JpaAttempt {
}
public JpaResult assumeSuccessful() {
- assumeThat(exception).as(firstRootCauseMessageLineOf(exception)).isNull();
+ assertThat(exception).as(firstRootCauseMessageLineOf(exception)).isNull();
return this;
}
diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml
index 9915854e..a4f570f9 100644
--- a/src/test/resources/application.yml
+++ b/src/test/resources/application.yml
@@ -4,7 +4,7 @@ spring:
platform: postgres
datasource:
- url: jdbc:tc:postgresql:13.7-bullseye:///spring_boot_testcontainers
+ url: jdbc:tc:postgresql:15.5-bookworm:///spring_boot_testcontainers
url-local: jdbc:postgresql://localhost:5432/postgres
username: postgres
password: password