feature/api-for-email-address-search-in-contacts (#113)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Co-authored-by: Michael Hönnig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/113 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
.aliases
bin
build.gradlesrc
main
java
net
hostsharing
hsadminng
hs
booking
project
hosting
asset
office
validation
lambda
mapper
rbac
resources
api-definition
hs-office
test
java
net
hostsharing
hsadminng
hs
booking
hosting
office
debitor
membership
person
relation
sepamandate
validation
lambda
mapper
@@ -3,30 +3,14 @@ package net.hostsharing.hsadminng.hs.booking.project;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationRbacEntity;
|
||||
import net.hostsharing.hsadminng.rbac.generator.RbacView;
|
||||
import net.hostsharing.hsadminng.rbac.generator.RbacView.SQL;
|
||||
import net.hostsharing.hsadminng.persistence.BaseEntity;
|
||||
import net.hostsharing.hsadminng.stringify.Stringify;
|
||||
import net.hostsharing.hsadminng.stringify.Stringifyable;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.hs.office.relation.HsOfficeRelationType.DEBITOR;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Column.dependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.ColumnValue.usingCase;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.ColumnValue.usingDefaultCase;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.GLOBAL;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Nullable.NOT_NULL;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Permission.*;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.Role.*;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.directlyFetchedByDependsOnColumn;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.SQL.fetchedBySql;
|
||||
import static net.hostsharing.hsadminng.rbac.generator.RbacView.rbacViewFor;
|
||||
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
|
||||
|
||||
@MappedSuperclass
|
||||
@@ -66,50 +50,4 @@ public abstract class HsBookingProject implements Stringifyable, BaseEntity<HsBo
|
||||
return ofNullable(debitor).map(HsBookingDebitorEntity::toShortString).orElse("D-???????") +
|
||||
":" + caption;
|
||||
}
|
||||
|
||||
public static RbacView rbac() {
|
||||
return rbacViewFor("project", HsBookingProjectRbacEntity.class)
|
||||
.withIdentityView(SQL.query("""
|
||||
SELECT bookingProject.uuid as uuid, debitorIV.idName || '-' || base.cleanIdentifier(bookingProject.caption) as idName
|
||||
FROM hs_booking.project bookingProject
|
||||
JOIN hs_office.debitor_iv debitorIV ON debitorIV.uuid = bookingProject.debitorUuid
|
||||
"""))
|
||||
.withRestrictedViewOrderBy(SQL.expression("caption"))
|
||||
.withUpdatableColumns("version", "caption")
|
||||
|
||||
.importEntityAlias("debitor", HsOfficeDebitorEntity.class, usingDefaultCase(),
|
||||
dependsOnColumn("debitorUuid"),
|
||||
directlyFetchedByDependsOnColumn(),
|
||||
NOT_NULL)
|
||||
|
||||
.importEntityAlias("debitorRel", HsOfficeRelationRbacEntity.class, usingCase(DEBITOR),
|
||||
dependsOnColumn("debitorUuid"),
|
||||
fetchedBySql("""
|
||||
SELECT ${columns}
|
||||
FROM hs_office.relation debitorRel
|
||||
JOIN hs_office.debitor debitor ON debitor.debitorRelUuid = debitorRel.uuid
|
||||
WHERE debitor.uuid = ${REF}.debitorUuid
|
||||
"""),
|
||||
NOT_NULL)
|
||||
.toRole("debitorRel", ADMIN).grantPermission(INSERT)
|
||||
.toRole(GLOBAL, ADMIN).grantPermission(DELETE)
|
||||
|
||||
.createRole(OWNER, (with) -> {
|
||||
with.incomingSuperRole("debitorRel", AGENT).unassumed();
|
||||
})
|
||||
.createSubRole(ADMIN, (with) -> {
|
||||
with.permission(UPDATE);
|
||||
})
|
||||
.createSubRole(AGENT)
|
||||
.createSubRole(TENANT, (with) -> {
|
||||
with.outgoingSubRole("debitorRel", TENANT);
|
||||
with.permission(SELECT);
|
||||
})
|
||||
|
||||
.limitDiagramTo("project", "debitorRel", "rbac.global");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
rbac().generateWithBaseFileName("6-hs-booking/620-booking-project/6203-hs-booking-project-rbac");
|
||||
}
|
||||
}
|
||||
|
@@ -10,12 +10,14 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||
import net.hostsharing.hsadminng.lambda.Reducer;
|
||||
import net.hostsharing.hsadminng.mapper.StandardMapper;
|
||||
import net.hostsharing.hsadminng.mapper.ToStringConverter;
|
||||
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.net.IDN;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_DNS_SETUP;
|
||||
@@ -109,8 +111,8 @@ public class DomainSetupHostingAssetFactory extends HostingAssetFactory {
|
||||
final var subAssetResourceOptional = findSubHostingAssetResource(resourceType);
|
||||
|
||||
subAssetResourceOptional.ifPresentOrElse(
|
||||
subAssetResource -> verifyNotOverspecified(subAssetResource),
|
||||
() -> { throw new ValidationException("sub-asset of type " + resourceType.name() + " required in legacy mode, but missing"); }
|
||||
this::verifyNotOverspecified,
|
||||
() -> { throw new ValidationException("sub-asset of type " + resourceType.name() + " required in legacy mode, but missing"); }
|
||||
);
|
||||
|
||||
return builderTransformer.apply(
|
||||
@@ -150,4 +152,8 @@ public class DomainSetupHostingAssetFactory extends HostingAssetFactory {
|
||||
super.persist(newHostingAsset);
|
||||
newHostingAsset.getSubHostingAssets().forEach(super::persist);
|
||||
}
|
||||
|
||||
private <T> T ref(final Class<T> entityClass, final UUID uuid) {
|
||||
return uuid != null ? emw.getReference(entityClass, uuid) : null;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.factories;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRealEntity;
|
||||
@@ -8,7 +9,6 @@ import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityS
|
||||
import net.hostsharing.hsadminng.mapper.StandardMapper;
|
||||
import net.hostsharing.hsadminng.persistence.EntityManagerWrapper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
abstract class HostingAssetFactory {
|
||||
@@ -20,13 +20,13 @@ abstract class HostingAssetFactory {
|
||||
|
||||
protected abstract HsHostingAsset create();
|
||||
|
||||
public String performSaveProcess() {
|
||||
public String createAndPersist() {
|
||||
try {
|
||||
final var newHostingAsset = create();
|
||||
final HsHostingAsset newHostingAsset = create();
|
||||
persist(newHostingAsset);
|
||||
return null;
|
||||
} catch (final Exception e) {
|
||||
return e.getMessage();
|
||||
} catch (final ValidationException exc) {
|
||||
return exc.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,4 @@ abstract class HostingAssetFactory {
|
||||
.save()
|
||||
.validateContext();
|
||||
}
|
||||
|
||||
protected <T> T ref(final Class<T> entityClass, final UUID uuid) {
|
||||
return uuid != null ? emw.getReference(entityClass, uuid) : null;
|
||||
}
|
||||
}
|
||||
|
14
src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java
14
src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/factories/HsBookingItemCreatedListener.java
@@ -2,6 +2,8 @@ package net.hostsharing.hsadminng.hs.hosting.asset.factories;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.validation.ValidationException;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.SneakyThrows;
|
||||
import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsHostingAssetAutoInsertResource;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.BookingItemCreatedAppEvent;
|
||||
@@ -13,7 +15,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component
|
||||
public class HsBookingItemCreatedListener implements ApplicationListener<BookingItemCreatedAppEvent> {
|
||||
|
||||
@@ -28,7 +29,7 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void onApplicationEvent(final BookingItemCreatedAppEvent bookingItemCreatedAppEvent) {
|
||||
public void onApplicationEvent(@NotNull BookingItemCreatedAppEvent bookingItemCreatedAppEvent) {
|
||||
if (containsAssetJson(bookingItemCreatedAppEvent)) {
|
||||
createRelatedHostingAsset(bookingItemCreatedAppEvent);
|
||||
}
|
||||
@@ -48,7 +49,7 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
||||
case DOMAIN_SETUP -> new DomainSetupHostingAssetFactory(emw, newBookingItemRealEntity, asset, standardMapper);
|
||||
};
|
||||
if (factory != null) {
|
||||
final var statusMessage = factory.performSaveProcess();
|
||||
final var statusMessage = factory.createAndPersist();
|
||||
// TODO.impl: once we implement retry, we need to amend this code (persist/merge/delete)
|
||||
if (statusMessage != null) {
|
||||
event.getEntity().setStatusMessage(statusMessage);
|
||||
@@ -68,12 +69,7 @@ public class HsBookingItemCreatedListener implements ApplicationListener<Booking
|
||||
@Override
|
||||
protected HsHostingAsset create() {
|
||||
// TODO.impl: we should validate the asset JSON, but some violations are un-avoidable at that stage
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String performSaveProcess() {
|
||||
return "waiting for manual setup of hosting asset for booking item of type " + fromBookingItem.getType();
|
||||
throw new ValidationException("waiting for manual setup of hosting asset for booking item of type " + fromBookingItem.getType());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
private HsOfficePersonRepository holderRepo;
|
||||
|
||||
@Autowired
|
||||
private HsOfficeContactRealRepository contactrealRepo;
|
||||
private HsOfficeContactRealRepository realContactRepo;
|
||||
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
@@ -48,11 +48,16 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
final String currentSubject,
|
||||
final String assumedRoles,
|
||||
final UUID personUuid,
|
||||
final HsOfficeRelationTypeResource relationType) {
|
||||
final HsOfficeRelationTypeResource relationType,
|
||||
final String personData,
|
||||
final String contactData) {
|
||||
context.define(currentSubject, assumedRoles);
|
||||
|
||||
final var entities = relationRbacRepo.findRelationRelatedToPersonUuidAndRelationType(personUuid,
|
||||
relationType == null ? null : HsOfficeRelationType.valueOf(relationType.name()));
|
||||
final List<HsOfficeRelationRbacEntity> entities =
|
||||
relationRbacRepo.findRelationRelatedToPersonUuidRelationTypePersonAndContactData(
|
||||
personUuid,
|
||||
relationType == null ? null : HsOfficeRelationType.valueOf(relationType.name()),
|
||||
personData, contactData);
|
||||
|
||||
final var resources = mapper.mapList(entities, HsOfficeRelationResource.class,
|
||||
RELATION_ENTITY_TO_RESOURCE_POSTMAPPER);
|
||||
@@ -77,7 +82,7 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
entityToSave.setHolder(holderRepo.findByUuid(body.getHolderUuid()).orElseThrow(
|
||||
() -> new NoSuchElementException("cannot find Person by holderUuid: " + body.getHolderUuid())
|
||||
));
|
||||
entityToSave.setContact(contactrealRepo.findByUuid(body.getContactUuid()).orElseThrow(
|
||||
entityToSave.setContact(realContactRepo.findByUuid(body.getContactUuid()).orElseThrow(
|
||||
() -> new NoSuchElementException("cannot find Contact by contactUuid: " + body.getContactUuid())
|
||||
));
|
||||
|
||||
@@ -144,7 +149,6 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||
return ResponseEntity.ok(mapped);
|
||||
}
|
||||
|
||||
|
||||
final BiConsumer<HsOfficeRelationRbacEntity, HsOfficeRelationResource> RELATION_ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> {
|
||||
resource.setAnchor(mapper.map(entity.getAnchor(), HsOfficePersonResource.class));
|
||||
resource.setHolder(mapper.map(entity.getHolder(), HsOfficePersonResource.class));
|
||||
|
@@ -12,26 +12,62 @@ public interface HsOfficeRelationRbacRepository extends Repository<HsOfficeRelat
|
||||
|
||||
Optional<HsOfficeRelationRbacEntity> findByUuid(UUID id);
|
||||
|
||||
default List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidAndRelationType(@NotNull UUID personUuid, HsOfficeRelationType relationType) {
|
||||
return findRelationRelatedToPersonUuidAndRelationTypeString(personUuid, relationType == null ? null : relationType.toString());
|
||||
}
|
||||
|
||||
@Query(value = """
|
||||
SELECT p.* FROM hs_office.relation_rv AS p
|
||||
WHERE p.anchorUuid = :personUuid OR p.holderUuid = :personUuid
|
||||
""", nativeQuery = true)
|
||||
List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuid(@NotNull UUID personUuid);
|
||||
|
||||
/**
|
||||
* Finds relations by a conjunction of optional criteria, including anchorPerson, holderPerson and contact data.
|
||||
* *
|
||||
* @param personUuid the optional UUID of the anchorPerson or holderPerson
|
||||
* @param relationType the type of the relation
|
||||
* @param personData a string to match the persons tradeName, familyName or givenName (use '%' for wildcard), case ignored
|
||||
* @param contactData a string to match the contacts caption, postalAddress, emailAddresses or phoneNumbers (use '%' for wildcard), case ignored
|
||||
* @return a list of (accessible) relations which match all given criteria
|
||||
*/
|
||||
default List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationTypePersonAndContactData(
|
||||
UUID personUuid,
|
||||
HsOfficeRelationType relationType,
|
||||
String personData,
|
||||
String contactData) {
|
||||
return findRelationRelatedToPersonUuidRelationTypePersonAndContactDataImpl(
|
||||
personUuid, toStringOrNull(relationType), toSqlLikeOperand(personData), toSqlLikeOperand(contactData));
|
||||
}
|
||||
|
||||
@Query(value = """
|
||||
SELECT p.* FROM hs_office.relation_rv AS p
|
||||
WHERE (:relationType IS NULL OR p.type = cast(:relationType AS hs_office.RelationType))
|
||||
AND ( p.anchorUuid = :personUuid OR p.holderUuid = :personUuid)
|
||||
""", nativeQuery = true)
|
||||
List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidAndRelationTypeString(@NotNull UUID personUuid, String relationType);
|
||||
SELECT rel FROM HsOfficeRelationRbacEntity AS rel
|
||||
WHERE (:relationType IS NULL OR CAST(rel.type AS String) = :relationType)
|
||||
AND ( :personUuid IS NULL
|
||||
OR rel.anchor.uuid = :personUuid OR rel.holder.uuid = :personUuid )
|
||||
AND ( :personData IS NULL
|
||||
OR lower(rel.anchor.tradeName) LIKE :personData OR lower(rel.holder.tradeName) LIKE :personData
|
||||
OR lower(rel.anchor.familyName) LIKE :personData OR lower(rel.holder.familyName) LIKE :personData
|
||||
OR lower(rel.anchor.givenName) LIKE :personData OR lower(rel.holder.givenName) LIKE :personData )
|
||||
AND ( :contactData IS NULL
|
||||
OR lower(rel.contact.caption) LIKE :contactData
|
||||
OR lower(rel.contact.postalAddress) LIKE :contactData
|
||||
OR lower(CAST(rel.contact.emailAddresses AS String)) LIKE :contactData
|
||||
OR lower(CAST(rel.contact.phoneNumbers AS String)) LIKE :contactData )
|
||||
""")
|
||||
List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationTypePersonAndContactDataImpl(
|
||||
final UUID personUuid,
|
||||
final String relationType,
|
||||
final String personData,
|
||||
final String contactData);
|
||||
|
||||
HsOfficeRelationRbacEntity save(final HsOfficeRelationRbacEntity entity);
|
||||
|
||||
long count();
|
||||
|
||||
int deleteByUuid(UUID uuid);
|
||||
|
||||
private static String toSqlLikeOperand(final String text) {
|
||||
return text == null ? null : ("%" + text.toLowerCase() + "%");
|
||||
}
|
||||
|
||||
private static String toStringOrNull(final HsOfficeRelationType relationType) {
|
||||
return relationType == null ? null : relationType.name();
|
||||
}
|
||||
}
|
||||
|
@@ -56,6 +56,10 @@ public class IntegerProperty<P extends IntegerProperty<P>> extends ValidatablePr
|
||||
return unit;
|
||||
}
|
||||
|
||||
public Integer min() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public Integer max() {
|
||||
return max;
|
||||
}
|
||||
|
@@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.validation;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Setter;
|
||||
import net.hostsharing.hsadminng.mapper.Array;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -83,11 +84,15 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
|
||||
}
|
||||
|
||||
/// predefined values, similar to fixed values in a combobox
|
||||
public P provided(final String... provided) {
|
||||
this.provided = provided;
|
||||
public P provided(final String firstProvidedValue, final String... moreProvidedValues) {
|
||||
this.provided = ArrayUtils.addAll(new String[]{firstProvidedValue}, moreProvidedValues);
|
||||
return self();
|
||||
}
|
||||
|
||||
public String[] provided() {
|
||||
return this.provided;
|
||||
}
|
||||
|
||||
/**
|
||||
* The property value is not disclosed in error messages.
|
||||
*
|
||||
@@ -109,7 +114,11 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
|
||||
|
||||
@Override
|
||||
protected String display(final String propValue) {
|
||||
return undisclosed ? "provided value" : ("'" + propValue + "'");
|
||||
return undisclosed
|
||||
? "provided value"
|
||||
: propValue != null
|
||||
? ("'" + propValue + "'")
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -1,7 +1,10 @@
|
||||
package net.hostsharing.hsadminng.lambda;
|
||||
|
||||
import lombok.experimental.UtilityClass;
|
||||
|
||||
@UtilityClass
|
||||
public class Reducer {
|
||||
public static <T> T toSingleElement(T last, T next) {
|
||||
public static <T> T toSingleElement(T ignoredLast, T ignoredNext) {
|
||||
throw new AssertionError("only a single entity expected");
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,6 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.factories;
|
||||
package net.hostsharing.hsadminng.mapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
@@ -16,8 +13,7 @@ public class ToStringConverter {
|
||||
return this;
|
||||
}
|
||||
|
||||
public String from(Object obj) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
public String from(final Object obj) {
|
||||
return "{ " +
|
||||
Arrays.stream(obj.getClass().getDeclaredFields())
|
||||
.filter(f -> !ignoredFields.contains(f.getName()))
|
||||
@@ -34,4 +30,15 @@ public class ToStringConverter {
|
||||
.collect(joining(", "))
|
||||
+ " }";
|
||||
}
|
||||
|
||||
public String from(final Map<?, ?> map) {
|
||||
return "{ "
|
||||
+ map.keySet().stream()
|
||||
.filter(key -> !ignoredFields.contains(key.toString()))
|
||||
.sorted()
|
||||
.map(k -> Map.entry(k, map.get(k)))
|
||||
.map(e -> e.getKey() + ": " + e.getValue())
|
||||
.collect(joining(", "))
|
||||
+ " }";
|
||||
}
|
||||
}
|
@@ -30,7 +30,7 @@ public class RbacGrantsDiagramService {
|
||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
|
||||
writer.write("""
|
||||
### all grants to %s
|
||||
|
||||
|
||||
```mermaid
|
||||
%s
|
||||
```
|
||||
@@ -62,7 +62,7 @@ public class RbacGrantsDiagramService {
|
||||
@PersistenceContext
|
||||
private EntityManager em;
|
||||
|
||||
private Map<UUID, List<RawRbacGrantEntity>> descendantsByUuid = new HashMap<>();
|
||||
private final Map<UUID, List<RawRbacGrantEntity>> descendantsByUuid = new HashMap<>();
|
||||
|
||||
public String allGrantsTocurrentSubject(final EnumSet<Include> includes) {
|
||||
final var graph = new LimitedHashSet<RawRbacGrantEntity>();
|
||||
@@ -231,8 +231,7 @@ public class RbacGrantsDiagramService {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
record Node(String idName, UUID uuid) {
|
||||
record Node(String idName, UUID uuid) {
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
get:
|
||||
summary: Returns a list of (optionally filtered) person relations for a given person.
|
||||
description: Returns the list of (optionally filtered) person relations of a given person and which are visible to the current subject or any of it's assumed roles.
|
||||
description:
|
||||
Returns the list of (optionally filtered) person relations of a given person and which are visible to the current subject or any of it's assumed roles.
|
||||
To match data, all given query parameters must be fulfilled ('and' / logical conjunction).
|
||||
tags:
|
||||
- hs-office-relations
|
||||
operationId: listRelations
|
||||
@@ -9,7 +11,7 @@ get:
|
||||
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||
- name: personUuid
|
||||
in: query
|
||||
required: true
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
@@ -20,6 +22,18 @@ get:
|
||||
schema:
|
||||
$ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationType'
|
||||
description: Prefix of name properties from holder or contact to filter the results.
|
||||
- name: personData
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: 'Data from any of these text field in the anchor or holder person: tradeName, familyName, givenName'
|
||||
- name: contactData
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: 'Data from any of these text field in the contact: caption, postalAddress, emailAddresses, phoneNumbers'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
|
Reference in New Issue
Block a user