create relation with holder- and contact-data, and search for contact emailAddress + relation mark (#136)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: #136 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
parent
19fac6b5e1
commit
20fa27194b
@ -13,8 +13,16 @@ public class Validate {
|
|||||||
return new Validate(variableNames);
|
return new Validate(variableNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void atMaxOneNonNull(final Object var1, final Object var2) {
|
public final void atMaxOne(final Object var1, final Object var2) {
|
||||||
if (var1 != null && var2 != null) {
|
if (var1 != null && var2 != null) {
|
||||||
|
throw new ValidationException(
|
||||||
|
"At maximum one of (" + variableNames + ") must be non-null, " +
|
||||||
|
"but are (" + var1 + ", " + var2 + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void exactlyOne(final Object var1, final Object var2) {
|
||||||
|
if ((var1 != null) == (var2 != null)) {
|
||||||
throw new ValidationException(
|
throw new ValidationException(
|
||||||
"Exactly one of (" + variableNames + ") must be non-null, " +
|
"Exactly one of (" + variableNames + ") must be non-null, " +
|
||||||
"but are (" + var1 + ", " + var2 + ")");
|
"but are (" + var1 + ", " + var2 + ")");
|
||||||
|
@ -17,6 +17,7 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.errors.Validate.validate;
|
||||||
import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
|
import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@ -38,10 +39,14 @@ public class HsOfficeContactController implements HsOfficeContactsApi {
|
|||||||
public ResponseEntity<List<HsOfficeContactResource>> getListOfContacts(
|
public ResponseEntity<List<HsOfficeContactResource>> getListOfContacts(
|
||||||
final String currentSubject,
|
final String currentSubject,
|
||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final String caption) {
|
final String caption,
|
||||||
|
final String emailAddress) {
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var entities = contactRepo.findContactByOptionalCaptionLike(caption);
|
validate("caption, emailAddress").atMaxOne(caption, emailAddress);
|
||||||
|
final var entities = emailAddress != null
|
||||||
|
? contactRepo.findContactByEmailAddress(emailAddress)
|
||||||
|
: contactRepo.findContactByOptionalCaptionLike(caption);
|
||||||
|
|
||||||
final var resources = mapper.mapList(entities, HsOfficeContactResource.class);
|
final var resources = mapper.mapList(entities, HsOfficeContactResource.class);
|
||||||
return ResponseEntity.ok(resources);
|
return ResponseEntity.ok(resources);
|
||||||
|
@ -21,6 +21,16 @@ public interface HsOfficeContactRbacRepository extends Repository<HsOfficeContac
|
|||||||
@Timed("app.office.contacts.repo.findContactByOptionalCaptionLike.rbac")
|
@Timed("app.office.contacts.repo.findContactByOptionalCaptionLike.rbac")
|
||||||
List<HsOfficeContactRbacEntity> findContactByOptionalCaptionLike(String caption);
|
List<HsOfficeContactRbacEntity> findContactByOptionalCaptionLike(String caption);
|
||||||
|
|
||||||
|
@Query(value = """
|
||||||
|
select c.* from hs_office.contact_rv c
|
||||||
|
where exists (
|
||||||
|
SELECT 1 FROM jsonb_each_text(c.emailAddresses) AS kv(key, value)
|
||||||
|
WHERE kv.value LIKE :emailAddressRegEx
|
||||||
|
)
|
||||||
|
""", nativeQuery = true)
|
||||||
|
@Timed("app.office.contacts.repo.findContactByEmailAddress.rbac")
|
||||||
|
List<HsOfficeContactRbacEntity> findContactByEmailAddress(final String emailAddressRegEx);
|
||||||
|
|
||||||
@Timed("app.office.contacts.repo.save.rbac")
|
@Timed("app.office.contacts.repo.save.rbac")
|
||||||
HsOfficeContactRbacEntity save(final HsOfficeContactRbacEntity entity);
|
HsOfficeContactRbacEntity save(final HsOfficeContactRbacEntity entity);
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
|
|||||||
final String partnerNumber) {
|
final String partnerNumber) {
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
validate("partnerUuid, partnerNumber").atMaxOneNonNull(partnerUuid, partnerNumber);
|
validate("partnerUuid, partnerNumber").atMaxOne(partnerUuid, partnerNumber);
|
||||||
|
|
||||||
final var entities = partnerNumber != null
|
final var entities = partnerNumber != null
|
||||||
? membershipRepo.findMembershipsByPartnerNumber(
|
? membershipRepo.findMembershipsByPartnerNumber(
|
||||||
|
@ -35,10 +35,10 @@ public class HsOfficePersonController implements HsOfficePersonsApi {
|
|||||||
public ResponseEntity<List<HsOfficePersonResource>> getListOfPersons(
|
public ResponseEntity<List<HsOfficePersonResource>> getListOfPersons(
|
||||||
final String currentSubject,
|
final String currentSubject,
|
||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final String caption) {
|
final String name) {
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var entities = personRepo.findPersonByOptionalNameLike(caption);
|
final var entities = personRepo.findPersonByOptionalNameLike(name);
|
||||||
|
|
||||||
final var resources = mapper.mapList(entities, HsOfficePersonResource.class);
|
final var resources = mapper.mapList(entities, HsOfficePersonResource.class);
|
||||||
return ResponseEntity.ok(resources);
|
return ResponseEntity.ok(resources);
|
||||||
|
@ -2,9 +2,12 @@ package net.hostsharing.hsadminng.hs.office.relation;
|
|||||||
|
|
||||||
import io.micrometer.core.annotation.Timed;
|
import io.micrometer.core.annotation.Timed;
|
||||||
import net.hostsharing.hsadminng.context.Context;
|
import net.hostsharing.hsadminng.context.Context;
|
||||||
|
import net.hostsharing.hsadminng.errors.Validate;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRealRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeRelationsApi;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeRelationsApi;
|
||||||
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.*;
|
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.*;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealEntity;
|
||||||
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
|
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonRealRepository;
|
||||||
import net.hostsharing.hsadminng.mapper.StandardMapper;
|
import net.hostsharing.hsadminng.mapper.StandardMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -20,6 +23,7 @@ import java.util.NoSuchElementException;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
import static net.hostsharing.hsadminng.mapper.KeyValueMap.from;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
||||||
@ -31,10 +35,10 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
private StandardMapper mapper;
|
private StandardMapper mapper;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficeRelationRbacRepository relationRbacRepo;
|
private HsOfficeRelationRbacRepository rbacRelationRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficePersonRealRepository personRepo;
|
private HsOfficePersonRealRepository realPersonRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private HsOfficeContactRealRepository realContactRepo;
|
private HsOfficeContactRealRepository realContactRepo;
|
||||||
@ -50,15 +54,16 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
final String assumedRoles,
|
final String assumedRoles,
|
||||||
final UUID personUuid,
|
final UUID personUuid,
|
||||||
final HsOfficeRelationTypeResource relationType,
|
final HsOfficeRelationTypeResource relationType,
|
||||||
|
final String mark,
|
||||||
final String personData,
|
final String personData,
|
||||||
final String contactData) {
|
final String contactData) {
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final List<HsOfficeRelationRbacEntity> entities =
|
final List<HsOfficeRelationRbacEntity> entities =
|
||||||
relationRbacRepo.findRelationRelatedToPersonUuidRelationTypePersonAndContactData(
|
rbacRelationRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(
|
||||||
personUuid,
|
personUuid,
|
||||||
relationType == null ? null : HsOfficeRelationType.valueOf(relationType.name()),
|
relationType == null ? null : HsOfficeRelationType.valueOf(relationType.name()),
|
||||||
personData, contactData);
|
mark, personData, contactData);
|
||||||
|
|
||||||
final var resources = mapper.mapList(entities, HsOfficeRelationResource.class,
|
final var resources = mapper.mapList(entities, HsOfficeRelationResource.class,
|
||||||
RELATION_ENTITY_TO_RESOURCE_POSTMAPPER);
|
RELATION_ENTITY_TO_RESOURCE_POSTMAPPER);
|
||||||
@ -78,17 +83,34 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
final var entityToSave = new HsOfficeRelationRbacEntity();
|
final var entityToSave = new HsOfficeRelationRbacEntity();
|
||||||
entityToSave.setType(HsOfficeRelationType.valueOf(body.getType()));
|
entityToSave.setType(HsOfficeRelationType.valueOf(body.getType()));
|
||||||
entityToSave.setMark(body.getMark());
|
entityToSave.setMark(body.getMark());
|
||||||
entityToSave.setAnchor(personRepo.findByUuid(body.getAnchorUuid()).orElseThrow(
|
|
||||||
|
entityToSave.setAnchor(realPersonRepo.findByUuid(body.getAnchorUuid()).orElseThrow(
|
||||||
() -> new NoSuchElementException("cannot find Person by anchorUuid: " + body.getAnchorUuid())
|
() -> new NoSuchElementException("cannot find Person by anchorUuid: " + body.getAnchorUuid())
|
||||||
));
|
));
|
||||||
entityToSave.setHolder(personRepo.findByUuid(body.getHolderUuid()).orElseThrow(
|
|
||||||
() -> new NoSuchElementException("cannot find Person by holderUuid: " + body.getHolderUuid())
|
|
||||||
));
|
|
||||||
entityToSave.setContact(realContactRepo.findByUuid(body.getContactUuid()).orElseThrow(
|
|
||||||
() -> new NoSuchElementException("cannot find Contact by contactUuid: " + body.getContactUuid())
|
|
||||||
));
|
|
||||||
|
|
||||||
final var saved = relationRbacRepo.save(entityToSave);
|
Validate.validate("anchor, anchor.uuid").exactlyOne(body.getHolder(), body.getHolderUuid());
|
||||||
|
if ( body.getHolderUuid() != null) {
|
||||||
|
entityToSave.setHolder(realPersonRepo.findByUuid(body.getHolderUuid()).orElseThrow(
|
||||||
|
() -> new NoSuchElementException("cannot find Person by holderUuid: " + body.getHolderUuid())
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
entityToSave.setHolder(realPersonRepo.save(
|
||||||
|
mapper.map(body.getHolder(), HsOfficePersonRealEntity.class)
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
Validate.validate("contact, contact.uuid").exactlyOne(body.getContact(), body.getContactUuid());
|
||||||
|
if ( body.getContactUuid() != null) {
|
||||||
|
entityToSave.setContact(realContactRepo.findByUuid(body.getContactUuid()).orElseThrow(
|
||||||
|
() -> new NoSuchElementException("cannot find Contact by contactUuid: " + body.getContactUuid())
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
entityToSave.setContact(realContactRepo.save(
|
||||||
|
mapper.map(body.getContact(), HsOfficeContactRealEntity.class, CONTACT_RESOURCE_TO_ENTITY_POSTMAPPER)
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
|
||||||
|
final var saved = rbacRelationRepo.save(entityToSave);
|
||||||
|
|
||||||
final var uri =
|
final var uri =
|
||||||
MvcUriComponentsBuilder.fromController(getClass())
|
MvcUriComponentsBuilder.fromController(getClass())
|
||||||
@ -110,7 +132,7 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
|
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var result = relationRbacRepo.findByUuid(relationUuid);
|
final var result = rbacRelationRepo.findByUuid(relationUuid);
|
||||||
if (result.isEmpty()) {
|
if (result.isEmpty()) {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
@ -126,7 +148,7 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
final UUID relationUuid) {
|
final UUID relationUuid) {
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var result = relationRbacRepo.deleteByUuid(relationUuid);
|
final var result = rbacRelationRepo.deleteByUuid(relationUuid);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
return ResponseEntity.notFound().build();
|
return ResponseEntity.notFound().build();
|
||||||
}
|
}
|
||||||
@ -145,11 +167,11 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
|
|
||||||
context.define(currentSubject, assumedRoles);
|
context.define(currentSubject, assumedRoles);
|
||||||
|
|
||||||
final var current = relationRbacRepo.findByUuid(relationUuid).orElseThrow();
|
final var current = rbacRelationRepo.findByUuid(relationUuid).orElseThrow();
|
||||||
|
|
||||||
new HsOfficeRelationEntityPatcher(em, current).apply(body);
|
new HsOfficeRelationEntityPatcher(em, current).apply(body);
|
||||||
|
|
||||||
final var saved = relationRbacRepo.save(current);
|
final var saved = rbacRelationRepo.save(current);
|
||||||
final var mapped = mapper.map(saved, HsOfficeRelationResource.class);
|
final var mapped = mapper.map(saved, HsOfficeRelationResource.class);
|
||||||
return ResponseEntity.ok(mapped);
|
return ResponseEntity.ok(mapped);
|
||||||
}
|
}
|
||||||
@ -159,4 +181,11 @@ public class HsOfficeRelationController implements HsOfficeRelationsApi {
|
|||||||
resource.setHolder(mapper.map(entity.getHolder(), HsOfficePersonResource.class));
|
resource.setHolder(mapper.map(entity.getHolder(), HsOfficePersonResource.class));
|
||||||
resource.setContact(mapper.map(entity.getContact(), HsOfficeContactResource.class));
|
resource.setContact(mapper.map(entity.getContact(), HsOfficeContactResource.class));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final BiConsumer<HsOfficeContactInsertResource, HsOfficeContactRealEntity> CONTACT_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||||
|
entity.putEmailAddresses(from(resource.getEmailAddresses()));
|
||||||
|
entity.putPhoneNumbers(from(resource.getPhoneNumbers()));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
@ -26,24 +26,29 @@ public interface HsOfficeRelationRbacRepository extends Repository<HsOfficeRelat
|
|||||||
* *
|
* *
|
||||||
* @param personUuid the optional UUID of the anchorPerson or holderPerson
|
* @param personUuid the optional UUID of the anchorPerson or holderPerson
|
||||||
* @param relationType the type of the relation
|
* @param relationType the type of the relation
|
||||||
|
* @param mark the mark (use '%' for wildcard), case ignored
|
||||||
* @param personData a string to match the persons tradeName, familyName or givenName (use '%' for wildcard), case ignored
|
* @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
|
* @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
|
* @return a list of (accessible) relations which match all given criteria
|
||||||
*/
|
*/
|
||||||
default List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationTypePersonAndContactData(
|
default List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(
|
||||||
final UUID personUuid,
|
final UUID personUuid,
|
||||||
final HsOfficeRelationType relationType,
|
final HsOfficeRelationType relationType,
|
||||||
|
final String mark,
|
||||||
final String personData,
|
final String personData,
|
||||||
final String contactData) {
|
final String contactData) {
|
||||||
return findRelationRelatedToPersonUuidRelationTypePersonAndContactDataImpl(
|
return findRelationRelatedToPersonUuidRelationByTypeMarkPersonAndContactDataImpl(
|
||||||
personUuid, toStringOrNull(relationType), toSqlLikeOperand(personData), toSqlLikeOperand(contactData));
|
personUuid, toStringOrNull(relationType),
|
||||||
|
toSqlLikeOperand(mark), toSqlLikeOperand(personData), toSqlLikeOperand(contactData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use ELIKE instead of lower(...) LIKE ...? Or use jsonb_path with RegEx like emailAddressRegEx in ContactRepo?
|
||||||
@Query(value = """
|
@Query(value = """
|
||||||
SELECT rel FROM HsOfficeRelationRbacEntity AS rel
|
SELECT rel FROM HsOfficeRelationRbacEntity AS rel
|
||||||
WHERE (:relationType IS NULL OR CAST(rel.type AS String) = :relationType)
|
WHERE (:relationType IS NULL OR CAST(rel.type AS String) = :relationType)
|
||||||
AND ( :personUuid IS NULL
|
AND ( :personUuid IS NULL
|
||||||
OR rel.anchor.uuid = :personUuid OR rel.holder.uuid = :personUuid )
|
OR rel.anchor.uuid = :personUuid OR rel.holder.uuid = :personUuid )
|
||||||
|
AND ( :mark IS NULL OR lower(rel.mark) LIKE :mark )
|
||||||
AND ( :personData IS NULL
|
AND ( :personData IS NULL
|
||||||
OR lower(rel.anchor.tradeName) LIKE :personData OR lower(rel.holder.tradeName) LIKE :personData
|
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.familyName) LIKE :personData OR lower(rel.holder.familyName) LIKE :personData
|
||||||
@ -54,10 +59,11 @@ public interface HsOfficeRelationRbacRepository extends Repository<HsOfficeRelat
|
|||||||
OR lower(CAST(rel.contact.emailAddresses AS String)) LIKE :contactData
|
OR lower(CAST(rel.contact.emailAddresses AS String)) LIKE :contactData
|
||||||
OR lower(CAST(rel.contact.phoneNumbers AS String)) LIKE :contactData )
|
OR lower(CAST(rel.contact.phoneNumbers AS String)) LIKE :contactData )
|
||||||
""")
|
""")
|
||||||
@Timed("app.office.relations.repo.findRelationRelatedToPersonUuidRelationTypePersonAndContactDataImpl.rbac")
|
@Timed("app.office.relations.repo.findRelationRelatedToPersonUuidRelationByTypeMarkPersonAndContactDataImpl.rbac")
|
||||||
List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationTypePersonAndContactDataImpl(
|
List<HsOfficeRelationRbacEntity> findRelationRelatedToPersonUuidRelationByTypeMarkPersonAndContactDataImpl(
|
||||||
final UUID personUuid,
|
final UUID personUuid,
|
||||||
final String relationType,
|
final String relationType,
|
||||||
|
final String mark,
|
||||||
final String personData,
|
final String personData,
|
||||||
final String contactData);
|
final String contactData);
|
||||||
|
|
||||||
|
@ -7,12 +7,19 @@ get:
|
|||||||
parameters:
|
parameters:
|
||||||
- $ref: 'auth.yaml#/components/parameters/currentSubject'
|
- $ref: 'auth.yaml#/components/parameters/currentSubject'
|
||||||
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: name
|
- name: caption
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
description: Prefix of caption to filter the results.
|
description: Beginning of caption to filter the results.
|
||||||
|
- name: emailAddress
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
|
Email-address to filter the results, use '%' as wildcard.
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
|
@ -52,6 +52,8 @@ components:
|
|||||||
holder.uuid:
|
holder.uuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
holder:
|
||||||
|
$ref: 'hs-office-person-schemas.yaml#/components/schemas/HsOfficePersonInsert'
|
||||||
type:
|
type:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
@ -61,11 +63,17 @@ components:
|
|||||||
contact.uuid:
|
contact.uuid:
|
||||||
type: string
|
type: string
|
||||||
format: uuid
|
format: uuid
|
||||||
|
contact:
|
||||||
|
$ref: 'hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContactInsert'
|
||||||
required:
|
required:
|
||||||
- anchor.uuid
|
- anchor.uuid
|
||||||
- holder.uuid
|
- type
|
||||||
- type
|
# soon we might need to be able to use this:
|
||||||
- contact.uuid
|
# https://community.smartbear.com/discussions/swaggerostools/defining-conditional-attributes-in-openapi/222410
|
||||||
|
# For now we just describe the conditionally required properties:
|
||||||
|
description:
|
||||||
|
Additionally to `type` and `anchor.uuid`, either `anchor.uuid` or `anchor`
|
||||||
|
and either `contact` or `contact.uuid` need to be given.
|
||||||
|
|
||||||
# relation created as a sub-element with implicitly known type
|
# relation created as a sub-element with implicitly known type
|
||||||
HsOfficeRelationSubInsert:
|
HsOfficeRelationSubInsert:
|
||||||
|
@ -21,7 +21,13 @@ get:
|
|||||||
required: false
|
required: false
|
||||||
schema:
|
schema:
|
||||||
$ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationType'
|
$ref: 'hs-office-relation-schemas.yaml#/components/schemas/HsOfficeRelationType'
|
||||||
description: Prefix of name properties from holder or contact to filter the results.
|
description: Beginning of name properties from holder or contact to filter the results.
|
||||||
|
- name: mark
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
description:
|
||||||
- name: personData
|
- name: personData
|
||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package net.hostsharing.hsadminng.errors;
|
package net.hostsharing.hsadminng.errors;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import jakarta.validation.ValidationException;
|
import jakarta.validation.ValidationException;
|
||||||
@ -9,23 +10,53 @@ import static org.assertj.core.api.Assertions.catchThrowable;
|
|||||||
|
|
||||||
class ValidateUnitTest {
|
class ValidateUnitTest {
|
||||||
|
|
||||||
@Test
|
@Nested
|
||||||
void shouldFailValidationIfBothParametersAreNotNull() {
|
class AtMaxOne {
|
||||||
final var throwable = catchThrowable(() ->
|
@Test
|
||||||
Validate.validate("var1, var2").atMaxOneNonNull("val1", "val2")
|
void shouldFailValidationIfBothParametersAreNotNull() {
|
||||||
);
|
final var throwable = catchThrowable(() ->
|
||||||
assertThat(throwable).isInstanceOf(ValidationException.class)
|
Validate.validate("var1, var2").atMaxOne("val1", "val2")
|
||||||
.hasMessage("Exactly one of (var1, var2) must be non-null, but are (val1, val2)");
|
);
|
||||||
|
assertThat(throwable).isInstanceOf(ValidationException.class)
|
||||||
|
.hasMessage("At maximum one of (var1, var2) must be non-null, but are (val1, val2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotFailValidationIfBothParametersAreNull() {
|
||||||
|
Validate.validate("var1, var2").atMaxOne(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotFailValidationIfExactlyOneParameterIsNonNull() {
|
||||||
|
Validate.validate("var1, var2").atMaxOne("val1", null);
|
||||||
|
Validate.validate("var1, var2").atMaxOne(null, "val2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Nested
|
||||||
void shouldNotFailValidationIfBothParametersAreull() {
|
class ExactlyOne {
|
||||||
Validate.validate("var1, var2").atMaxOneNonNull(null, null);
|
@Test
|
||||||
}
|
void shouldFailValidationIfBothParametersAreNotNull() {
|
||||||
|
final var throwable = catchThrowable(() ->
|
||||||
|
Validate.validate("var1, var2").exactlyOne("val1", "val2")
|
||||||
|
);
|
||||||
|
assertThat(throwable).isInstanceOf(ValidationException.class)
|
||||||
|
.hasMessage("Exactly one of (var1, var2) must be non-null, but are (val1, val2)");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldNotFailValidationIfExactlyOneParameterIsNonNull() {
|
void shouldFailValidationIfBothParametersAreNull() {
|
||||||
Validate.validate("var1, var2").atMaxOneNonNull("val1", null);
|
final var throwable = catchThrowable(() ->
|
||||||
Validate.validate("var1, var2").atMaxOneNonNull(null, "val2");
|
Validate.validate("var1, var2").exactlyOne(null, null)
|
||||||
|
);
|
||||||
|
assertThat(throwable).isInstanceOf(ValidationException.class)
|
||||||
|
.hasMessage("Exactly one of (var1, var2) must be non-null, but are (null, null)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotFailValidationIfExactlyOneParameterIsNonNull() {
|
||||||
|
Validate.validate("var1, var2").exactlyOne("val1", null);
|
||||||
|
Validate.validate("var1, var2").exactlyOne(null, "val2");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ class HsOfficeContactRbacRepositoryIntegrationTest extends ContextBasedTestWithC
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class FindAllContacts {
|
class FindContacts {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void globalAdmin_withoutAssumedRole_canViewAllContacts() {
|
public void globalAdmin_withoutAssumedRole_canViewAllContacts() {
|
||||||
@ -184,6 +184,22 @@ class HsOfficeContactRbacRepositoryIntegrationTest extends ContextBasedTestWithC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class FindByEmailAddress {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void globalAdmin_withoutAssumedRole_canFindContactsByEmailAddress() {
|
||||||
|
// given
|
||||||
|
context("superuser-alex@hostsharing.net", null);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final var result = contactRepo.findContactByEmailAddress("%@secondcontact.example.com");
|
||||||
|
|
||||||
|
// then
|
||||||
|
exactlyTheseContactsAreReturned(result, "second contact");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class DeleteByUuid {
|
class DeleteByUuid {
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
|
|||||||
class AddRelation {
|
class AddRelation {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void globalAdmin_withoutAssumedRole_canAddRelation() {
|
void globalAdmin_withoutAssumedRole_canAddRelationWithHolderUuidAndContactUuid() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Third").get(0);
|
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Third").get(0);
|
||||||
@ -261,7 +261,62 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
|
|||||||
.body("holder.givenName", is("Paul"))
|
.body("holder.givenName", is("Paul"))
|
||||||
.body("contact.caption", is("second contact"))
|
.body("contact.caption", is("second contact"))
|
||||||
.header("Location", startsWith("http://localhost"))
|
.header("Location", startsWith("http://localhost"))
|
||||||
.extract().header("Location"); // @formatter:on
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
|
// finally, the new relation can be accessed under the generated UUID
|
||||||
|
final var newSubjectUuid = toCleanup(HsOfficeRelationRealEntity.class, UUID.fromString(
|
||||||
|
location.substring(location.lastIndexOf('/') + 1)));
|
||||||
|
assertThat(newSubjectUuid).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void globalAdmin_withoutAssumedRole_canAddRelationWithHolderAndContactData() {
|
||||||
|
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
final var givenAnchorPerson = personRepo.findPersonByOptionalNameLike("Third").get(0);
|
||||||
|
|
||||||
|
final var location = RestAssured // @formatter:off
|
||||||
|
.given()
|
||||||
|
.header("current-subject", "superuser-alex@hostsharing.net")
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("""
|
||||||
|
{
|
||||||
|
"type": "%s",
|
||||||
|
"mark": "%s",
|
||||||
|
"anchor.uuid": "%s",
|
||||||
|
"holder": {
|
||||||
|
"personType": "NATURAL_PERSON",
|
||||||
|
"familyName": "Person",
|
||||||
|
"givenName": "Temp"
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"caption": "Temp Contact",
|
||||||
|
"emailAddresses": {
|
||||||
|
"main": "test@example.org"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".formatted(
|
||||||
|
HsOfficeRelationTypeResource.SUBSCRIBER,
|
||||||
|
"operations-discuss",
|
||||||
|
givenAnchorPerson.getUuid()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.port(port)
|
||||||
|
.when()
|
||||||
|
.post("http://localhost/api/hs/office/relations")
|
||||||
|
.then().log().all().assertThat()
|
||||||
|
.statusCode(201)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.body("uuid", isUuidValid())
|
||||||
|
.body("type", is("SUBSCRIBER"))
|
||||||
|
.body("mark", is("operations-discuss"))
|
||||||
|
.body("anchor.tradeName", is("Third OHG"))
|
||||||
|
.body("holder.givenName", is("Temp"))
|
||||||
|
.body("holder.familyName", is("Person"))
|
||||||
|
.body("contact.caption", is("Temp Contact"))
|
||||||
|
.header("Location", startsWith("http://localhost"))
|
||||||
|
.extract().header("Location"); // @formatter:on
|
||||||
|
|
||||||
// finally, the new relation can be accessed under the generated UUID
|
// finally, the new relation can be accessed under the generated UUID
|
||||||
final var newSubjectUuid = toCleanup(HsOfficeRelationRealEntity.class, UUID.fromString(
|
final var newSubjectUuid = toCleanup(HsOfficeRelationRealEntity.class, UUID.fromString(
|
||||||
@ -277,7 +332,7 @@ class HsOfficeRelationControllerAcceptanceTest extends ContextBasedTestWithClean
|
|||||||
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Smith").get(0);
|
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Smith").get(0);
|
||||||
final var givenContact = contactrealRepo.findContactByOptionalCaptionLike("fourth").get(0);
|
final var givenContact = contactrealRepo.findContactByOptionalCaptionLike("fourth").get(0);
|
||||||
|
|
||||||
final var location = RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
.header("current-subject", "superuser-alex@hostsharing.net")
|
.header("current-subject", "superuser-alex@hostsharing.net")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
|
@ -193,7 +193,7 @@ class HsOfficeRelationRepositoryIntegrationTest extends ContextBasedTestWithClea
|
|||||||
.findFirst().orElseThrow();
|
.findFirst().orElseThrow();
|
||||||
|
|
||||||
// when:
|
// when:
|
||||||
final var result = relationRbacRepo.findRelationRelatedToPersonUuidRelationTypePersonAndContactData(person.getUuid(), null, null, null);
|
final var result = relationRbacRepo.findRelationRelatedToPersonUuidRelationTypeMarkPersonAndContactData(person.getUuid(), null, null, null, null);
|
||||||
|
|
||||||
// then:
|
// then:
|
||||||
exactlyTheseRelationsAreReturned(
|
exactlyTheseRelationsAreReturned(
|
||||||
|
@ -31,7 +31,8 @@ import net.hostsharing.hsadminng.hs.office.scenarios.partner.CreatePartner;
|
|||||||
import net.hostsharing.hsadminng.hs.office.scenarios.partner.DeletePartner;
|
import net.hostsharing.hsadminng.hs.office.scenarios.partner.DeletePartner;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.person.ShouldUpdatePersonData;
|
import net.hostsharing.hsadminng.hs.office.scenarios.person.ShouldUpdatePersonData;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.RemoveOperationsContactFromPartner;
|
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.RemoveOperationsContactFromPartner;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.SubscribeToMailinglist;
|
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.SubscribeExistingPersonAndContactToMailinglist;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.SubscribeNewPersonAndContactToMailinglist;
|
||||||
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.UnsubscribeFromMailinglist;
|
import net.hostsharing.hsadminng.hs.office.scenarios.subscription.UnsubscribeFromMailinglist;
|
||||||
import net.hostsharing.hsadminng.hs.scenarios.Produces;
|
import net.hostsharing.hsadminng.hs.scenarios.Produces;
|
||||||
import net.hostsharing.hsadminng.hs.scenarios.Requires;
|
import net.hostsharing.hsadminng.hs.scenarios.Requires;
|
||||||
@ -564,7 +565,7 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
@Requires("Person: Test AG")
|
@Requires("Person: Test AG")
|
||||||
@Produces("Subscription: Michael Miller to operations-announce")
|
@Produces("Subscription: Michael Miller to operations-announce")
|
||||||
void shouldSubscribeNewPersonAndContactToMailinglist() {
|
void shouldSubscribeNewPersonAndContactToMailinglist() {
|
||||||
new SubscribeToMailinglist(scenarioTest)
|
new SubscribeNewPersonAndContactToMailinglist(scenarioTest)
|
||||||
// TODO.spec: do we need the personType? or is an operational contact always a natural person? what about distribution lists?
|
// TODO.spec: do we need the personType? or is an operational contact always a natural person? what about distribution lists?
|
||||||
.given("partnerPersonTradeName", "Test AG")
|
.given("partnerPersonTradeName", "Test AG")
|
||||||
.given("subscriberFamilyName", "Miller")
|
.given("subscriberFamilyName", "Miller")
|
||||||
@ -578,7 +579,22 @@ class HsOfficeScenarioTests extends ScenarioTest {
|
|||||||
@Test
|
@Test
|
||||||
@Order(5001)
|
@Order(5001)
|
||||||
@Requires("Subscription: Michael Miller to operations-announce")
|
@Requires("Subscription: Michael Miller to operations-announce")
|
||||||
void shouldUnsubscribeNewPersonAndContactToMailinglist() {
|
@Produces("Subscription: Michael Miller to operations-discussion")
|
||||||
|
void shouldSubscribeExistingPersonAndContactToMailinglist() {
|
||||||
|
new SubscribeExistingPersonAndContactToMailinglist(scenarioTest)
|
||||||
|
.given("partnerPersonTradeName", "Test AG")
|
||||||
|
.given("subscriberFamilyName", "Miller")
|
||||||
|
.given("subscriberGivenName", "Michael")
|
||||||
|
.given("subscriberEMailAddress", "michael.miller@example.org")
|
||||||
|
.given("mailingList", "operations-discussion")
|
||||||
|
.doRun()
|
||||||
|
.keep();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(5002)
|
||||||
|
@Requires("Subscription: Michael Miller to operations-announce")
|
||||||
|
void shouldUnsubscribePersonAndContactFromMailinglist() {
|
||||||
new UnsubscribeFromMailinglist(scenarioTest)
|
new UnsubscribeFromMailinglist(scenarioTest)
|
||||||
.given("mailingList", "operations-announce")
|
.given("mailingList", "operations-announce")
|
||||||
.given("subscriberEMailAddress", "michael.miller@example.org")
|
.given("subscriberEMailAddress", "michael.miller@example.org")
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.subscription;
|
||||||
|
|
||||||
|
import io.restassured.http.ContentType;
|
||||||
|
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||||
|
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class SubscribeExistingPersonAndContactToMailinglist extends UseCase<SubscribeExistingPersonAndContactToMailinglist> {
|
||||||
|
|
||||||
|
public SubscribeExistingPersonAndContactToMailinglist(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||||
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
obtain(
|
||||||
|
"Person: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
||||||
|
httpGet("/api/hs/office/persons?name=%{subscriberFamilyName}")
|
||||||
|
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"In real scenarios there are most likely multiple results and you have to choose the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
obtain("Contact: %{subscriberEMailAddress}", () ->
|
||||||
|
httpGet("/api/hs/office/contacts?emailAddress=%{subscriberEMailAddress}")
|
||||||
|
.expecting(HttpStatus.OK).expecting(ContentType.JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"In real scenarios there are most likely multiple results and you have to choose the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"type": "SUBSCRIBER",
|
||||||
|
"mark": ${mailingList},
|
||||||
|
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
||||||
|
"holder.uuid": ${Person: %{subscriberGivenName} %{subscriberFamilyName}},
|
||||||
|
"contact.uuid": ${Contact: %{subscriberEMailAddress}}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(CREATED).expecting(JSON);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package net.hostsharing.hsadminng.hs.office.scenarios.subscription;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
||||||
|
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
||||||
|
|
||||||
|
import static io.restassured.http.ContentType.JSON;
|
||||||
|
import static org.springframework.http.HttpStatus.CREATED;
|
||||||
|
import static org.springframework.http.HttpStatus.OK;
|
||||||
|
|
||||||
|
public class SubscribeNewPersonAndContactToMailinglist extends UseCase<SubscribeNewPersonAndContactToMailinglist> {
|
||||||
|
|
||||||
|
public SubscribeNewPersonAndContactToMailinglist(final ScenarioTest testSuite) {
|
||||||
|
super(testSuite);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected HttpResponse run() {
|
||||||
|
|
||||||
|
obtain("Person: %{partnerPersonTradeName}", () ->
|
||||||
|
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
||||||
|
.expecting(OK).expecting(JSON),
|
||||||
|
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
||||||
|
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
||||||
|
);
|
||||||
|
|
||||||
|
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
||||||
|
{
|
||||||
|
"type": "SUBSCRIBER",
|
||||||
|
"mark": ${mailingList},
|
||||||
|
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
||||||
|
"holder": {
|
||||||
|
"personType": "NATURAL_PERSON",
|
||||||
|
"familyName": ${subscriberFamilyName},
|
||||||
|
"givenName": ${subscriberGivenName}
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"caption": "%{subscriberGivenName} %{subscriberFamilyName}",
|
||||||
|
"emailAddresses": {
|
||||||
|
"main": ${subscriberEMailAddress}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""))
|
||||||
|
.expecting(CREATED).expecting(JSON);
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +0,0 @@
|
|||||||
package net.hostsharing.hsadminng.hs.office.scenarios.subscription;
|
|
||||||
|
|
||||||
import io.restassured.http.ContentType;
|
|
||||||
import net.hostsharing.hsadminng.hs.scenarios.UseCase;
|
|
||||||
import net.hostsharing.hsadminng.hs.scenarios.ScenarioTest;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
|
|
||||||
import static io.restassured.http.ContentType.JSON;
|
|
||||||
import static org.springframework.http.HttpStatus.CREATED;
|
|
||||||
import static org.springframework.http.HttpStatus.OK;
|
|
||||||
|
|
||||||
public class SubscribeToMailinglist extends UseCase<SubscribeToMailinglist> {
|
|
||||||
|
|
||||||
public SubscribeToMailinglist(final ScenarioTest testSuite) {
|
|
||||||
super(testSuite);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected HttpResponse run() {
|
|
||||||
|
|
||||||
obtain("Person: %{partnerPersonTradeName}", () ->
|
|
||||||
httpGet("/api/hs/office/persons?name=" + uriEncoded("%{partnerPersonTradeName}"))
|
|
||||||
.expecting(OK).expecting(JSON),
|
|
||||||
response -> response.expectArrayElements(1).getFromBody("[0].uuid"),
|
|
||||||
"In production, data this query could result in multiple outputs. In that case, you have to find out which is the right one."
|
|
||||||
);
|
|
||||||
|
|
||||||
obtain("Person: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
|
||||||
httpPost("/api/hs/office/persons", usingJsonBody("""
|
|
||||||
{
|
|
||||||
"personType": "NATURAL_PERSON",
|
|
||||||
"familyName": ${subscriberFamilyName},
|
|
||||||
"givenName": ${subscriberGivenName}
|
|
||||||
}
|
|
||||||
"""))
|
|
||||||
.expecting(HttpStatus.CREATED).expecting(ContentType.JSON)
|
|
||||||
);
|
|
||||||
|
|
||||||
obtain("Contact: %{subscriberGivenName} %{subscriberFamilyName}", () ->
|
|
||||||
httpPost("/api/hs/office/contacts", usingJsonBody("""
|
|
||||||
{
|
|
||||||
"caption": "%{subscriberGivenName} %{subscriberFamilyName}",
|
|
||||||
"emailAddresses": {
|
|
||||||
"main": ${subscriberEMailAddress}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"""))
|
|
||||||
.expecting(CREATED).expecting(JSON)
|
|
||||||
);
|
|
||||||
|
|
||||||
return httpPost("/api/hs/office/relations", usingJsonBody("""
|
|
||||||
{
|
|
||||||
"type": "SUBSCRIBER",
|
|
||||||
"mark": ${mailingList},
|
|
||||||
"anchor.uuid": ${Person: %{partnerPersonTradeName}},
|
|
||||||
"holder.uuid": ${Person: %{subscriberGivenName} %{subscriberFamilyName}},
|
|
||||||
"contact.uuid": ${Contact: %{subscriberGivenName} %{subscriberFamilyName}}
|
|
||||||
}
|
|
||||||
"""))
|
|
||||||
.expecting(CREATED).expecting(JSON);
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user