hs.admin.partner from API via Controller to Entity
22 files added
5 files modified
| | |
| | | showWarnings true |
| | | openApiNullable true |
| | | } |
| | | springHs { |
| | | processorName 'spring' |
| | | processor 'io.openapiprocessor:openapi-processor-spring:2022.4' |
| | | apiPath "$projectDir/src/main/resources/api-definition/hs-admin/hs-admin.yaml" |
| | | mapping "$projectDir/src/main/resources/api-definition/hs-admin/api-mappings.yaml" |
| | | targetDir "$projectDir/build/generated/sources/openapi" |
| | | showWarnings true |
| | | openApiNullable true |
| | | } |
| | | } |
| | | sourceSets.main.java.srcDir 'build/generated/sources/openapi' |
| | | ['processSpringRoot', 'processSpringRbac', 'processSpringTest'].each { |
| | | project.tasks.processResources.dependsOn it |
| | | project.tasks.compileJava.dependsOn it |
| | | abstract class ProcessSpring extends DefaultTask {} |
| | | tasks.register('processSpring', ProcessSpring) |
| | | ['processSpringRoot', 'processSpringRbac', 'processSpringTest', 'processSpringHs'].each { |
| | | project.tasks.processSpring.dependsOn it |
| | | } |
| | | project.tasks.processResources.dependsOn processSpring |
| | | project.tasks.compileJava.dependsOn processSpring |
| | | |
| | | // Spotless Code Formatting |
| | | spotless { |
| | |
| | | targetClasses = ['net.hostsharing.hsadminng.**'] |
| | | excludedClasses = [ |
| | | 'net.hostsharing.hsadminng.config.**', |
| | | 'net.hostsharing.hsadminng.**.*Controller', |
| | | 'net.hostsharing.hsadminng.**.generated.**' |
| | | ] |
| | | |
| | |
| | | threads = 4 |
| | | |
| | | // As Java unit tests are pretty pointless in our case, this maybe makes not much sense. |
| | | mutationThreshold = 31 |
| | | coverageThreshold = 44 |
| | | testStrengthThreshold = 76 |
| | | mutationThreshold = 71 |
| | | coverageThreshold = 57 |
| | | testStrengthThreshold = 99 |
| | | |
| | | outputFormats = ['XML', 'HTML'] |
| | | timestampedReports = false |
| | |
| | | package net.hostsharing.hsadminng; |
| | | |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.model.HsAdminPersonResource; |
| | | import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; |
| | | import org.modelmapper.Converter; |
| | | import org.modelmapper.ModelMapper; |
| | | import org.modelmapper.spi.MappingContext; |
| | | |
| | | import java.util.List; |
| | | import java.util.function.BiConsumer; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * A nicer API for ModelMapper. |
| | | */ |
| | | public abstract class Mapper { |
| | | private final static ModelMapper modelMapper = new ModelMapper(); |
| | | |
| | | public final static ModelMapper modelMapper = new ModelMapper(); |
| | | |
| | | public static <S, T> List<T> mapList(final List<S> source, final Class<T> targetClass) { |
| | | return mapList(source, targetClass, null); |
| | | } |
| | | |
| | | public static <S, T> List<T> mapList(final List<S> source, final Class<T> targetClass, final BiConsumer<S, T> postMapper) { |
| | | return source |
| | | .stream() |
| | | .map(element -> modelMapper.map(element, targetClass)) |
| | | .collect(Collectors.toList()); |
| | | .stream() |
| | | .map(element -> { |
| | | final var target = map(element, targetClass); |
| | | if (postMapper != null) { |
| | | postMapper.accept(element, target); |
| | | } |
| | | return target; |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | } |
| | | |
| | | public static <S, T> T map(final S source, final Class<T> targetClass) { |
| | | return modelMapper.map(source, targetClass); |
| | | return map(source, targetClass, null); |
| | | } |
| | | |
| | | public static <S, T> T map(final S source, final Class<T> targetClass, final BiConsumer<S, T> postMapper) { |
| | | final var target = modelMapper.map(source, targetClass); |
| | | if (postMapper != null) { |
| | | postMapper.accept(source, target); |
| | | } |
| | | return target; |
| | | } |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.contact; |
| | | |
| | | import com.vladmihalcea.hibernate.type.array.ListArrayType; |
| | | import lombok.*; |
| | | import org.hibernate.annotations.TypeDef; |
| | | |
| | | import javax.persistence.Column; |
| | | import javax.persistence.Entity; |
| | | import javax.persistence.Id; |
| | | import java.util.UUID; |
| | | |
| | | @Entity |
| | | @Getter |
| | | @Setter |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class HsAdminContactEntity { |
| | | |
| | | private @Id UUID uuid; |
| | | private String label; |
| | | |
| | | @Column(name = "postaladdress") |
| | | private String postalAddress; |
| | | |
| | | @Column(name = "emailaddresses", columnDefinition = "json") |
| | | private String emailAddresses; |
| | | |
| | | @Column(name = "phonenumbers", columnDefinition = "json") |
| | | private String phoneNumbers; |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.contact; |
| | | |
| | | import org.springframework.data.jpa.repository.Query; |
| | | import org.springframework.data.repository.Repository; |
| | | |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | |
| | | public interface HsAdminContactRepository extends Repository<HsAdminContactEntity, UUID> { |
| | | |
| | | Optional<HsAdminContactEntity> findByUuid(UUID id); |
| | | |
| | | @Query(""" |
| | | SELECT c FROM HsAdminContactEntity c |
| | | WHERE :label is null |
| | | OR c.label like concat(:label, '%') |
| | | """) |
| | | // TODO: join tables missing |
| | | List<HsAdminContactEntity> findContactByOptionalLabelLike(String label); |
| | | |
| | | HsAdminContactEntity save(final HsAdminContactEntity entity); |
| | | |
| | | long count(); |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import net.hostsharing.hsadminng.Mapper; |
| | | import net.hostsharing.hsadminng.context.Context; |
| | | import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactEntity; |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.api.HsAdminPartnersApi; |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.model.HsAdminContactResource; |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.model.HsAdminPartnerResource; |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.model.HsAdminPartnerUpdateResource; |
| | | import net.hostsharing.hsadminng.hs.admin.generated.api.v1.model.HsAdminPersonResource; |
| | | import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; |
| | | |
| | | import java.util.List; |
| | | import java.util.UUID; |
| | | import java.util.function.BiConsumer; |
| | | |
| | | import static net.hostsharing.hsadminng.Mapper.map; |
| | | |
| | | @RestController |
| | | |
| | | public class HsAdminPartnerController implements HsAdminPartnersApi { |
| | | |
| | | @Autowired |
| | | private Context context; |
| | | |
| | | @Autowired |
| | | private HsAdminPartnerRepository partnerRepo; |
| | | |
| | | @Override |
| | | @Transactional(readOnly = true) |
| | | public ResponseEntity<List<HsAdminPartnerResource>> listPartners( |
| | | final String currentUser, |
| | | final String assumedRoles, |
| | | final String name) { |
| | | // TODO: context.define(currentUser, assumedRoles); |
| | | |
| | | // TODO: final var entities = partnerRepo.findPartnerByOptionalNameLike(name); |
| | | |
| | | final var entities = List.of( |
| | | HsAdminPartnerEntity.builder() |
| | | .uuid(UUID.randomUUID()) |
| | | .person(HsAdminPersonEntity.builder() |
| | | .tradeName("Ixx AG") |
| | | .build()) |
| | | .contact(HsAdminContactEntity.builder() |
| | | .label("Ixx AG") |
| | | .build()) |
| | | .build(), |
| | | HsAdminPartnerEntity.builder() |
| | | .uuid(UUID.randomUUID()) |
| | | .person(HsAdminPersonEntity.builder() |
| | | .tradeName("Ypsilon GmbH") |
| | | .build()) |
| | | .contact(HsAdminContactEntity.builder() |
| | | .label("Ypsilon GmbH") |
| | | .build()) |
| | | .build(), |
| | | HsAdminPartnerEntity.builder() |
| | | .uuid(UUID.randomUUID()) |
| | | .person(HsAdminPersonEntity.builder() |
| | | .tradeName("Zett OHG") |
| | | .build()) |
| | | .contact(HsAdminContactEntity.builder() |
| | | .label("Zett OHG") |
| | | .build()) |
| | | .build() |
| | | ); |
| | | |
| | | final var resources = Mapper.mapList(entities, HsAdminPartnerResource.class, |
| | | PARTNER_ENTITY_TO_RESOURCE_POSTMAPPER); |
| | | return ResponseEntity.ok(resources); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | public ResponseEntity<HsAdminPartnerResource> addPartner( |
| | | final String currentUser, |
| | | final String assumedRoles, |
| | | final HsAdminPartnerResource body) { |
| | | |
| | | // TODO: context.define(currentUser, assumedRoles); |
| | | |
| | | if (body.getUuid() == null) { |
| | | body.setUuid(UUID.randomUUID()); |
| | | } |
| | | |
| | | // TODO: final var saved = partnerRepo.save(map(body, HsAdminPartnerEntity.class)); |
| | | final var saved = map(body, HsAdminPartnerEntity.class, PARTNER_RESOURCE_TO_ENTITY_POSTMAPPER); |
| | | |
| | | final var uri = |
| | | MvcUriComponentsBuilder.fromController(getClass()) |
| | | .path("/api/hs/admin/partners/{id}") |
| | | .buildAndExpand(body.getUuid()) |
| | | .toUri(); |
| | | final var mapped = map(saved, HsAdminPartnerResource.class, |
| | | PARTNER_ENTITY_TO_RESOURCE_POSTMAPPER); |
| | | return ResponseEntity.created(uri).body(mapped); |
| | | } |
| | | |
| | | @Override |
| | | public ResponseEntity<HsAdminPartnerResource> getPartnerByUuid( |
| | | final String currentUser, |
| | | final String assumedRoles, |
| | | final UUID partnerUuid) { |
| | | |
| | | // TODO: context.define(currentUser, assumedRoles); |
| | | |
| | | // TODO: final var result = partnerRepo.findByUuid(partnerUuid); |
| | | final var result = |
| | | partnerUuid.equals(UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6")) ? null : |
| | | HsAdminPartnerEntity.builder() |
| | | .uuid(UUID.randomUUID()) |
| | | .person(HsAdminPersonEntity.builder() |
| | | .tradeName("Ixx AG") |
| | | .build()) |
| | | .contact(HsAdminContactEntity.builder() |
| | | .label("Ixx AG") |
| | | .build()) |
| | | .build(); |
| | | if (result == null) { |
| | | return ResponseEntity.notFound().build(); |
| | | } |
| | | return ResponseEntity.ok(map(result, HsAdminPartnerResource.class, PARTNER_ENTITY_TO_RESOURCE_POSTMAPPER)); |
| | | } |
| | | |
| | | @Override |
| | | public ResponseEntity<Void> deletePartnerByUuid(final String currentUser, final String assumedRoles, final UUID userUuid) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public ResponseEntity<HsAdminPartnerResource> updatePartner( |
| | | final String currentUser, |
| | | final String assumedRoles, |
| | | final UUID partnerUuid, |
| | | final HsAdminPartnerUpdateResource body) { |
| | | return null; |
| | | } |
| | | |
| | | private final BiConsumer<HsAdminPartnerResource, HsAdminPartnerEntity> PARTNER_RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { |
| | | entity.setPerson(map(resource.getPerson(), HsAdminPersonEntity.class)); |
| | | entity.setContact(map(resource.getContact(), HsAdminContactEntity.class)); |
| | | }; |
| | | |
| | | private final BiConsumer<HsAdminPartnerEntity, HsAdminPartnerResource> PARTNER_ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) -> { |
| | | resource.setPerson(map(entity.getPerson(), HsAdminPersonResource.class)); |
| | | resource.setContact(map(entity.getContact(), HsAdminContactResource.class)); |
| | | }; |
| | | |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import lombok.*; |
| | | import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactEntity; |
| | | import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; |
| | | |
| | | import javax.persistence.*; |
| | | import java.time.LocalDate; |
| | | import java.util.UUID; |
| | | |
| | | @Entity |
| | | @Table(name = "hs_admin_partner_rv") |
| | | @Getter |
| | | @Setter |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class HsAdminPartnerEntity { |
| | | |
| | | private @Id UUID uuid; |
| | | |
| | | @ManyToOne |
| | | @JoinColumn(name = "personuuid") |
| | | private HsAdminPersonEntity person; |
| | | |
| | | @ManyToOne |
| | | @JoinColumn(name = "contactuuid") |
| | | private HsAdminContactEntity contact; |
| | | |
| | | private @Column(name = "registrationoffice") String registrationOffice; |
| | | private @Column(name = "registrationnumber") String registrationNumber; |
| | | private @Column(name = "birthname") String birthName; |
| | | private @Column(name = "birthday") LocalDate birthday; |
| | | private @Column(name = "dateofdeath") LocalDate dateOfDeath; |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import org.springframework.data.jpa.repository.Query; |
| | | import org.springframework.data.repository.Repository; |
| | | |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | |
| | | public interface HsAdminPartnerRepository extends Repository<HsAdminPartnerEntity, UUID> { |
| | | |
| | | Optional<HsAdminPartnerEntity> findByUuid(UUID id); |
| | | |
| | | @Query(""" |
| | | SELECT partner FROM HsAdminPartnerEntity partner |
| | | JOIN HsAdminContactEntity contact ON contact.uuid = partner.contact |
| | | JOIN HsAdminPersonEntity person ON person.uuid = partner.person |
| | | WHERE :name is null |
| | | OR partner.birthName like concat(:name, '%') |
| | | OR contact.label like concat(:name, '%') |
| | | OR person.tradeName like concat(:name, '%') |
| | | OR person.givenName like concat(:name, '%') |
| | | OR person.familyName like concat(:name, '%') |
| | | """) |
| | | List<HsAdminPartnerEntity> findPartnerByOptionalNameLike(String name); |
| | | |
| | | HsAdminPartnerEntity save(final HsAdminPartnerEntity entity); |
| | | |
| | | long count(); |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.person; |
| | | |
| | | import com.vladmihalcea.hibernate.type.array.ListArrayType; |
| | | import lombok.*; |
| | | import org.hibernate.annotations.TypeDef; |
| | | |
| | | import javax.persistence.*; |
| | | import java.util.UUID; |
| | | |
| | | @Entity |
| | | @Table(name = "hs_admin_person_rv") |
| | | @TypeDef( |
| | | name = "list-array", |
| | | typeClass = ListArrayType.class |
| | | ) |
| | | @Getter |
| | | @Setter |
| | | @Builder |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class HsAdminPersonEntity { |
| | | |
| | | private @Id UUID uuid; |
| | | |
| | | @Enumerated(EnumType.STRING) |
| | | private PersonType type; |
| | | |
| | | private String tradeName; |
| | | |
| | | @Column(name = "givenname") |
| | | private String givenName; |
| | | |
| | | @Column(name = "familyname") |
| | | private String familyName; |
| | | |
| | | public enum PersonType { |
| | | NATURAL, |
| | | LEGAL, |
| | | SOLE_REPRESENTATION, |
| | | JOINT_REPRESENTATION |
| | | } |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.person; |
| | | |
| | | import org.springframework.data.jpa.repository.Query; |
| | | import org.springframework.data.repository.Repository; |
| | | |
| | | import java.util.List; |
| | | import java.util.Optional; |
| | | import java.util.UUID; |
| | | |
| | | public interface HsAdminPersonRepository extends Repository<HsAdminPersonEntity, UUID> { |
| | | |
| | | Optional<HsAdminPersonEntity> findByUuid(UUID id); |
| | | |
| | | @Query(""" |
| | | SELECT p FROM HsAdminPersonEntity p |
| | | WHERE :name is null |
| | | OR p.tradeName like concat(:name, '%') |
| | | OR p.givenName like concat(:name, '%') |
| | | OR p.familyName like concat(:name, '%') |
| | | """) |
| | | List<HsAdminPersonEntity> findPersonByOptionalNameLike(String name); |
| | | |
| | | HsAdminPersonEntity save(final HsAdminPersonEntity entity); |
| | | |
| | | long count(); |
| | | } |
New file |
| | |
| | | openapi-processor-mapping: v2 |
| | | |
| | | options: |
| | | package-name: net.hostsharing.hsadminng.hs.admin.generated.api.v1 |
| | | model-name-suffix: Resource |
| | | |
| | | map: |
| | | result: org.springframework.http.ResponseEntity |
| | | |
| | | types: |
| | | - type: array => java.util.List |
| | | - type: string:uuid => java.util.UUID |
| | | |
| | | paths: |
| | | /api/hs/admin/partners/{packageUUID}: |
| | | null: org.openapitools.jackson.nullable.JsonNullable |
New file |
| | |
| | | ../error-responses.yaml |
New file |
| | |
| | | |
| | | components: |
| | | |
| | | schemas: |
| | | |
| | | HsAdminContactBase: |
| | | type: object |
| | | properties: |
| | | label: |
| | | type: string |
| | | postalAddress: |
| | | type: string |
| | | emailAddresses: |
| | | type: string |
| | | phoneNumbers: |
| | | type: string |
| | | |
| | | HsAdminContact: |
| | | allOf: |
| | | - type: object |
| | | properties: |
| | | uuid: |
| | | type: string |
| | | format: uuid |
| | | - $ref: '#/components/schemas/HsAdminContactBase' |
| | | |
| | | HsAdminContactUpdate: |
| | | $ref: '#/components/schemas/HsAdminContactBase' |
New file |
| | |
| | | |
| | | components: |
| | | |
| | | schemas: |
| | | |
| | | HsAdminPartnerBase: |
| | | type: object |
| | | properties: |
| | | registrationOffice: |
| | | type: string |
| | | registrationNumber: |
| | | type: string |
| | | birthName: |
| | | type: string |
| | | birthday: |
| | | type: string |
| | | format: date |
| | | dateOfDeath: |
| | | type: string |
| | | format: date |
| | | |
| | | HsAdminPartner: |
| | | allOf: |
| | | - type: object |
| | | properties: |
| | | uuid: |
| | | type: string |
| | | format: uuid |
| | | person: |
| | | $ref: './hs-admin-person-schemas.yaml#/components/schemas/HsAdminPerson' |
| | | contact: |
| | | $ref: './hs-admin-contact-schemas.yaml#/components/schemas/HsAdminContact' |
| | | - $ref: '#/components/schemas/HsAdminPartnerBase' |
| | | |
| | | HsAdminPartnerUpdate: |
| | | allOf: |
| | | - type: object |
| | | properties: |
| | | personUuid: |
| | | type: string |
| | | format: uuid |
| | | contactUuid: |
| | | type: string |
| | | format: uuid |
| | | - $ref: '#/components/schemas/HsAdminPartnerBase' |
New file |
| | |
| | | get: |
| | | tags: |
| | | - hs-admin-partners |
| | | description: 'Fetch a single business partner by its uuid, if visible for the current subject.' |
| | | operationId: getPartnerByUuid |
| | | parameters: |
| | | - $ref: './auth.yaml#/components/parameters/currentUser' |
| | | - $ref: './auth.yaml#/components/parameters/assumedRoles' |
| | | - name: partnerUUID |
| | | in: path |
| | | required: true |
| | | schema: |
| | | type: string |
| | | format: uuid |
| | | responses: |
| | | "200": |
| | | description: OK |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartner' |
| | | |
| | | "401": |
| | | $ref: './error-responses.yaml#/components/responses/Unauthorized' |
| | | "403": |
| | | $ref: './error-responses.yaml#/components/responses/Forbidden' |
| | | |
| | | patch: |
| | | tags: |
| | | - hs-admin-partners |
| | | operationId: updatePartner |
| | | parameters: |
| | | - $ref: './auth.yaml#/components/parameters/currentUser' |
| | | - $ref: './auth.yaml#/components/parameters/assumedRoles' |
| | | - name: partnerUUID |
| | | in: path |
| | | required: true |
| | | schema: |
| | | type: string |
| | | format: uuid |
| | | requestBody: |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartnerUpdate' |
| | | responses: |
| | | "200": |
| | | description: OK |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartner' |
| | | "401": |
| | | $ref: './error-responses.yaml#/components/responses/Unauthorized' |
| | | "403": |
| | | $ref: './error-responses.yaml#/components/responses/Forbidden' |
| | | |
| | | |
| | | delete: |
| | | tags: |
| | | - hs-admin-partners |
| | | operationId: deletePartnerByUuid |
| | | parameters: |
| | | - $ref: './auth.yaml#/components/parameters/currentUser' |
| | | - $ref: './auth.yaml#/components/parameters/assumedRoles' |
| | | - name: userUuid |
| | | in: path |
| | | required: true |
| | | schema: |
| | | type: string |
| | | format: uuid |
| | | description: UUID of the user to delete. |
| | | responses: |
| | | "204": |
| | | description: No Content |
| | | "401": |
| | | $ref: './error-responses.yaml#/components/responses/Unauthorized' |
| | | "403": |
| | | $ref: './error-responses.yaml#/components/responses/Forbidden' |
| | | "404": |
| | | $ref: './error-responses.yaml#/components/responses/NotFound' |
New file |
| | |
| | | get: |
| | | summary: Returns a list of (optionally filtered) business partners. |
| | | description: Returns the list of (optionally filtered) business partners which are visible to the current user or any of it's assumed roles. |
| | | tags: |
| | | - hs-admin-partners |
| | | operationId: listPartners |
| | | parameters: |
| | | - $ref: './auth.yaml#/components/parameters/currentUser' |
| | | - $ref: './auth.yaml#/components/parameters/assumedRoles' |
| | | - name: name |
| | | in: query |
| | | required: false |
| | | schema: |
| | | type: string |
| | | description: Customer-prefix to filter the results. TODO |
| | | responses: |
| | | "200": |
| | | description: OK |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | type: array |
| | | items: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartner' |
| | | "401": |
| | | $ref: './error-responses.yaml#/components/responses/Unauthorized' |
| | | "403": |
| | | $ref: './error-responses.yaml#/components/responses/Forbidden' |
| | | |
| | | post: |
| | | summary: Adds a new business partner. |
| | | tags: |
| | | - hs-admin-partners |
| | | operationId: addPartner |
| | | parameters: |
| | | - $ref: './auth.yaml#/components/parameters/currentUser' |
| | | - $ref: './auth.yaml#/components/parameters/assumedRoles' |
| | | requestBody: |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartner' |
| | | required: true |
| | | responses: |
| | | "201": |
| | | description: Created |
| | | content: |
| | | 'application/json': |
| | | schema: |
| | | $ref: './hs-admin-partner-schemas.yaml#/components/schemas/HsAdminPartner' |
| | | "401": |
| | | $ref: './error-responses.yaml#/components/responses/Unauthorized' |
| | | "403": |
| | | $ref: './error-responses.yaml#/components/responses/Forbidden' |
| | | "409": |
| | | $ref: './error-responses.yaml#/components/responses/Conflict' |
New file |
| | |
| | | |
| | | components: |
| | | |
| | | schemas: |
| | | |
| | | HsAdminPersonBase: |
| | | type: object |
| | | properties: |
| | | personType: |
| | | type: string |
| | | enum: |
| | | - NATURAL # a human |
| | | - LEGAL # e.g. Corp., Inc., AG, GmbH, eG |
| | | - SOLE_REPRESENTATION # e.g. OHG, GbR |
| | | - JOINT_REPRESENTATION # e.g. community of heirs |
| | | tradeName: |
| | | type: string |
| | | givenName: |
| | | type: string |
| | | familyName: |
| | | type: string |
| | | |
| | | HsAdminPerson: |
| | | allOf: |
| | | - type: object |
| | | properties: |
| | | uuid: |
| | | type: string |
| | | format: uuid |
| | | - $ref: '#/components/schemas/HsAdminPersonBase' |
| | | |
| | | HsAdminPersonUpdate: |
| | | $ref: '#/components/schemas/HsAdminPersonBase' |
New file |
| | |
| | | openapi: 3.0.1 |
| | | info: |
| | | title: Hostsharing hsadmin-ng API |
| | | version: v0 |
| | | servers: |
| | | - url: http://localhost:8080 |
| | | description: Local development default URL. |
| | | |
| | | paths: |
| | | |
| | | /api/hs/admin/partners: |
| | | $ref: "./hs-admin-partners.yaml" |
| | | |
| | | /api/hs/admin/partners/{partnerUUID}: |
| | | $ref: "./hs-admin-partners-with-uuid.yaml" |
| | | |
New file |
| | |
| | | --liquibase formatted sql |
| | | |
| | | -- ============================================================================ |
| | | --changeset hs-base-GLOBAL-OBJECT:1 endDelimiter:--// |
| | | -- ---------------------------------------------------------------------------- |
| | | |
| | | /** |
| | | A single row to be referenced as a global object. |
| | | */ |
| | | begin transaction; |
| | | call defineContext('initializing table "global"', null, null, null); |
| | | insert |
| | | into RbacObject (objecttable) values ('global'); |
| | | insert |
| | | into Global (uuid, name) values ((select uuid from RbacObject where objectTable = 'global'), 'hostsharing'); |
| | | commit; |
| | | --// |
| | | |
| | | |
| | | -- ============================================================================ |
| | | --changeset hs-base-ADMIN-ROLE:1 endDelimiter:--// |
| | | -- ---------------------------------------------------------------------------- |
| | | /* |
| | | A global administrator role. |
| | | */ |
| | | create or replace function hsHostsharingAdmin() |
| | | returns RbacRoleDescriptor |
| | | returns null on null input |
| | | stable leakproof |
| | | language sql as $$ |
| | | select 'global', (select uuid from RbacObject where objectTable = 'global'), 'admin'::RbacRoleType; |
| | | $$; |
| | | |
| | | begin transaction; |
| | | call defineContext('creating Hostsharing admin role', null, null, null); |
| | | select createRole(hsHostsharingAdmin()); |
| | | commit; |
| | | |
| | | -- ============================================================================ |
| | | --changeset hs-base-ADMIN-USERS:1 context:dev,tc endDelimiter:--// |
| | | -- ---------------------------------------------------------------------------- |
| | | /* |
| | | Create two users and assign both to the administrators role. |
| | | */ |
| | | do language plpgsql $$ |
| | | declare |
| | | admins uuid ; |
| | | begin |
| | | call defineContext('creating fake Hostsharing admin users', null, null, null); |
| | | |
| | | admins = findRoleId(hsHostsharingAdmin()); |
| | | call grantRoleToUserUnchecked(admins, admins, createRbacUser('mike@hostsharing.net')); |
| | | call grantRoleToUserUnchecked(admins, admins, createRbacUser('sven@hostsharing.net')); |
| | | end; |
| | | $$; |
| | | --// |
| | | |
| | | |
| | | -- ============================================================================ |
| | | --changeset hs-base-hostsharing-TEST:1 context:dev,tc runAlways:true endDelimiter:--// |
| | | -- ---------------------------------------------------------------------------- |
| | | |
| | | /* |
| | | Tests if currentUserUuid() can fetch the user from the session variable. |
| | | */ |
| | | |
| | | do language plpgsql $$ |
| | | declare |
| | | userName varchar; |
| | | begin |
| | | call defineContext('testing currentUserUuid', null, 'sven@hostsharing.net', null); |
| | | select userName from RbacUser where uuid = currentUserUuid() into userName; |
| | | if userName <> 'sven@hostsharing.net' then |
| | | raise exception 'setting or fetching initial currentUser failed, got: %', userName; |
| | | end if; |
| | | |
| | | call defineContext('testing currentUserUuid', null, 'mike@hostsharing.net', null); |
| | | select userName from RbacUser where uuid = currentUserUuid() into userName; |
| | | if userName = 'mike@ehostsharing.net' then |
| | | raise exception 'currentUser should not change in one transaction, but did change, got: %', userName; |
| | | end if; |
| | | end; $$; |
| | | --// |
| | |
| | | |
| | | @com.tngtech.archunit.junit.ArchTest |
| | | @SuppressWarnings("unused") |
| | | public static final ArchRule hsPackagesRule = classes() |
| | | public static final ArchRule testPackagesRule = classes() |
| | | .that().resideInAPackage("..test.(*)..") |
| | | .should().onlyBeAccessed().byClassesThat() |
| | | .resideInAnyPackage("..test.(*).."); |
| | | |
| | | @com.tngtech.archunit.junit.ArchTest |
| | | @SuppressWarnings("unused") |
| | | public static final ArchRule hsPackagePackageRule = classes() |
| | | public static final ArchRule testPackagePackageRule = classes() |
| | | .that().resideInAPackage("..test.pac..") |
| | | .should().onlyBeAccessed().byClassesThat() |
| | | .resideInAnyPackage("..test.pac.."); |
| | | |
| | | @com.tngtech.archunit.junit.ArchTest |
| | | @SuppressWarnings("unused") |
| | | public static final ArchRule hsAdminPackagesRule = classes() |
| | | .that().resideInAPackage("..hs.admin.(*)..") |
| | | .should().onlyBeAccessed().byClassesThat() |
| | | .resideInAnyPackage("..hs.admin.(*).."); |
| | | |
| | | @com.tngtech.archunit.junit.ArchTest |
| | | @SuppressWarnings("unused") |
| | | public static final ArchRule hsAdminPartnerPackageRule = classes() |
| | | .that().resideInAPackage("..hs.admin.partner..") |
| | | .should().onlyBeAccessed().byClassesThat() |
| | | .resideInAnyPackage("..hs.admin.partner.."); |
| | | |
| | | @com.tngtech.archunit.junit.ArchTest |
| | | @SuppressWarnings("unused") |
| | | public static final ArchRule acceptsAnnotationOnMethodsRule = methods() |
| | | .that().areAnnotatedWith(Accepts.class) |
| | | .should().beDeclaredInClassesThat().haveSimpleNameEndingWith("AcceptanceTest") |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.contact; |
| | | |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.security.NoSuchAlgorithmException; |
| | | |
| | | class HsAdminContactRepositoryIntegrationTest { |
| | | |
| | | @Test |
| | | void test() throws UnsupportedEncodingException, NoSuchAlgorithmException { |
| | | |
| | | } |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import io.restassured.RestAssured; |
| | | import io.restassured.http.ContentType; |
| | | import net.hostsharing.hsadminng.Accepts; |
| | | import net.hostsharing.hsadminng.HsadminNgApplication; |
| | | import net.hostsharing.hsadminng.context.Context; |
| | | import org.junit.jupiter.api.Nested; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.context.SpringBootTest; |
| | | import org.springframework.boot.test.web.server.LocalServerPort; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.util.UUID; |
| | | |
| | | import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; |
| | | import static net.hostsharing.test.JsonBuilder.jsonObject; |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | import static org.hamcrest.Matchers.*; |
| | | |
| | | @SpringBootTest( |
| | | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, |
| | | classes = HsadminNgApplication.class |
| | | ) |
| | | @Transactional |
| | | class HsAdminPartnerControllerAcceptanceTest { |
| | | |
| | | @LocalServerPort |
| | | private Integer port; |
| | | |
| | | @Autowired |
| | | Context context; |
| | | |
| | | @Autowired |
| | | Context contextMock; |
| | | @Autowired |
| | | HsAdminPartnerRepository partnerRepository; |
| | | |
| | | @Nested |
| | | @Accepts({ "Partner:F(Find)" }) |
| | | class ListPartners { |
| | | |
| | | @Test |
| | | void testHostsharingAdmin_withoutAssumedRoles_canViewAllPartners_ifNoCriteriaGiven() { |
| | | RestAssured // @formatter:off |
| | | .given() |
| | | .header("current-user", "mike@hostsharing.net") |
| | | .port(port) |
| | | .when() |
| | | .get("http://localhost/api/hs/admin/partners") |
| | | .then().assertThat() |
| | | .statusCode(200) |
| | | .contentType("application/json") |
| | | .body("[0].contact.label", is("Ixx AG")) |
| | | .body("[0].person.tradeName", is("Ixx AG")) |
| | | .body("[1].contact.label", is("Ypsilon GmbH")) |
| | | .body("[1].person.tradeName", is("Ypsilon GmbH")) |
| | | .body("[2].contact.label", is("Zett OHG")) |
| | | .body("[2].person.tradeName", is("Zett OHG")) |
| | | .body("size()", greaterThanOrEqualTo(3)); |
| | | // @formatter:on |
| | | } |
| | | } |
| | | |
| | | @Nested |
| | | @Accepts({ "Partner:C(Create)" }) |
| | | class AddPartner { |
| | | |
| | | private final static String NEW_PARTNER_JSON_WITHOUT_UUID = |
| | | """ |
| | | { |
| | | "person": { |
| | | "personType": "LEGAL", |
| | | "tradeName": "Test Corp.", |
| | | "givenName": null, |
| | | "familyName": null |
| | | }, |
| | | "contact": { |
| | | "label": "Test Corp.", |
| | | "postalAddress": "Test Corp.\\nTestweg 50\\n20001 Hamburg", |
| | | "emailAddresses": "office@example.com", |
| | | "phoneNumbers": "040 12345" |
| | | }, |
| | | "registrationOffice": "Registergericht Hamburg", |
| | | "registrationNumber": "123456", |
| | | "birthName": null, |
| | | "birthday": null, |
| | | "dateOfDeath": null |
| | | } |
| | | """; |
| | | |
| | | @Test |
| | | void hostsharingAdmin_withoutAssumedRole_canAddPartner_withExplicitUuid() { |
| | | |
| | | final var givenUUID = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"); |
| | | |
| | | final var location = RestAssured // @formatter:off |
| | | .given() |
| | | .header("current-user", "mike@hostsharing.net") |
| | | .contentType(ContentType.JSON) |
| | | .body(jsonObject(NEW_PARTNER_JSON_WITHOUT_UUID) |
| | | .with("uuid", givenUUID.toString()).toString()) |
| | | .port(port) |
| | | .when() |
| | | .post("http://localhost/api/hs/admin/partners") |
| | | .then().assertThat() |
| | | .statusCode(201) |
| | | .contentType(ContentType.JSON) |
| | | .body("uuid", is("3fa85f64-5717-4562-b3fc-2c963f66afa6")) |
| | | .body("registrationNumber", is("123456")) |
| | | .body("person.tradeName", is("Test Corp.")) |
| | | .header("Location", startsWith("http://localhost")) |
| | | .extract().header("Location"); // @formatter:on |
| | | |
| | | // finally, the new partner can be viewed by its own admin |
| | | final var newUserUuid = UUID.fromString( |
| | | location.substring(location.lastIndexOf('/') + 1)); |
| | | assertThat(newUserUuid).isEqualTo(givenUUID); |
| | | // TODO: context.define("partner-admin@ttt.example.com"); |
| | | // assertThat(partnerRepository.findByUuid(newUserUuid)) |
| | | // .hasValueSatisfying(c -> assertThat(c.getPerson().getTradeName()).isEqualTo("Test Corp.")); |
| | | } |
| | | |
| | | @Test |
| | | void hostsharingAdmin_withoutAssumedRole_canAddPartner_withGeneratedUuid() { |
| | | |
| | | final var location = RestAssured // @formatter:off |
| | | .given() |
| | | .header("current-user", "mike@hostsharing.net") |
| | | .contentType(ContentType.JSON) |
| | | .body(NEW_PARTNER_JSON_WITHOUT_UUID) |
| | | .port(port) |
| | | .when() |
| | | .post("http://localhost/api/hs/admin/partners") |
| | | .then().assertThat() |
| | | .statusCode(201) |
| | | .contentType(ContentType.JSON) |
| | | .body("uuid", isUuidValid()) |
| | | .body("registrationNumber", is("123456")) |
| | | .body("person.tradeName", is("Test Corp.")) |
| | | .header("Location", startsWith("http://localhost")) |
| | | .extract().header("Location"); // @formatter:on |
| | | |
| | | // finally, the new partner can be viewed by its own admin |
| | | final var newUserUuid = UUID.fromString( |
| | | location.substring(location.lastIndexOf('/') + 1)); |
| | | assertThat(newUserUuid).isNotNull(); |
| | | // TODO: context.define("partner-admin@ttt.example.com"); |
| | | // assertThat(partnerRepository.findByUuid(newUserUuid)) |
| | | // .hasValueSatisfying(c -> assertThat(c.getPerson().getTradeName()).isEqualTo("Test Corp.")); |
| | | } |
| | | } |
| | | |
| | | @Nested |
| | | @Accepts({ "Partner:R(Read)" }) |
| | | class GetPartner { |
| | | |
| | | @Test |
| | | void hostsharingAdmin_withoutAssumedRole_canGetArbitraryPartner() { |
| | | // TODO: final var givenPartnerUuid = partnerRepository.findPartnerByOptionalNameLike("Ixx").get(0).getUuid(); |
| | | final var givenPartnerUuid = UUID.randomUUID(); |
| | | |
| | | RestAssured // @formatter:off |
| | | .given() |
| | | .header("current-user", "mike@hostsharing.net") |
| | | .port(port) |
| | | .when() |
| | | .get("http://localhost/api/hs/admin/partners/" + givenPartnerUuid) |
| | | .then().log().body().assertThat() |
| | | .statusCode(200) |
| | | .contentType("application/json") |
| | | .body("person.tradeName", is("Ixx AG")) |
| | | .body("contact.label", is("Ixx AG")); |
| | | // @formatter:on |
| | | } |
| | | |
| | | @Test |
| | | @Accepts({ "Partner:X(Access Control)" }) |
| | | void normalUser_canNotGetUnrelatedPartner() { |
| | | // TODO: final var givenPartnerUuid = partnerRepository.findPartnerByOptionalNameLike("Ixx").get(0).getUuid(); |
| | | final UUID givenPartnerUuid = UUID.fromString("3fa85f64-5717-4562-b3fc-2c963f66afa6"); |
| | | |
| | | RestAssured // @formatter:off |
| | | .given() |
| | | .header("current-user", "somebody@example.org") |
| | | .port(port) |
| | | .when() |
| | | .get("http://localhost/api/hs/admin/partners/" + givenPartnerUuid) |
| | | .then().log().body().assertThat() |
| | | .statusCode(404); |
| | | // @formatter:on |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import net.hostsharing.hsadminng.context.Context; |
| | | import net.hostsharing.hsadminng.context.ContextBasedTest; |
| | | import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; |
| | | import org.junit.jupiter.api.Disabled; |
| | | import org.junit.jupiter.api.Nested; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; |
| | | import org.springframework.boot.test.mock.mockito.MockBean; |
| | | import org.springframework.context.annotation.ComponentScan; |
| | | import org.springframework.test.annotation.DirtiesContext; |
| | | |
| | | import javax.persistence.EntityManager; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.util.List; |
| | | |
| | | import static net.hostsharing.hsadminng.hs.admin.partner.TestHsAdminPartner.testLtd; |
| | | import static net.hostsharing.test.JpaAttempt.attempt; |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | @Disabled |
| | | @DataJpaTest |
| | | @ComponentScan(basePackageClasses = { Context.class, HsAdminPartnerRepository.class }) |
| | | @DirtiesContext |
| | | class HsAdminPartnerRepositoryIntegrationTest extends ContextBasedTest { |
| | | |
| | | @Autowired |
| | | HsAdminPartnerRepository partnerRepository; |
| | | |
| | | @Autowired |
| | | EntityManager em; |
| | | |
| | | @MockBean |
| | | HttpServletRequest request; |
| | | |
| | | @Nested |
| | | class CreateCustomer { |
| | | |
| | | @Test |
| | | public void testHostsharingAdmin_withoutAssumedRole_canCreateNewCustomer() { |
| | | // given |
| | | context("mike@example.org", null); |
| | | final var count = partnerRepository.count(); |
| | | |
| | | // when |
| | | |
| | | final var result = attempt(em, () -> { |
| | | return partnerRepository.save(testLtd); |
| | | }); |
| | | |
| | | // then |
| | | assertThat(result.wasSuccessful()).isTrue(); |
| | | assertThat(result.returnedValue()).isNotNull().extracting(HsAdminPartnerEntity::getUuid).isNotNull(); |
| | | assertThatPartnerIsPersisted(result.returnedValue()); |
| | | assertThat(partnerRepository.count()).isEqualTo(count + 1); |
| | | } |
| | | |
| | | private void assertThatPartnerIsPersisted(final HsAdminPartnerEntity saved) { |
| | | final var found = partnerRepository.findByUuid(saved.getUuid()); |
| | | assertThat(found).isNotEmpty().get().usingRecursiveComparison().isEqualTo(saved); |
| | | } |
| | | } |
| | | |
| | | @Nested |
| | | class FindAllCustomers { |
| | | |
| | | @Test |
| | | public void testGlobalAdmin_withoutAssumedRole_canViewAllCustomers() { |
| | | // given |
| | | context("mike@example.org", null); |
| | | |
| | | // when |
| | | final var result = partnerRepository.findPartnerByOptionalNameLike(null); |
| | | |
| | | // then |
| | | allThesePartnersAreReturned(result, "Ixx AG", "Ypsilon GmbH", "Zett OHG"); |
| | | } |
| | | |
| | | } |
| | | |
| | | @Nested |
| | | class FindByPrefixLike { |
| | | |
| | | @Test |
| | | public void testGlobalAdmin_withoutAssumedRole_canViewAllCustomers() { |
| | | // given |
| | | context("mike@example.org", null); |
| | | |
| | | // when |
| | | final var result = partnerRepository.findPartnerByOptionalNameLike("Yps"); |
| | | |
| | | // then |
| | | exactlyTheseCustomersAreReturned(result, "Ypsilon GmbH"); |
| | | } |
| | | |
| | | @Test |
| | | public void customerAdmin_withoutAssumedRole_canViewOnlyItsOwnCustomer() { |
| | | // given: |
| | | context("customer-admin@xxx.example.com", null); |
| | | |
| | | // when: |
| | | final var result = partnerRepository.findPartnerByOptionalNameLike("Yps"); |
| | | |
| | | // then: |
| | | exactlyTheseCustomersAreReturned(result); |
| | | } |
| | | } |
| | | |
| | | void exactlyTheseCustomersAreReturned(final List<HsAdminPartnerEntity> actualResult, final String... partnerTradeNames) { |
| | | assertThat(actualResult) |
| | | .hasSize(partnerTradeNames.length) |
| | | .extracting(HsAdminPartnerEntity::getPerson) |
| | | .extracting(HsAdminPersonEntity::getTradeName) |
| | | .containsExactlyInAnyOrder(partnerTradeNames); |
| | | } |
| | | |
| | | void allThesePartnersAreReturned(final List<HsAdminPartnerEntity> actualResult, final String... partnerTradeNames) { |
| | | assertThat(actualResult) |
| | | .extracting(HsAdminPartnerEntity::getPerson) |
| | | .extracting(HsAdminPersonEntity::getTradeName) |
| | | .contains(partnerTradeNames); |
| | | } |
| | | } |
New file |
| | |
| | | package net.hostsharing.hsadminng.hs.admin.partner; |
| | | |
| | | import net.hostsharing.hsadminng.hs.admin.contact.HsAdminContactEntity; |
| | | import net.hostsharing.hsadminng.hs.admin.partner.HsAdminPartnerEntity; |
| | | import net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity; |
| | | |
| | | import java.util.UUID; |
| | | |
| | | import static net.hostsharing.hsadminng.hs.admin.person.HsAdminPersonEntity.PersonType.LEGAL; |
| | | |
| | | public class TestHsAdminPartner { |
| | | |
| | | public static final HsAdminPartnerEntity testLtd = hsAdminPartnerWithLegalPerson("Test Ltd."); |
| | | |
| | | static public HsAdminPartnerEntity hsAdminPartnerWithLegalPerson(final String tradeName) { |
| | | return HsAdminPartnerEntity.builder() |
| | | .uuid(UUID.randomUUID()) |
| | | .person(HsAdminPersonEntity.builder() |
| | | .type(LEGAL) |
| | | .tradeName(tradeName) |
| | | .build()) |
| | | .contact(HsAdminContactEntity.builder() |
| | | .label(tradeName) |
| | | .build()) |
| | | .build(); |
| | | } |
| | | } |
| | |
| | | |
| | | import java.util.UUID; |
| | | |
| | | import static net.hostsharing.test.IsValidUuidMatcher.isValidUuid; |
| | | import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid; |
| | | import static org.hamcrest.Matchers.is; |
| | | import static org.mockito.ArgumentMatchers.argThat; |
| | | import static org.mockito.Mockito.verify; |
| | |
| | | |
| | | // then |
| | | .andExpect(status().isCreated()) |
| | | .andExpect(jsonPath("uuid", isValidUuid())); |
| | | .andExpect(jsonPath("uuid", isUuidValid())); |
| | | |
| | | // then |
| | | verify(rbacUserRepository).create(argThat(entity -> entity.getUuid() != null)); |
| | |
| | | import org.hamcrest.Matcher; |
| | | |
| | | import java.util.UUID; |
| | | import java.util.function.Predicate; |
| | | |
| | | public class IsValidUuidMatcher extends BaseMatcher<CharSequence> { |
| | | |
| | | public static Matcher<CharSequence> isValidUuid() { |
| | | public static Matcher<CharSequence> isUuidValid() { |
| | | return new IsValidUuidMatcher(); |
| | | } |
| | | |
| | | public static boolean isValidUuid(final String actual) { |
| | | public static boolean isUuidValid(final String actual) { |
| | | try { |
| | | UUID.fromString(actual); |
| | | } catch (final IllegalArgumentException exc) { |
| | |
| | | return true; |
| | | } |
| | | |
| | | public static Predicate<String> isValidUuid() { |
| | | return IsValidUuidMatcher::isUuidValid; |
| | | } |
| | | |
| | | @Override |
| | | public boolean matches(final Object actual) { |
| | | if (actual == null || actual.getClass().isAssignableFrom(CharSequence.class)) { |
| | | return false; |
| | | } |
| | | return isValidUuid(actual.toString()); |
| | | return isUuidValid(actual.toString()); |
| | | } |
| | | |
| | | @Override |
New file |
| | |
| | | package net.hostsharing.test; |
| | | |
| | | import org.json.JSONException; |
| | | import org.json.JSONObject; |
| | | |
| | | /** |
| | | * Build JSONObject with little boilerplate code. |
| | | */ |
| | | public class JsonBuilder { |
| | | |
| | | private final JSONObject jsonObject; |
| | | |
| | | /** |
| | | * Create a JsonBuilder from a string. |
| | | * |
| | | * @param jsonString valid JSON |
| | | * @return a new JsonBuilder |
| | | */ |
| | | public static JsonBuilder jsonObject(final String jsonString) { |
| | | return new JsonBuilder(jsonString); |
| | | } |
| | | |
| | | /** |
| | | * Add a property (key/value pair). |
| | | * |
| | | * @param key JSON key |
| | | * @param value JSON value |
| | | * @return this JsonBuilder |
| | | */ |
| | | public JsonBuilder with(final String key, final String value) { |
| | | try { |
| | | jsonObject.put(key, value); |
| | | } catch (JSONException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | return this; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | try { |
| | | return jsonObject.toString(4); |
| | | } catch (JSONException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | private JsonBuilder(final String jsonString) { |
| | | try { |
| | | jsonObject = new JSONObject(jsonString); |
| | | } catch (JSONException e) { |
| | | throw new RuntimeException(e); |
| | | } |
| | | } |
| | | |
| | | } |