Merge branch 'bugfix/swagger-ui-on-management-port-to-bypass-cas' into feature/dependency-versions-upgrade

This commit is contained in:
Michael Hoennig 2025-01-09 08:05:22 +01:00
commit bb790166d4
18 changed files with 112 additions and 58 deletions

View File

@ -109,7 +109,7 @@ Also try for example 'admin@xxx.example.com' or 'unknown@example.org'.
If you want a formatted JSON output, you can pipe the result to `jq` or similar. If you want a formatted JSON output, you can pipe the result to `jq` or similar.
And to see the full, currently implemented, API, open http://localhost:8080/swagger-ui/index.html. And to see the full, currently implemented, API, open http://localhost:8081/actuator/swagger-ui/index.html (uses management-port and thus bypasses authentication).
If you still need to install some of these tools, find some hints in the next chapters. If you still need to install some of these tools, find some hints in the next chapters.

View File

@ -13,10 +13,16 @@ if [ "$1" == "--trace" ]; then
} }
function doCurl() { function doCurl() {
set -x set -x
curl --fail-with-body \ if [ -z "$HSADMINNG_CAS_ASSUME" ]; then
--header "Authorization: $HSADMINNG_CAS_TICKET" \ curl --fail-with-body \
--header "assumed-roles: $HSADMINNG_CAS_ASSUME" \ --header "Authorization: $HSADMINNG_CAS_TICKET" \
"$@" "$@"
else
curl --fail-with-body \
--header "Authorization: $HSADMINNG_CAS_TICKET" \
--header "assumed-roles: $HSADMINNG_CAS_ASSUME" \
"$@"
fi
set +x set +x
} }
shift shift

View File

@ -45,13 +45,13 @@ public class CasAuthenticator implements Authenticator {
private String casValidation(final HttpServletRequest httpRequest) private String casValidation(final HttpServletRequest httpRequest)
throws SAXException, IOException, ParserConfigurationException { throws SAXException, IOException, ParserConfigurationException {
System.err.println("CasAuthenticator.casValidation using CAS-server: " + casServerUrl);
final var ticket = httpRequest.getHeader("Authorization"); final var ticket = httpRequest.getHeader("Authorization");
final var url = casServerUrl + "/p3/serviceValidate" + final var url = casServerUrl + "/p3/serviceValidate" +
"?service=" + serviceUrl + "?service=" + serviceUrl +
"&ticket=" + ticket; "&ticket=" + ticket;
System.err.println("CasAuthenticator.casValidation using URL: " + url);
final var response = restTemplate.getForObject(url, String.class); final var response = restTemplate.getForObject(url, String.class);
final var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() final var doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()

View File

@ -88,9 +88,9 @@ public class HsOfficeDebitorEntity implements BaseEntity<HsOfficeDebitorEntity>,
( (
SELECT DISTINCT partner.uuid SELECT DISTINCT partner.uuid
FROM hs_office.partner_rv partner FROM hs_office.partner_rv partner
JOIN hs_office.relation_rv dRel JOIN hs_office.relation dRel
ON dRel.uuid = debitorreluuid AND dRel.type = 'DEBITOR' ON dRel.uuid = debitorreluuid AND dRel.type = 'DEBITOR'
JOIN hs_office.relation_rv pRel JOIN hs_office.relation pRel
ON pRel.uuid = partner.partnerRelUuid AND pRel.type = 'PARTNER' ON pRel.uuid = partner.partnerRelUuid AND pRel.type = 'PARTNER'
WHERE pRel.holderUuid = dRel.anchorUuid WHERE pRel.holderUuid = dRel.anchorUuid
) )

View File

@ -9,6 +9,7 @@ import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder; import lombok.experimental.SuperBuilder;
import net.hostsharing.hsadminng.errors.DisplayAs; import net.hostsharing.hsadminng.errors.DisplayAs;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.role.WithRoleId;
import net.hostsharing.hsadminng.repr.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.repr.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
@ -30,7 +31,7 @@ import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@SuperBuilder(toBuilder = true) @SuperBuilder(toBuilder = true)
@FieldNameConstants @FieldNameConstants
@DisplayAs("Person") @DisplayAs("Person")
public class HsOfficePerson<T extends HsOfficePerson<?> & BaseEntity<?>> implements BaseEntity<T>, Stringifyable { public class HsOfficePerson<T extends HsOfficePerson<?> & BaseEntity<?>> implements BaseEntity<T>, Stringifyable, WithRoleId {
private static Stringify<HsOfficePerson> toString = stringify(HsOfficePerson.class, "person") private static Stringify<HsOfficePerson> toString = stringify(HsOfficePerson.class, "person")
.withProp(Fields.personType, HsOfficePerson::getPersonType) .withProp(Fields.personType, HsOfficePerson::getPersonType)

View File

@ -6,6 +6,7 @@ import lombok.experimental.SuperBuilder;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity; import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
import net.hostsharing.hsadminng.persistence.BaseEntity; import net.hostsharing.hsadminng.persistence.BaseEntity;
import net.hostsharing.hsadminng.rbac.role.WithRoleId;
import net.hostsharing.hsadminng.repr.Stringify; import net.hostsharing.hsadminng.repr.Stringify;
import net.hostsharing.hsadminng.repr.Stringifyable; import net.hostsharing.hsadminng.repr.Stringifyable;
@ -22,7 +23,7 @@ import static net.hostsharing.hsadminng.repr.Stringify.stringify;
@Setter @Setter
@SuperBuilder(toBuilder = true) @SuperBuilder(toBuilder = true)
@FieldNameConstants @FieldNameConstants
public class HsOfficeRelation implements BaseEntity<HsOfficeRelation>, Stringifyable { public class HsOfficeRelation implements BaseEntity<HsOfficeRelation>, Stringifyable, WithRoleId {
private static Stringify<HsOfficeRelation> toString = stringify(HsOfficeRelation.class, "rel") private static Stringify<HsOfficeRelation> toString = stringify(HsOfficeRelation.class, "rel")
.withProp(Fields.anchor, HsOfficeRelation::getAnchor) .withProp(Fields.anchor, HsOfficeRelation::getAnchor)

View File

@ -0,0 +1,20 @@
package net.hostsharing.hsadminng.rbac.role;
import jakarta.persistence.Table;
import java.util.UUID;
public interface WithRoleId {
UUID getUuid();
/**
* @return the RBAC-Role-Id of the given `rbacRoleType` for this entity instance.
*/
default String roleId(final RbacRoleType rbacRoleType) {
if ( getUuid() == null ) {
throw new IllegalStateException("UUID missing => role can't be determined");
}
final Table tableAnnot = getClass().getAnnotation(Table.class);
final var qualifiedTableName = tableAnnot.schema() + "." + tableAnnot.name();
return qualifiedTableName + "#" + getUuid() + ":" + rbacRoleType.name();
}
}

View File

@ -9,7 +9,7 @@ management:
web: web:
exposure: exposure:
# HOWTO: view _clickable_ Spring Actuator (Micrometer) Metrics endpoints: http://localhost:8081/actuator/metric-links # HOWTO: view _clickable_ Spring Actuator (Micrometer) Metrics endpoints: http://localhost:8081/actuator/metric-links
include: info, health, metrics, metric-links include: info, health, metrics, metric-links, mappings, openapi, swaggerui
observations: observations:
annotations: annotations:
enabled: true enabled: true
@ -30,6 +30,10 @@ spring:
hibernate: hibernate:
dialect: net.hostsharing.hsadminng.config.PostgresCustomDialect dialect: net.hostsharing.hsadminng.config.PostgresCustomDialect
# keep this in sync with test/.../application.yml
springdoc:
use-management-port: true
liquibase: liquibase:
contexts: dev contexts: dev

View File

@ -251,7 +251,7 @@ begin
execute sql into uuid; execute sql into uuid;
exception exception
when others then when others then
raise exception 'function %_uuid_by_id_name(''%'') failed: %, SQLSTATE: %. If it could not be found, add identity view support to %\nSQL:%', raise exception 'function %_uuid_by_id_name(''%'') failed: %, SQLSTATE: %. If the function itself could not be found, add identity view support to %\nSQL:%',
objectTable, objectIdName, SQLERRM, SQLSTATE, objectTable, sql; objectTable, objectIdName, SQLERRM, SQLSTATE, objectTable, sql;
end; end;
if uuid is null then if uuid is null then
@ -275,7 +275,7 @@ begin
execute sql into idName; execute sql into idName;
exception exception
when others then when others then
raise exception 'function %_id_name_by_uuid(''%'') failed: %, SQLSTATE: %. If it could not be found, add identity view support to %', raise exception 'function %_id_name_by_uuid(''%'') failed: %, SQLSTATE: %. If the function itself could not be found, add identity view support to %',
objectTable, objectUuid, SQLERRM, SQLSTATE, objectTable; objectTable, objectUuid, SQLERRM, SQLSTATE, objectTable;
end; end;
return idName; return idName;

View File

@ -29,8 +29,24 @@ create table if not exists hs_office.relation
); );
--// --//
-- TODO.impl: unique constraint, to prevent using the same person multiple times as a partner, or better:
-- ( anchorUuid, holderUuid, type) -- ============================================================================
--changeset michael.hoennig:hs-office-relation-unique-constraints endDelimiter:--//
-- ----------------------------------------------------------------------------
CREATE UNIQUE INDEX unique_relation_with_mark
ON hs_office.relation (type, anchorUuid, holderUuid, contactUuid, mark)
WHERE mark IS NOT NULL;
CREATE UNIQUE INDEX unique_relation_without_mark
ON hs_office.relation (type, anchorUuid, holderUuid, contactUuid)
WHERE mark IS NULL;
CREATE UNIQUE INDEX unique_partner_relation
ON hs_office.relation (type, anchorUuid, holderUuid)
WHERE mark IS NULL AND type = 'PARTNER';
--//
-- ============================================================================ -- ============================================================================

View File

@ -100,8 +100,8 @@ do language plpgsql $$
call hs_office.relation_create_test_data('Third OHG', 'DEBITOR', 'Third OHG', 'third contact'); call hs_office.relation_create_test_data('Third OHG', 'DEBITOR', 'Third OHG', 'third contact');
call hs_office.relation_create_test_data('Fourth eG', 'PARTNER', 'Hostsharing eG', 'fourth contact'); call hs_office.relation_create_test_data('Fourth eG', 'PARTNER', 'Hostsharing eG', 'fourth contact');
call hs_office.relation_create_test_data('Fouler', 'REPRESENTATIVE', 'Third OHG', 'third contact'); call hs_office.relation_create_test_data('Fouler', 'REPRESENTATIVE', 'Fourth eG', 'fourth contact');
call hs_office.relation_create_test_data('Third OHG', 'DEBITOR', 'Third OHG', 'third contact'); call hs_office.relation_create_test_data('Fourth eG', 'DEBITOR', 'Fourth eG', 'fourth contact');
call hs_office.relation_create_test_data('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact'); call hs_office.relation_create_test_data('Smith', 'PARTNER', 'Hostsharing eG', 'sixth contact');
call hs_office.relation_create_test_data('Smith', 'DEBITOR', 'Smith', 'third contact'); call hs_office.relation_create_test_data('Smith', 'DEBITOR', 'Smith', 'third contact');

View File

@ -82,14 +82,14 @@ class WebSecurityConfigIntegrationTest {
@Test @Test
public void shouldSupportSwaggerUi() { public void shouldSupportSwaggerUi() {
final var result = this.restTemplate.getForEntity( final var result = this.restTemplate.getForEntity(
"http://localhost:" + this.managementPort + "/swagger-ui/index.html", String.class); "http://localhost:" + this.managementPort + "/actuator/swagger-ui/index.html", String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK);
} }
@Test @Test
public void shouldSupportApiDocs() { public void shouldSupportApiDocs() {
final var result = this.restTemplate.getForEntity( final var result = this.restTemplate.getForEntity(
"http://localhost:" + this.managementPort + "/v3/api-docs/swagger-config", String.class); "http://localhost:" + this.managementPort + "/actuator/v3/api-docs/swagger-config", String.class);
assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); // permitted but not configured assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); // permitted but not configured
} }

View File

@ -170,19 +170,18 @@ public class CsvDataImport extends ContextBasedTest {
} }
public <T extends BaseEntity> T persistViaEM(final Integer id, final T entity) { public <T extends BaseEntity> T persistViaEM(final Integer id, final T entity) {
//System.out.println("persisting #" + entity.hashCode() + ": " + entity); if (em.contains(entity)) {
if (!em.contains(entity)) { return entity;
em.persist(entity); }
try {
em.persist(entity);
em.flush(); // makes it a bit slower, but produces better error messages
System.out.println("persisted #" + id + " as " + entity.getUuid());
return entity;
} catch (final Exception exc) {
System.err.println("persist failed for #" + id + " as " + entity);
throw exc; // for breakpoints
} }
// uncomment for debugging purposes
// try {
// em.flush(); // makes it slow, but produces better error messages
// System.out.println("persisted #" + entity.hashCode() + " as " + entity.getUuid());
// return entity;
// } catch (final Exception exc) {
// throw exc; // for breakpoints
// }
return entity;
} }
@SneakyThrows @SneakyThrows

View File

@ -616,7 +616,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor(); final var givenDebitor = givenSomeTemporaryDebitor();
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth").get(0); final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("tenth").get(0);
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
.given() .given()
@ -644,7 +644,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
"holder": { "tradeName": "Fourth eG" }, "holder": { "tradeName": "Fourth eG" },
"type": "DEBITOR", "type": "DEBITOR",
"mark": null, "mark": null,
"contact": { "caption": "fourth contact" } "contact": { "caption": "tenth contact" }
}, },
"debitorNumber": "D-10004${debitorNumberSuffix}", "debitorNumber": "D-10004${debitorNumberSuffix}",
"debitorNumberSuffix": "${debitorNumberSuffix}", "debitorNumberSuffix": "${debitorNumberSuffix}",
@ -685,7 +685,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
.matches(debitor -> { .matches(debitor -> {
assertThat(debitor.getDebitorRel().getHolder().getTradeName()) assertThat(debitor.getDebitorRel().getHolder().getTradeName())
.isEqualTo(givenDebitor.getDebitorRel().getHolder().getTradeName()); .isEqualTo(givenDebitor.getDebitorRel().getHolder().getTradeName());
assertThat(debitor.getDebitorRel().getContact().getCaption()).isEqualTo("fourth contact"); assertThat(debitor.getDebitorRel().getContact().getCaption()).isEqualTo("tenth contact");
assertThat(debitor.getVatId()).isEqualTo("VAT222222"); assertThat(debitor.getVatId()).isEqualTo("VAT222222");
assertThat(debitor.getVatCountryCode()).isEqualTo("AA"); assertThat(debitor.getVatCountryCode()).isEqualTo("AA");
assertThat(debitor.isVatBusiness()).isEqualTo(true); assertThat(debitor.isVatBusiness()).isEqualTo(true);
@ -704,7 +704,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("current-subject", "superuser-alex@hostsharing.net") .header("current-subject", "superuser-alex@hostsharing.net")
.header("assumed-roles", "hs_office.contact#fourthcontact:ADMIN") .header("assumed-roles", "hs_office.contact#tenthcontact:ADMIN")
.contentType(ContentType.JSON) .contentType(ContentType.JSON)
.body(""" .body("""
{ {
@ -747,11 +747,11 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
void contactAdminUser_canNotDeleteRelatedDebitor() { void contactAdminUser_canNotDeleteRelatedDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor(); final var givenDebitor = givenSomeTemporaryDebitor();
assertThat(givenDebitor.getDebitorRel().getContact().getCaption()).isEqualTo("fourth contact"); assertThat(givenDebitor.getDebitorRel().getContact().getCaption()).isEqualTo("tenth contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
.header("current-subject", "contact-admin@fourthcontact.example.com") .header("current-subject", "contact-admin@tenthcontact.example.com")
.port(port) .port(port)
.when() .when()
.delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid()) .delete("http://localhost/api/hs/office/debitors/" + givenDebitor.getUuid())
@ -766,7 +766,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
void normalUser_canNotDeleteUnrelatedDebitor() { void normalUser_canNotDeleteUnrelatedDebitor() {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor(); final var givenDebitor = givenSomeTemporaryDebitor();
assertThat(givenDebitor.getDebitorRel().getContact().getCaption()).isEqualTo("fourth contact"); assertThat(givenDebitor.getDebitorRel().getContact().getCaption()).isEqualTo("tenth contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -786,7 +786,7 @@ class HsOfficeDebitorControllerAcceptanceTest extends ContextBasedTestWithCleanu
return jpaAttempt.transacted(() -> { return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0).load(); final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0).load();
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth contact").get(0); final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("tenth contact").get(0);
final var newDebitor = HsOfficeDebitorEntity.builder() final var newDebitor = HsOfficeDebitorEntity.builder()
.debitorNumberSuffix(nextDebitorSuffix()) .debitorNumberSuffix(nextDebitorSuffix())
.billable(true) .billable(true)

View File

@ -33,6 +33,7 @@ import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN;
import static net.hostsharing.hsadminng.rbac.test.EntityList.one; import static net.hostsharing.hsadminng.rbac.test.EntityList.one;
import static net.hostsharing.hsadminng.rbac.grant.RawRbacGrantEntity.distinctGrantDisplaysOf; import static net.hostsharing.hsadminng.rbac.grant.RawRbacGrantEntity.distinctGrantDisplaysOf;
import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf; import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf;
@ -85,7 +86,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
final var count = debitorRepo.count(); final var count = debitorRepo.count();
final var givenPartner = partnerRepo.findPartnerByPartnerNumber(10001).orElseThrow(); final var givenPartner = partnerRepo.findPartnerByPartnerNumber(10001).orElseThrow();
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH")); final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH"));
final var givenContact = one(contactRealRepo.findContactByOptionalCaptionLike("first contact")); final var givenContact = one(contactRealRepo.findContactByOptionalCaptionLike("eleventh contact"));
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -119,7 +120,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH")); final var givenPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First GmbH"));
final var givenContact = one(contactRealRepo.findContactByOptionalCaptionLike("first contact")); final var givenContact = one(contactRealRepo.findContactByOptionalCaptionLike("eleventh contact"));
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -335,10 +336,11 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif"); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", "Fourth", "fif");
final var originalDebitorRel = givenDebitor.getDebitorRel();
assertThatDebitorIsVisibleForUserWithRole( assertThatDebitorIsVisibleForUserWithRole(
givenDebitor, givenDebitor,
"hs_office.relation#FourtheG-with-DEBITOR-FourtheG:ADMIN", true); givenDebitor.getDebitorRel().roleId(ADMIN), true);
final var givenNewPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First")); final var givenNewPartnerPerson = one(personRepo.findPersonByOptionalNameLike("First"));
final var givenNewBillingPerson = one(personRepo.findPersonByOptionalNameLike("Firby")); final var givenNewBillingPerson = one(personRepo.findPersonByOptionalNameLike("Firby"));
final var givenNewContact = one(contactRealRepo.findContactByOptionalCaptionLike("sixth contact")); final var givenNewContact = one(contactRealRepo.findContactByOptionalCaptionLike("sixth contact"));
@ -371,10 +373,10 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// ... partner role was reassigned: // ... partner role was reassigned:
assertThatDebitorIsNotVisibleForUserWithRole( assertThatDebitorIsNotVisibleForUserWithRole(
result.returnedValue(), result.returnedValue(),
"hs_office.relation#FourtheG-with-DEBITOR-FourtheG:ADMIN"); originalDebitorRel.roleId(ADMIN));
assertThatDebitorIsVisibleForUserWithRole( assertThatDebitorIsVisibleForUserWithRole(
result.returnedValue(), result.returnedValue(),
"hs_office.relation#FirstGmbH-with-DEBITOR-FirbySusan:AGENT", true); result.returnedValue().getDebitorRel().roleId(ADMIN), true);
// ... contact role was reassigned: // ... contact role was reassigned:
assertThatDebitorIsNotVisibleForUserWithRole( assertThatDebitorIsNotVisibleForUserWithRole(
@ -397,10 +399,10 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
public void globalAdmin_canUpdateNullRefundBankAccountToNotNullBankAccountForArbitraryDebitor() { public void globalAdmin_canUpdateNullRefundBankAccountToNotNullBankAccountForArbitraryDebitor() {
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "fifth contact", null, "fig"); final var givenDebitor = givenSomeTemporaryDebitor("Fourth", "tenth contact", null, "fig");
assertThatDebitorIsVisibleForUserWithRole( assertThatDebitorIsVisibleForUserWithRole(
givenDebitor, givenDebitor,
"hs_office.relation#FourtheG-with-DEBITOR-FourtheG:ADMIN", true); givenDebitor.getDebitorRel().roleId(ADMIN), true);
assertThatDebitorActuallyInDatabase(givenDebitor, true); assertThatDebitorActuallyInDatabase(givenDebitor, true);
final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first")); final var givenNewBankAccount = one(bankAccountRepo.findByOptionalHolderLike("first"));
@ -564,7 +566,7 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", "hs_office.relation#FourtheG-with-DEBITOR-FourtheG:ADMIN"); context("superuser-alex@hostsharing.net", givenDebitor.getDebitorRel().roleId(ADMIN));
assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent(); assertThat(debitorRepo.findByUuid(givenDebitor.getUuid())).isPresent();
debitorRepo.deleteByUuid(givenDebitor.getUuid()); debitorRepo.deleteByUuid(givenDebitor.getUuid());

View File

@ -94,7 +94,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG").stream().findFirst().orElseThrow(); final var givenMandantPerson = personRealRepo.findPersonByOptionalNameLike("Hostsharing eG").stream().findFirst().orElseThrow();
final var givenPerson = personRealRepo.findPersonByOptionalNameLike("Third").stream().findFirst().orElseThrow(); final var givenPerson = personRealRepo.findPersonByOptionalNameLike("Winkler").stream().findFirst().orElseThrow();
final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth").stream().findFirst().orElseThrow(); final var givenContact = contactRealRepo.findContactByOptionalCaptionLike("fourth").stream().findFirst().orElseThrow();
final var location = RestAssured // @formatter:off final var location = RestAssured // @formatter:off
@ -129,7 +129,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
"partnerNumber": "P-20002", "partnerNumber": "P-20002",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "Third OHG" }, "holder": { "familyName": "Winkler" },
"type": "PARTNER", "type": "PARTNER",
"mark": null, "mark": null,
"contact": { "caption": "fourth contact" } "contact": { "caption": "fourth contact" }
@ -315,7 +315,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenPartner = givenSomeTemporaryPartnerBessler(20011); final var givenPartner = givenSomeTemporaryPartnerBessler(20011);
final var givenPartnerRel = givenSomeTemporaryPartnerRel("Third OHG", "third contact"); final var givenPartnerRel = givenSomeTemporaryPartnerRel("Winkler", "third contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -345,7 +345,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
"partnerNumber": "P-20011", "partnerNumber": "P-20011",
"partnerRel": { "partnerRel": {
"anchor": { "tradeName": "Hostsharing eG" }, "anchor": { "tradeName": "Hostsharing eG" },
"holder": { "tradeName": "Third OHG" }, "holder": { "familyName": "Winkler" },
"type": "PARTNER", "type": "PARTNER",
"contact": { "caption": "third contact" } "contact": { "caption": "third contact" }
}, },
@ -366,7 +366,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get() assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get()
.matches(partner -> { .matches(partner -> {
assertThat(partner.getPartnerNumber()).isEqualTo(givenPartner.getPartnerNumber()); assertThat(partner.getPartnerNumber()).isEqualTo(givenPartner.getPartnerNumber());
assertThat(partner.getPartnerRel().getHolder().getTradeName()).isEqualTo("Third OHG"); assertThat(partner.getPartnerRel().getHolder().getFamilyName()).isEqualTo("Winkler");
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact"); assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact");
assertThat(partner.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Aurich"); assertThat(partner.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Aurich");
assertThat(partner.getDetails().getRegistrationNumber()).isEqualTo("222222"); assertThat(partner.getDetails().getRegistrationNumber()).isEqualTo("222222");
@ -382,7 +382,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
final var givenPartner = givenSomeTemporaryPartnerBessler(20011); final var givenPartner = givenSomeTemporaryPartnerBessler(20011);
final var givenPartnerRel = givenSomeTemporaryPartnerRel("Third OHG", "third contact"); final var givenPartnerRel = givenSomeTemporaryPartnerRel("Winkler", "third contact");
RestAssured // @formatter:off RestAssured // @formatter:off
.given() .given()
@ -404,7 +404,7 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu
context.define("superuser-alex@hostsharing.net"); context.define("superuser-alex@hostsharing.net");
assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get() assertThat(partnerRepo.findByUuid(givenPartner.getUuid())).isPresent().get()
.matches(partner -> { .matches(partner -> {
assertThat(partner.getPartnerRel().getHolder().getTradeName()).isEqualTo("Third OHG"); assertThat(partner.getPartnerRel().getHolder().getFamilyName()).isEqualTo("Winkler");
assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact"); assertThat(partner.getPartnerRel().getContact().getCaption()).isEqualTo("third contact");
return true; return true;
}); });

View File

@ -31,6 +31,7 @@ import static net.hostsharing.hsadminng.rbac.grant.RawRbacGrantEntity.distinctGr
import static net.hostsharing.hsadminng.rbac.role.RawRbacObjectEntity.objectDisplaysOf; import static net.hostsharing.hsadminng.rbac.role.RawRbacObjectEntity.objectDisplaysOf;
import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf; import static net.hostsharing.hsadminng.rbac.role.RawRbacRoleEntity.distinctRoleNamesOf;
import static net.hostsharing.hsadminng.mapper.Array.from; import static net.hostsharing.hsadminng.mapper.Array.from;
import static net.hostsharing.hsadminng.rbac.role.RbacRoleType.ADMIN;
import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt; import static net.hostsharing.hsadminng.rbac.test.JpaAttempt.attempt;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -76,7 +77,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
// given // given
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
final var count = partnerRepo.count(); final var count = partnerRepo.count();
final var partnerRel = givenSomeTemporaryHostsharingPartnerRel("First GmbH", "first contact"); final var partnerRel = givenSomeTemporaryHostsharingPartnerRel("Winkler", "first contact");
// when // when
final var result = attempt(em, () -> { final var result = attempt(em, () -> {
@ -269,7 +270,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
// when // when
final var result = jpaAttempt.transacted(() -> { final var result = jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net"); context("superuser-alex@hostsharing.net");
givenPartner.setPartnerRel(givenSomeTemporaryHostsharingPartnerRel("Third OHG", "sixth contact")); givenPartner.setPartnerRel(givenSomeTemporaryHostsharingPartnerRel("Winkler", "sixth contact"));
return partnerRepo.save(givenPartner); return partnerRepo.save(givenPartner);
}); });
@ -281,7 +282,7 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTestWithClean
"rbac.global#global:ADMIN"); "rbac.global#global:ADMIN");
assertThatPartnerIsVisibleForUserWithRole( assertThatPartnerIsVisibleForUserWithRole(
givenPartner, givenPartner,
"hs_office.person#ThirdOHG:ADMIN"); givenPartner.getPartnerRel().getHolder().roleId(ADMIN));
assertThatPartnerIsNotVisibleForUserWithRole( assertThatPartnerIsNotVisibleForUserWithRole(
givenPartner, givenPartner,
"hs_office.person#ErbenBesslerMelBessler:ADMIN"); "hs_office.person#ErbenBesslerMelBessler:ADMIN");

View File

@ -39,6 +39,10 @@ spring:
change-log: classpath:/db/changelog/db.changelog-master.yaml change-log: classpath:/db/changelog/db.changelog-master.yaml
contexts: tc,test,dev,pg_stat_statements contexts: tc,test,dev,pg_stat_statements
# keep this in sync with main/.../application.yml
springdoc:
use-management-port: true
logging: logging:
level: level:
liquibase: WARN liquibase: WARN