diff --git a/package-lock.json b/package-lock.json index 544d36a9..b13a9116 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6025,7 +6025,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -6046,12 +6047,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6066,17 +6069,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -6193,7 +6199,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -6205,6 +6212,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6219,6 +6227,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6226,12 +6235,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6250,6 +6261,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -6330,7 +6342,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -6342,6 +6355,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6427,7 +6441,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6463,6 +6478,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6482,6 +6498,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6525,12 +6542,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/src/main/java/org/hostsharing/hsadminng/HsadminNgApp.java b/src/main/java/org/hostsharing/hsadminng/HsadminNgApp.java index d2e0adb8..3b119fde 100644 --- a/src/main/java/org/hostsharing/hsadminng/HsadminNgApp.java +++ b/src/main/java/org/hostsharing/hsadminng/HsadminNgApp.java @@ -1,11 +1,11 @@ package org.hostsharing.hsadminng; +import io.github.jhipster.config.JHipsterConstants; +import org.apache.commons.lang3.StringUtils; import org.hostsharing.hsadminng.config.ApplicationProperties; import org.hostsharing.hsadminng.config.DefaultProfileUtil; - -import io.github.jhipster.config.JHipsterConstants; - -import org.apache.commons.lang3.StringUtils; +import org.hostsharing.hsadminng.security.SecurityUtils; +import org.hostsharing.hsadminng.service.accessfilter.Role; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; @@ -41,6 +41,10 @@ public class HsadminNgApp { */ @PostConstruct public void initApplication() { + + // TODO: remove this hack once proper user roles are implemented + SecurityUtils.addUserRole(null, null, Role.HOSTMASTER); + Collection activeProfiles = Arrays.asList(env.getActiveProfiles()); if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) && activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) { log.error("You have misconfigured your application! It should not run " + diff --git a/src/main/java/org/hostsharing/hsadminng/domain/Asset.java b/src/main/java/org/hostsharing/hsadminng/domain/Asset.java index 13e13dc8..97410eba 100644 --- a/src/main/java/org/hostsharing/hsadminng/domain/Asset.java +++ b/src/main/java/org/hostsharing/hsadminng/domain/Asset.java @@ -2,17 +2,16 @@ package org.hostsharing.hsadminng.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.hostsharing.hsadminng.domain.enumeration.AssetAction; import javax.persistence.*; -import javax.validation.constraints.*; - +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; import java.math.BigDecimal; import java.time.LocalDate; import java.util.Objects; -import org.hostsharing.hsadminng.domain.enumeration.AssetAction; - /** * A Asset. */ diff --git a/src/main/java/org/hostsharing/hsadminng/domain/Customer.java b/src/main/java/org/hostsharing/hsadminng/domain/Customer.java index 8d49b690..b1745ea5 100644 --- a/src/main/java/org/hostsharing/hsadminng/domain/Customer.java +++ b/src/main/java/org/hostsharing/hsadminng/domain/Customer.java @@ -1,20 +1,16 @@ package org.hostsharing.hsadminng.domain; -import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; +import org.hostsharing.hsadminng.domain.enumeration.VatRegion; import javax.persistence.*; import javax.validation.constraints.*; - import java.io.Serializable; import java.time.LocalDate; import java.util.HashSet; -import java.util.Set; import java.util.Objects; - -import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; - -import org.hostsharing.hsadminng.domain.enumeration.VatRegion; +import java.util.Set; /** * A Customer. @@ -99,13 +95,21 @@ public class Customer implements Serializable { @OneToMany(mappedBy = "customer") private Set memberships = new HashSet<>(); + @OneToMany(mappedBy = "customer") private Set sepamandates = new HashSet<>(); + // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove + public Long getId() { return id; } + public Customer id(long id) { + this.id = id; + return this; + } + public void setId(Long id) { this.id = id; } @@ -354,6 +358,7 @@ public class Customer implements Serializable { public void setSepamandates(Set sepaMandates) { this.sepamandates = sepaMandates; } + // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove @Override diff --git a/src/main/java/org/hostsharing/hsadminng/domain/Membership.java b/src/main/java/org/hostsharing/hsadminng/domain/Membership.java index 37541257..0e6f4b0e 100644 --- a/src/main/java/org/hostsharing/hsadminng/domain/Membership.java +++ b/src/main/java/org/hostsharing/hsadminng/domain/Membership.java @@ -1,17 +1,16 @@ package org.hostsharing.hsadminng.domain; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import javax.persistence.*; -import javax.validation.constraints.*; - +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; import java.time.LocalDate; import java.util.HashSet; -import java.util.Set; import java.util.Objects; +import java.util.Set; /** * A Membership. @@ -49,18 +48,26 @@ public class Membership implements Serializable { @OneToMany(mappedBy = "membership") private Set shares = new HashSet<>(); + @OneToMany(mappedBy = "membership") private Set assets = new HashSet<>(); + @ManyToOne(optional = false) @NotNull @JsonIgnoreProperties("memberships") private Customer customer; // jhipster-needle-entity-add-field - JHipster will add fields here, do not remove + public Long getId() { return id; } + public Membership id(Long id) { + this.id = id; + return this; + } + public void setId(Long id) { this.id = id; } @@ -192,6 +199,7 @@ public class Membership implements Serializable { public void setCustomer(Customer customer) { this.customer = customer; } + // jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove @Override diff --git a/src/main/java/org/hostsharing/hsadminng/domain/SepaMandate.java b/src/main/java/org/hostsharing/hsadminng/domain/SepaMandate.java index e6bd34f4..6edc6e09 100644 --- a/src/main/java/org/hostsharing/hsadminng/domain/SepaMandate.java +++ b/src/main/java/org/hostsharing/hsadminng/domain/SepaMandate.java @@ -4,8 +4,8 @@ package org.hostsharing.hsadminng.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import javax.persistence.*; -import javax.validation.constraints.*; - +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; import java.time.LocalDate; import java.util.Objects; diff --git a/src/main/java/org/hostsharing/hsadminng/domain/Share.java b/src/main/java/org/hostsharing/hsadminng/domain/Share.java index 7d20e156..76923dd2 100644 --- a/src/main/java/org/hostsharing/hsadminng/domain/Share.java +++ b/src/main/java/org/hostsharing/hsadminng/domain/Share.java @@ -2,16 +2,15 @@ package org.hostsharing.hsadminng.domain; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.hostsharing.hsadminng.domain.enumeration.ShareAction; import javax.persistence.*; -import javax.validation.constraints.*; - +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; import java.time.LocalDate; import java.util.Objects; -import org.hostsharing.hsadminng.domain.enumeration.ShareAction; - /** * A Share. */ diff --git a/src/main/java/org/hostsharing/hsadminng/security/AuthoritiesConstants.java b/src/main/java/org/hostsharing/hsadminng/security/AuthoritiesConstants.java index 9aebdf89..bb1fd344 100644 --- a/src/main/java/org/hostsharing/hsadminng/security/AuthoritiesConstants.java +++ b/src/main/java/org/hostsharing/hsadminng/security/AuthoritiesConstants.java @@ -5,8 +5,12 @@ package org.hostsharing.hsadminng.security; */ public final class AuthoritiesConstants { + public static final String HOSTMASTER = "ROLE_HOSTMASTER"; + public static final String ADMIN = "ROLE_ADMIN"; + public static final String SUPPORTER = "ROLE_SUPPORTER"; + public static final String USER = "ROLE_USER"; public static final String ANONYMOUS = "ROLE_ANONYMOUS"; diff --git a/src/main/java/org/hostsharing/hsadminng/security/SecurityUtils.java b/src/main/java/org/hostsharing/hsadminng/security/SecurityUtils.java index eb655672..f5a4a1cb 100644 --- a/src/main/java/org/hostsharing/hsadminng/security/SecurityUtils.java +++ b/src/main/java/org/hostsharing/hsadminng/security/SecurityUtils.java @@ -1,9 +1,12 @@ package org.hostsharing.hsadminng.security; +import org.hostsharing.hsadminng.service.accessfilter.Role; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; /** @@ -11,6 +14,8 @@ import java.util.Optional; */ public final class SecurityUtils { + private static List userRoleAssignments = new ArrayList<>(); + private SecurityUtils() { } @@ -73,4 +78,41 @@ public final class SecurityUtils { .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals(authority))) .orElse(false); } + + public static Role getLoginUserRoleFor(final Class onDtoClass, final Long onId) { + final Role highestRole = userRoleAssignments.stream(). + map(ura -> + matches(onDtoClass, onId, ura) + ? ura.role + : Role.ANYBODY). + reduce(Role.ANYBODY, (r1, r2) -> r1.covers(r2) ? r1 : r2); + return highestRole; + } + + private static boolean matches(Class onDtoClass, Long onId, UserRoleAssignment ura) { + final boolean matches = (ura.onClass == null || onDtoClass == ura.onClass) && (ura.onId == null || ura.onId.equals(onId)); + return matches; + } + + // TODO: depends on https://plan.hostsharing.net/project/hsadmin/us/67?milestone=34 + public static void addUserRole(final Class onClass, final Long onId, final Role role) { + userRoleAssignments.add(new UserRoleAssignment(onClass, onId, role)); + + } + + public static void clearUserRoles() { + userRoleAssignments.clear(); + } + + private static class UserRoleAssignment { + final Class onClass; + final Long onId; + final Role role; + + UserRoleAssignment(Class onClass, Long onId, Role role) { + this.onClass = onClass; + this.onId = onId; + this.role = role; + } + } } diff --git a/src/main/java/org/hostsharing/hsadminng/service/AssetService.java b/src/main/java/org/hostsharing/hsadminng/service/AssetService.java index 21d1afb5..bc15e0b3 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/AssetService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/AssetService.java @@ -6,7 +6,6 @@ import org.hostsharing.hsadminng.service.dto.AssetDTO; import org.hostsharing.hsadminng.service.mapper.AssetMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; diff --git a/src/main/java/org/hostsharing/hsadminng/service/CustomerQueryService.java b/src/main/java/org/hostsharing/hsadminng/service/CustomerQueryService.java index e596b66d..718575f0 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/CustomerQueryService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/CustomerQueryService.java @@ -1,9 +1,14 @@ package org.hostsharing.hsadminng.service; -import java.util.List; - -import javax.persistence.criteria.JoinType; - +import io.github.jhipster.service.QueryService; +import org.hostsharing.hsadminng.domain.Customer; +import org.hostsharing.hsadminng.domain.Customer_; +import org.hostsharing.hsadminng.domain.Membership_; +import org.hostsharing.hsadminng.domain.SepaMandate_; +import org.hostsharing.hsadminng.repository.CustomerRepository; +import org.hostsharing.hsadminng.service.dto.CustomerCriteria; +import org.hostsharing.hsadminng.service.dto.CustomerDTO; +import org.hostsharing.hsadminng.service.mapper.CustomerMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -12,14 +17,8 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import io.github.jhipster.service.QueryService; - -import org.hostsharing.hsadminng.domain.Customer; -import org.hostsharing.hsadminng.domain.*; // for static metamodels -import org.hostsharing.hsadminng.repository.CustomerRepository; -import org.hostsharing.hsadminng.service.dto.CustomerCriteria; -import org.hostsharing.hsadminng.service.dto.CustomerDTO; -import org.hostsharing.hsadminng.service.mapper.CustomerMapper; +import javax.persistence.criteria.JoinType; +import java.util.List; /** * Service for executing complex queries for Customer entities in the database. diff --git a/src/main/java/org/hostsharing/hsadminng/service/CustomerService.java b/src/main/java/org/hostsharing/hsadminng/service/CustomerService.java index d7153deb..06d8d978 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/CustomerService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/CustomerService.java @@ -6,7 +6,6 @@ import org.hostsharing.hsadminng.service.dto.CustomerDTO; import org.hostsharing.hsadminng.service.mapper.CustomerMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; @@ -19,7 +18,7 @@ import java.util.Optional; */ @Service @Transactional -public class CustomerService { +public class CustomerService implements IdToDtoResolver { private final Logger log = LoggerFactory.getLogger(CustomerService.class); diff --git a/src/main/java/org/hostsharing/hsadminng/service/IdToDtoResolver.java b/src/main/java/org/hostsharing/hsadminng/service/IdToDtoResolver.java new file mode 100644 index 00000000..32851fb6 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/IdToDtoResolver.java @@ -0,0 +1,7 @@ +package org.hostsharing.hsadminng.service; + +import java.util.Optional; + +public interface IdToDtoResolver { + Optional findOne(Long id); +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/MembershipQueryService.java b/src/main/java/org/hostsharing/hsadminng/service/MembershipQueryService.java index c25a4912..adb07608 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/MembershipQueryService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/MembershipQueryService.java @@ -1,9 +1,11 @@ package org.hostsharing.hsadminng.service; -import java.util.List; - -import javax.persistence.criteria.JoinType; - +import io.github.jhipster.service.QueryService; +import org.hostsharing.hsadminng.domain.*; +import org.hostsharing.hsadminng.repository.MembershipRepository; +import org.hostsharing.hsadminng.service.dto.MembershipCriteria; +import org.hostsharing.hsadminng.service.dto.MembershipDTO; +import org.hostsharing.hsadminng.service.mapper.MembershipMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -12,14 +14,8 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import io.github.jhipster.service.QueryService; - -import org.hostsharing.hsadminng.domain.Membership; -import org.hostsharing.hsadminng.domain.*; // for static metamodels -import org.hostsharing.hsadminng.repository.MembershipRepository; -import org.hostsharing.hsadminng.service.dto.MembershipCriteria; -import org.hostsharing.hsadminng.service.dto.MembershipDTO; -import org.hostsharing.hsadminng.service.mapper.MembershipMapper; +import javax.persistence.criteria.JoinType; +import java.util.List; /** * Service for executing complex queries for Membership entities in the database. diff --git a/src/main/java/org/hostsharing/hsadminng/service/MembershipService.java b/src/main/java/org/hostsharing/hsadminng/service/MembershipService.java index 12e4fb40..473f5d7e 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/MembershipService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/MembershipService.java @@ -19,7 +19,7 @@ import java.util.Optional; */ @Service @Transactional -public class MembershipService { +public class MembershipService implements IdToDtoResolver { private final Logger log = LoggerFactory.getLogger(MembershipService.class); @@ -73,6 +73,7 @@ public class MembershipService { * @param id the id of the entity * @return the entity */ + @Override @Transactional(readOnly = true) public Optional findOne(Long id) { log.debug("Request to get Membership : {}", id); diff --git a/src/main/java/org/hostsharing/hsadminng/service/SepaMandateQueryService.java b/src/main/java/org/hostsharing/hsadminng/service/SepaMandateQueryService.java index ff0ebc89..3789d8d1 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/SepaMandateQueryService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/SepaMandateQueryService.java @@ -1,9 +1,13 @@ package org.hostsharing.hsadminng.service; -import java.util.List; - -import javax.persistence.criteria.JoinType; - +import io.github.jhipster.service.QueryService; +import org.hostsharing.hsadminng.domain.Customer_; +import org.hostsharing.hsadminng.domain.SepaMandate; +import org.hostsharing.hsadminng.domain.SepaMandate_; +import org.hostsharing.hsadminng.repository.SepaMandateRepository; +import org.hostsharing.hsadminng.service.dto.SepaMandateCriteria; +import org.hostsharing.hsadminng.service.dto.SepaMandateDTO; +import org.hostsharing.hsadminng.service.mapper.SepaMandateMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; @@ -12,14 +16,8 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import io.github.jhipster.service.QueryService; - -import org.hostsharing.hsadminng.domain.SepaMandate; -import org.hostsharing.hsadminng.domain.*; // for static metamodels -import org.hostsharing.hsadminng.repository.SepaMandateRepository; -import org.hostsharing.hsadminng.service.dto.SepaMandateCriteria; -import org.hostsharing.hsadminng.service.dto.SepaMandateDTO; -import org.hostsharing.hsadminng.service.mapper.SepaMandateMapper; +import javax.persistence.criteria.JoinType; +import java.util.List; /** * Service for executing complex queries for SepaMandate entities in the database. diff --git a/src/main/java/org/hostsharing/hsadminng/service/ShareService.java b/src/main/java/org/hostsharing/hsadminng/service/ShareService.java index 98c4979a..c9ff868b 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/ShareService.java +++ b/src/main/java/org/hostsharing/hsadminng/service/ShareService.java @@ -1,7 +1,6 @@ package org.hostsharing.hsadminng.service; import org.hostsharing.hsadminng.domain.Share; -import org.hostsharing.hsadminng.domain.enumeration.ShareAction; import org.hostsharing.hsadminng.repository.ShareRepository; import org.hostsharing.hsadminng.service.dto.ShareDTO; import org.hostsharing.hsadminng.service.mapper.ShareMapper; @@ -20,7 +19,7 @@ import java.util.Optional; */ @Service @Transactional -public class ShareService { +public class ShareService implements IdToDtoResolver { private final Logger log = LoggerFactory.getLogger(ShareService.class); diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java new file mode 100644 index 00000000..852f6138 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/AccessFor.java @@ -0,0 +1,16 @@ +package org.hostsharing.hsadminng.service.accessfilter; + + +import java.lang.annotation.*; + +@Documented +@Target({ElementType.FIELD, ElementType.TYPE_USE}) +@Retention(RetentionPolicy.RUNTIME) +public @interface AccessFor { + Role[] init() default Role.NOBODY; + + Role[] update() default Role.NOBODY; + + Role[] read() default Role.NOBODY; +} + diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonAccessFilter.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonAccessFilter.java new file mode 100644 index 00000000..e58e2046 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonAccessFilter.java @@ -0,0 +1,121 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.hostsharing.hsadminng.security.SecurityUtils; +import org.hostsharing.hsadminng.service.IdToDtoResolver; +import org.hostsharing.hsadminng.service.dto.MembershipDTO; +import org.hostsharing.hsadminng.service.util.ReflectionUtil; +import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; + +import static com.google.common.base.Verify.verify; + +abstract class JSonAccessFilter { + private final ApplicationContext ctx; + final T dto; + final Field selfIdField; + final Field parentIdField; + + JSonAccessFilter(final ApplicationContext ctx, final T dto) { + this.ctx = ctx; + this.dto = dto; + this.selfIdField = determineFieldWithAnnotation(dto.getClass(), SelfId.class); + this.parentIdField = determineFieldWithAnnotation(dto.getClass(), ParentId.class); + } + + boolean isParentIdField(final Field field) { + return field.equals(parentIdField); + } + + Long getId() { + if (selfIdField == null) { + return null; + } + return (Long) ReflectionUtil.getValue(dto, selfIdField); + } + + /** + * @param field to get a display representation for + * @return a simplified, decently user readable, display representation of the given field + */ + String toDisplay(final Field field) { + return field.getDeclaringClass().getSimpleName() + "." + field.getName(); + } + + /** + * @return the role of the login user in relation to the dto, this filter is created for. + */ + Role getLoginUserRole() { + final Role roleOnSelf = getLoginUserRoleOnSelf(); + if (roleOnSelf.isIndependent()) { + return roleOnSelf; + } + return getLoginUserRoleOnAncestorOfDtoClassIfHigher(roleOnSelf, dto); + } + + private Role getLoginUserRoleOnSelf() { + return SecurityUtils.getLoginUserRoleFor(dto.getClass(), getId()); + } + + private Role getLoginUserRoleOnAncestorOfDtoClassIfHigher(final Role baseRole, final Object dto) { + final Field parentIdField = determineFieldWithAnnotation(dto.getClass(), ParentId.class); + + if (parentIdField == null) { + return baseRole; + } + + final ParentId parentIdAnnot = parentIdField.getAnnotation(ParentId.class); + final Class parentDtoLoader = parentIdAnnot.resolver(); + final Class parentDtoClass = getGenericClassParameter(parentDtoLoader); + final Long parentId = (Long) ReflectionUtil.getValue(dto, parentIdField); + final Role roleOnParent = SecurityUtils.getLoginUserRoleFor(parentDtoClass, parentId); + + final Object parentEntity = loadDto(parentDtoLoader, parentId); + return Role.broadest(baseRole, getLoginUserRoleOnAncestorOfDtoClassIfHigher(roleOnParent, parentEntity)); + } + + @SuppressWarnings("unchecked") + private Class getGenericClassParameter(Class parentDtoLoader) { + for (Type genericInterface : parentDtoLoader.getGenericInterfaces()) { + if (genericInterface instanceof ParameterizedType) { + final ParameterizedType parameterizedType = (ParameterizedType) genericInterface; + if (parameterizedType.getRawType()== IdToDtoResolver.class) { + return (Class) parameterizedType.getActualTypeArguments()[0]; + } + } + + } + throw new AssertionError(parentDtoLoader.getSimpleName() + " expected to implement " + IdToDtoResolver.class.getSimpleName() + "<...DTO>"); + } + + @SuppressWarnings("unchecked") + protected Object loadDto(final Class resolverClass, final Long id) { + verify(id != null, "id must not be null"); + + final AutowireCapableBeanFactory beanFactory = ctx.getAutowireCapableBeanFactory(); + verify(beanFactory != null, "no bean factory found, probably missing mock configuration for ApplicationContext, e.g. given(...)"); + + final IdToDtoResolver resolverBean = beanFactory.createBean(resolverClass); + verify(resolverBean != null, "no " + resolverClass.getSimpleName() + " bean created, probably missing mock configuration for AutowireCapableBeanFactory, e.g. given(...)"); + + return resolverBean.findOne(id).orElseThrow(() -> new BadRequestAlertException("Can't resolve entity ID " + id + " via " + resolverClass, resolverClass.getSimpleName(), "isNotFound")); + } + + private static Field determineFieldWithAnnotation(final Class dtoClass, final Class idAnnotationClass) { + Field parentIdField = null; + for (Field field : dtoClass.getDeclaredFields()) { + if (field.isAnnotationPresent(idAnnotationClass)) { + if (parentIdField != null) { + throw new AssertionError("multiple @" + idAnnotationClass.getSimpleName() + " detected in " + field.getDeclaringClass().getSimpleName()); + } + parentIdField = field; + } + } + return parentIdField; + } +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilter.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilter.java new file mode 100644 index 00000000..0fe113a8 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilter.java @@ -0,0 +1,140 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.node.*; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.ObjectUtils; +import org.hostsharing.hsadminng.service.util.ReflectionUtil; +import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; +import org.springframework.context.ApplicationContext; + +import java.lang.reflect.Field; +import java.time.LocalDate; +import java.util.HashSet; +import java.util.Set; + +import static org.hostsharing.hsadminng.service.util.ReflectionUtil.unchecked; + +public class JSonDeserializerWithAccessFilter extends JSonAccessFilter { + + private final TreeNode treeNode; + private final Set writtenFields = new HashSet<>(); + + public JSonDeserializerWithAccessFilter(final ApplicationContext ctx, final JsonParser jsonParser, final DeserializationContext deserializationContext, Class dtoClass) { + super(ctx, unchecked(dtoClass::newInstance)); + this.treeNode = unchecked(() -> jsonParser.getCodec().readTree(jsonParser)); + } + + // Jackson deserializes from the JsonParser, thus no input parameter needed. + public T deserialize() { + deserializeValues(); + final T currentDto = loadCurrentDto(getId()); + overwriteUnmodifiedFieldsWithCurrentValues(currentDto); + checkAccessToWrittenFields(currentDto); + return dto; + } + + private void deserializeValues() { + treeNode.fieldNames().forEachRemaining(fieldName -> { + try { + final Field field = dto.getClass().getDeclaredField(fieldName); + final Object newValue = readValue(treeNode, field); + writeValue(dto, field, newValue); + } catch (NoSuchFieldException e) { + throw new RuntimeException("setting field " + fieldName + " failed", e); + } + }); + } + + @SuppressWarnings("unchecked") + private T loadCurrentDto(final Long id) { + if (id != null) { + return (T) loadDto(selfIdField.getAnnotation(SelfId.class).resolver(), id); + } + return null; + } + + private void overwriteUnmodifiedFieldsWithCurrentValues(final Object currentDto) { + if (currentDto == null) { + return; + } + for (Field field : currentDto.getClass().getDeclaredFields()) { + if (field.isAnnotationPresent(AccessFor.class) && !writtenFields.contains(field)) { + final Object value = ReflectionUtil.getValue(currentDto, field); + ReflectionUtil.setValue(dto, field, value); + } + + } + } + + private Object readValue(final TreeNode treeNode, final Field field) { + return readValue(treeNode, field.getName(), field.getType()); + + } + + private Object readValue(final TreeNode treeNode, final String fieldName, final Class fieldClass) { + final TreeNode fieldNode = treeNode.get(fieldName); + if (fieldNode instanceof NullNode) { + return null; + } + if (fieldNode instanceof TextNode) { + return ((TextNode) fieldNode).asText(); + } + if (fieldNode instanceof IntNode) { + return ((IntNode) fieldNode).asInt(); + } + if (fieldNode instanceof LongNode) { + return ((LongNode) fieldNode).asLong(); + } + if (fieldNode instanceof ArrayNode && LocalDate.class.isAssignableFrom(fieldClass)) { + return LocalDate.of(((ArrayNode) fieldNode).get(0).asInt(), ((ArrayNode) fieldNode).get(1).asInt(), ((ArrayNode) fieldNode).get(2).asInt()); + } + { + throw new NotImplementedException("property type not yet implemented: " + fieldNode + " -> " + fieldName + ": " + fieldClass); + } + } + + private void writeValue(final T dto, final Field field, final Object value) { + if (value == null) { + ReflectionUtil.setValue(dto, field, null); + } else if (field.getType().isAssignableFrom(value.getClass())) { + ReflectionUtil.setValue(dto, field, value); + } else if (Integer.class.isAssignableFrom(field.getType()) || int.class.isAssignableFrom(field.getType())) { + ReflectionUtil.setValue(dto, field, ((Number) value).intValue()); + } else if (Long.class.isAssignableFrom(field.getType()) || long.class.isAssignableFrom(field.getType())) { + ReflectionUtil.setValue(dto, field, ((Number) value).longValue()); + } else if (field.getType().isEnum()) { + ReflectionUtil.setValue(dto, field, Enum.valueOf((Class) field.getType(), value.toString())); + } else if (LocalDate.class.isAssignableFrom(field.getType())) { + ReflectionUtil.setValue(dto, field, LocalDate.parse(value.toString())); + } else { + throw new NotImplementedException("property type not yet implemented: " + field); + } + writtenFields.add(field); + } + + private void checkAccessToWrittenFields(final T currentDto) { + writtenFields.forEach(field -> { + if (!field.equals(selfIdField)) { + final Role role = getLoginUserRole(); + if (getId() == null) { + if (!role.isAllowedToInit(field)) { + if (!field.equals(parentIdField)) { + throw new BadRequestAlertException("Initialization of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "initializationProhibited"); + } else { + throw new BadRequestAlertException("Referencing field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "referencingProhibited"); + } + } + } else if (isUpdate(field, dto, currentDto) && !getLoginUserRole().isAllowedToUpdate(field)) { + throw new BadRequestAlertException("Update of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "updateProhibited"); + } + } + }); + } + + private boolean isUpdate(final Field field, final T dto, T currentDto) { + return ObjectUtils.notEqual(ReflectionUtil.getValue(dto, field), ReflectionUtil.getValue(currentDto, field)); + } +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java new file mode 100644 index 00000000..fbbaade3 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilter.java @@ -0,0 +1,72 @@ +package org.hostsharing.hsadminng.service.accessfilter; + + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.SerializerProvider; +import org.apache.commons.lang3.NotImplementedException; +import org.springframework.context.ApplicationContext; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.time.LocalDate; + +public class JSonSerializerWithAccessFilter extends JSonAccessFilter { + private final JsonGenerator jsonGenerator; + private final SerializerProvider serializerProvider; + + public JSonSerializerWithAccessFilter(final ApplicationContext ctx, + final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider, + final T dto) { + super(ctx, dto); + this.jsonGenerator = jsonGenerator; + this.serializerProvider = serializerProvider; + } + + // Jackson serializes into the JsonGenerator, thus no return value needed. + public void serialize() throws IOException { + + jsonGenerator.writeStartObject(); + for (Field field : dto.getClass().getDeclaredFields()) { + toJSon(dto, jsonGenerator, field); + } + jsonGenerator.writeEndObject(); + } + + private void toJSon(final Object dto, final JsonGenerator jsonGenerator, final Field field) throws IOException { + if (getLoginUserRole().isAllowedToRead(field)) { + final String fieldName = field.getName(); + // TODO: maybe replace by serializerProvider.defaultSerialize...()? + // But that makes it difficult for parallel structure with the deserializer (clumsy API). + // Alternatively extract the supported types to subclasses of some abstract class and + // here as well as in the deserializer just access the matching implementation through a map. + // Or even completely switch from Jackson to GSON? + final Object fieldValue = get(dto, field); + if (fieldValue == null) { + jsonGenerator.writeNullField(fieldName); + } else if (Integer.class.isAssignableFrom(field.getType()) || int.class.isAssignableFrom(field.getType())) { + jsonGenerator.writeNumberField(fieldName, (int) fieldValue); + } else if (Long.class.isAssignableFrom(field.getType()) || long.class.isAssignableFrom(field.getType())) { + jsonGenerator.writeNumberField(fieldName, (long) fieldValue); + } else if (LocalDate.class.isAssignableFrom(field.getType())) { + jsonGenerator.writeStringField(fieldName, fieldValue.toString()); // TODO proper format + } else if (Enum.class.isAssignableFrom(field.getType())) { + jsonGenerator.writeStringField(fieldName, fieldValue.toString()); // TODO proper representation + } else if (String.class.isAssignableFrom(field.getType())) { + jsonGenerator.writeStringField(fieldName, (String) fieldValue); + } else { + throw new NotImplementedException("property type not yet implemented: " + field); + } + } + } + + private Object get(final Object dto, final Field field) { + try { + field.setAccessible(true); + return field.get(dto); + } catch (IllegalAccessException e) { + throw new RuntimeException("getting field " + field + " failed", e); + } + } + +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/ParentId.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/ParentId.java new file mode 100644 index 00000000..e392374e --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/ParentId.java @@ -0,0 +1,19 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.hostsharing.hsadminng.service.IdToDtoResolver; + +import java.lang.annotation.*; + +/** + * Used to mark a field within a DTO as containing the id of a referenced entity, + * it's needed to determine access rights for entity creation. + * + * @see AccessFor + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ParentId { + /// The service which can load the referenced DTO. + Class> resolver(); +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java new file mode 100644 index 00000000..e1de24cf --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/Role.java @@ -0,0 +1,186 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import java.lang.reflect.Field; + +/** + * These enum values are on the one hand used to define the minimum role required to grant access to resources, + * but on the other hand also for the roles users can be assigned to. + * + * TODO: Maybe splitting it up into UserRole and RequiredRole would make it more clear? + * And maybe instead of a level, we could then add the comprised roles in the constructor? + * This could also be a better way to express that the financial contact has no rights to + * other users resources (see also ACTUAL_CUSTOMER_USEr vs. ANY_CUSTOMER_USER). + */ +public enum Role { + /** + * Default for access rights requirement. You can read it as: 'Nobody is allowed to ...'. + * This is usually used for fields which are managed by hsadminNg itself. + */ + NOBODY(0), + + /** + * Hostmasters are initialize/update/read and field which, except where NOBODY is allowed to. + */ + HOSTMASTER(1), + + /** + * This role is for administrators, e.g. to create memberships and book shared and assets. + */ + ADMIN(2), + + /** + * This role is for members of the support team. + */ + SUPPORTER(3), + + /** + * This role is for contractual contacts of a customer, like a director of the company. + * Who has this role, has the broadest access to all resources which belong to this customer. + * Everything which relates to the contract with the customer, needs this role. + */ + CONTRACTUAL_CONTACT(20), + + /** + * This role is for financial contacts of a customer, e.g. for accessing billing data. + */ + FINANCIAL_CONTACT(22) { + @Override + public boolean covers(final Role role) { + if (role == ACTUAL_CUSTOMER_USER) { + return false; + } + return super.covers(role); + } + }, + + /** + * This role is for technical contacts of a customer. + */ + TECHNICAL_CONTACT(22), + + + /** + * This meta-role is to specify that any kind of customer contact can get access to the resource. + */ + ANY_CUSTOMER_CONTACT(29), + + /** + * Any user which belongs to a customer has at least this role. + */ + ACTUAL_CUSTOMER_USER(80), + + /** + * Use this to grant rights to any user, also special function users who have no + * rights on other users resources. + */ + ANY_CUSTOMER_USER(89), + + /** + * This role is meant to specify that a resources can be accessed by anybody, even without login. + * It's currently only used for technical purposes. + */ + ANYBODY(99); + + private final int level; + + Role(final int level) { + this.level = level; + } + + /** + * @return true if this role is independent of a target object, false otherwise. + */ + public boolean isIndependent() { + return covers(Role.SUPPORTER); + } + + /** + @return the role with the broadest access rights + */ + public static Role broadest(final Role role, final Role... roles) { + Role broadests = role; + for ( Role r: roles ) { + if ( r.covers(broadests)) { + broadests = r; + } + } + return broadests; + } + + /** + * Determines if the given role is covered by this role. + * + * Where 'this' means the Java instance itself as a role of a system user. + * + * {@code + * Role.HOSTMASTER.covers(Role.ANY_CUSTOMER_USER) == true + * } + * + * @param role The required role for a resource. + * + * @return whether this role comprises the given role + */ + public boolean covers(final Role role) { + return this == role || this.level < role.level; + } + + /** + * Checks if this role of a user allows to initialize the given field when creating the resource. + * + * @param field a field of the DTO of a resource + * + * @return true if allowed + */ + public boolean isAllowedToInit(final Field field) { + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.init()); + } + + /** + * Checks if this role of a user allows to update the given field. + * + * @param field a field of the DTO of a resource + * + * @return true if allowed + */ + public boolean isAllowedToUpdate(final Field field) { + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.update()); + } + + /** + * Checks if this role of a user allows to read the given field. + * + * @param field a field of the DTO of a resource + * + * @return true if allowed + */ + public boolean isAllowedToRead(final Field field) { + + final AccessFor accessFor = field.getAnnotation(AccessFor.class); + if (accessFor == null) { + return false; + } + + return isRoleCovered(accessFor.read()); + } + + private boolean isRoleCovered(final Role[] requiredRoles) { + for (Role accessAllowedForRole : requiredRoles) { + if (this.covers(accessAllowedForRole)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/accessfilter/SelfId.java b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/SelfId.java new file mode 100644 index 00000000..6c67b9fb --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/accessfilter/SelfId.java @@ -0,0 +1,21 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.hostsharing.hsadminng.service.IdToDtoResolver; + +import java.lang.annotation.*; + +/** + * Used to mark a field within a DTO as containing the own id, + * it's needed to identify an existing entity for update functions. + * Initialization and update rights have no meaning for such fields, + * its initialized automatically and never updated. + * + * @see AccessFor + */ +@Documented +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface SelfId { + /// The service which can load the referenced DTO. + Class> resolver(); +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/AssetDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/AssetDTO.java index db7570af..d52a535a 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/AssetDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/AssetDTO.java @@ -1,10 +1,13 @@ package org.hostsharing.hsadminng.service.dto; -import java.time.LocalDate; -import javax.validation.constraints.*; + +import org.hostsharing.hsadminng.domain.enumeration.AssetAction; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; import java.math.BigDecimal; +import java.time.LocalDate; import java.util.Objects; -import org.hostsharing.hsadminng.domain.enumeration.AssetAction; /** * A DTO for the Asset entity. @@ -31,7 +34,7 @@ public class AssetDTO implements Serializable { private Long membershipId; - private String membershipAdmissionDocumentDate; + private String membershipDisplayReference; public Long getId() { return id; @@ -89,12 +92,12 @@ public class AssetDTO implements Serializable { this.membershipId = membershipId; } - public String getMembershipAdmissionDocumentDate() { - return membershipAdmissionDocumentDate; + public String getMembershipDisplayReference() { + return membershipDisplayReference; } - public void setMembershipAdmissionDocumentDate(String membershipAdmissionDocumentDate) { - this.membershipAdmissionDocumentDate = membershipAdmissionDocumentDate; + public void setMembershipDisplayReference(String membershipDisplayReference) { + this.membershipDisplayReference = membershipDisplayReference; } @Override @@ -128,7 +131,7 @@ public class AssetDTO implements Serializable { ", amount=" + getAmount() + ", remark='" + getRemark() + "'" + ", membership=" + getMembershipId() + - ", membership='" + getMembershipAdmissionDocumentDate() + "'" + + ", membership='" + getMembershipDisplayReference() + "'" + "}"; } } diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerCriteria.java b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerCriteria.java index dce18ff4..50fc2a0e 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerCriteria.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerCriteria.java @@ -1,17 +1,11 @@ package org.hostsharing.hsadminng.service.dto; +import io.github.jhipster.service.filter.*; +import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; +import org.hostsharing.hsadminng.domain.enumeration.VatRegion; + import java.io.Serializable; import java.util.Objects; -import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; -import org.hostsharing.hsadminng.domain.enumeration.VatRegion; -import io.github.jhipster.service.filter.BooleanFilter; -import io.github.jhipster.service.filter.DoubleFilter; -import io.github.jhipster.service.filter.Filter; -import io.github.jhipster.service.filter.FloatFilter; -import io.github.jhipster.service.filter.IntegerFilter; -import io.github.jhipster.service.filter.LongFilter; -import io.github.jhipster.service.filter.StringFilter; -import io.github.jhipster.service.filter.LocalDateFilter; /** * Criteria class for the Customer entity. This class is used in CustomerResource to diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java index 2d0fdfdb..4b9708d1 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/CustomerDTO.java @@ -1,69 +1,98 @@ package org.hostsharing.hsadminng.service.dto; -import java.time.LocalDate; -import javax.validation.constraints.*; -import java.io.Serializable; -import java.util.Objects; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; import org.hostsharing.hsadminng.domain.enumeration.VatRegion; +import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.accessfilter.*; +import org.springframework.boot.jackson.JsonComponent; +import org.springframework.context.ApplicationContext; + +import javax.validation.constraints.*; +import java.io.IOException; +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; /** * A DTO for the Customer entity. */ -public class CustomerDTO implements Serializable { +public class CustomerDTO extends FluentBuilder implements Serializable { + @SelfId(resolver = CustomerService.class) + @AccessFor(read = Role.ANY_CUSTOMER_USER) private Long id; @NotNull @Min(value = 10000) @Max(value = 99999) + @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER) private Integer reference; @NotNull @Size(max = 3) @Pattern(regexp = "[a-z][a-z0-9]+") + @AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER) private String prefix; @NotNull @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.ANY_CUSTOMER_USER) private String name; @NotNull + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT) private CustomerKind kind; + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate birthDate; @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String birthPlace; @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String registrationCourt; @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String registrationNumber; @NotNull + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private VatRegion vatRegion; @Size(max = 40) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String vatNumber; @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = Role.CONTRACTUAL_CONTACT, read = Role.CONTRACTUAL_CONTACT) private String contractualSalutation; @NotNull @Size(max = 400) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CONTRACTUAL_CONTACT) private String contractualAddress; @Size(max = 80) + @AccessFor(init = Role.ADMIN, update = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}, read = Role.CONTRACTUAL_CONTACT) private String billingSalutation; @Size(max = 400) + @AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String billingAddress; @Size(max = 160) + @AccessFor(init = Role.ADMIN, update = Role.SUPPORTER, read = Role.SUPPORTER) private String remark; - public Long getId() { return id; } @@ -234,4 +263,39 @@ public class CustomerDTO implements Serializable { ", remark='" + getRemark() + "'" + "}"; } + + @JsonComponent + public static class CustomerJsonSerializer extends JsonSerializer { + + private final ApplicationContext ctx; + + public CustomerJsonSerializer(final ApplicationContext ctx) { + this.ctx = ctx; + } + + @Override + public void serialize(final CustomerDTO customerDTO, final JsonGenerator jsonGenerator, + final SerializerProvider serializerProvider) throws IOException { + + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, serializerProvider, customerDTO).serialize(); + } + } + + @JsonComponent + public static class CustomerJsonDeserializer extends JsonDeserializer { + + private final ApplicationContext ctx; + + public CustomerJsonDeserializer(final ApplicationContext ctx) { + this.ctx = ctx; + } + + @Override + public CustomerDTO deserialize(final JsonParser jsonParser, + final DeserializationContext deserializationContext) { + + return new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, deserializationContext, CustomerDTO.class).deserialize(); + } + } } + diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/FluentBuilder.java b/src/main/java/org/hostsharing/hsadminng/service/dto/FluentBuilder.java new file mode 100644 index 00000000..63cf70c6 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/FluentBuilder.java @@ -0,0 +1,15 @@ +package org.hostsharing.hsadminng.service.dto; + +import java.util.function.Consumer; + +public class FluentBuilder { + + @SuppressWarnings("unchecked") + public T with( + Consumer builderFunction) { + builderFunction.accept((T) this); + return (T) this; + } + + +} diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipCriteria.java b/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipCriteria.java index 8e29c98f..14d42ed3 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipCriteria.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipCriteria.java @@ -1,15 +1,12 @@ package org.hostsharing.hsadminng.service.dto; +import io.github.jhipster.service.filter.Filter; +import io.github.jhipster.service.filter.LocalDateFilter; +import io.github.jhipster.service.filter.LongFilter; +import io.github.jhipster.service.filter.StringFilter; + import java.io.Serializable; import java.util.Objects; -import io.github.jhipster.service.filter.BooleanFilter; -import io.github.jhipster.service.filter.DoubleFilter; -import io.github.jhipster.service.filter.Filter; -import io.github.jhipster.service.filter.FloatFilter; -import io.github.jhipster.service.filter.IntegerFilter; -import io.github.jhipster.service.filter.LongFilter; -import io.github.jhipster.service.filter.StringFilter; -import io.github.jhipster.service.filter.LocalDateFilter; /** * Criteria class for the Membership entity. This class is used in MembershipResource to diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipDTO.java index 7c62fd2e..2286a064 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/MembershipDTO.java @@ -1,41 +1,52 @@ package org.hostsharing.hsadminng.service.dto; -import java.time.LocalDate; -import javax.validation.constraints.*; + +import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.MembershipService; +import org.hostsharing.hsadminng.service.accessfilter.AccessFor; +import org.hostsharing.hsadminng.service.accessfilter.ParentId; +import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.service.accessfilter.SelfId; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; +import java.time.LocalDate; import java.util.Objects; -import java.util.function.Consumer; /** * A DTO for the Membership entity. */ -public class MembershipDTO implements Serializable { +public class MembershipDTO extends FluentBuilder implements Serializable { + @SelfId(resolver = MembershipService.class) + @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private Long id; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate admissionDocumentDate; + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate cancellationDocumentDate; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate memberFromDate; + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate memberUntilDate; @Size(max = 160) + @AccessFor(init = Role.ADMIN, read = Role.SUPPORTER) private String remark; - + @ParentId(resolver = CustomerService.class) + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private Long customerId; + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private String customerPrefix; - public MembershipDTO with( - Consumer builderFunction) { - builderFunction.accept(this); - return this; - } - public Long getId() { return id; } diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateCriteria.java b/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateCriteria.java index 9b3a4fe1..5196db49 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateCriteria.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateCriteria.java @@ -1,15 +1,12 @@ package org.hostsharing.hsadminng.service.dto; +import io.github.jhipster.service.filter.Filter; +import io.github.jhipster.service.filter.LocalDateFilter; +import io.github.jhipster.service.filter.LongFilter; +import io.github.jhipster.service.filter.StringFilter; + import java.io.Serializable; import java.util.Objects; -import io.github.jhipster.service.filter.BooleanFilter; -import io.github.jhipster.service.filter.DoubleFilter; -import io.github.jhipster.service.filter.Filter; -import io.github.jhipster.service.filter.FloatFilter; -import io.github.jhipster.service.filter.IntegerFilter; -import io.github.jhipster.service.filter.LongFilter; -import io.github.jhipster.service.filter.StringFilter; -import io.github.jhipster.service.filter.LocalDateFilter; /** * Criteria class for the SepaMandate entity. This class is used in SepaMandateResource to diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateDTO.java index 1867c642..914b22b9 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/SepaMandateDTO.java @@ -1,7 +1,9 @@ package org.hostsharing.hsadminng.service.dto; -import java.time.LocalDate; -import javax.validation.constraints.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; +import java.time.LocalDate; import java.util.Objects; /** diff --git a/src/main/java/org/hostsharing/hsadminng/service/dto/ShareDTO.java b/src/main/java/org/hostsharing/hsadminng/service/dto/ShareDTO.java index d4d7ef2d..cb61e088 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/dto/ShareDTO.java +++ b/src/main/java/org/hostsharing/hsadminng/service/dto/ShareDTO.java @@ -1,36 +1,54 @@ package org.hostsharing.hsadminng.service.dto; -import java.time.LocalDate; -import javax.validation.constraints.*; -import java.io.Serializable; -import java.util.Objects; + import org.hostsharing.hsadminng.domain.enumeration.ShareAction; +import org.hostsharing.hsadminng.service.MembershipService; +import org.hostsharing.hsadminng.service.ShareService; +import org.hostsharing.hsadminng.service.accessfilter.AccessFor; +import org.hostsharing.hsadminng.service.accessfilter.ParentId; +import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.service.accessfilter.SelfId; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.time.LocalDate; +import java.util.Objects; /** * A DTO for the Share entity. */ public class ShareDTO implements Serializable { + @SelfId(resolver = ShareService.class) + @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private Long id; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate documentDate; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private LocalDate valueDate; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private ShareAction action; @NotNull + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private Integer quantity; @Size(max = 160) + @AccessFor(init = Role.ADMIN, read = Role.SUPPORTER) private String remark; - + @ParentId(resolver = MembershipService.class) + @AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) private Long membershipId; - private String membershipAdmissionDocumentDate; + @AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT}) + private String membershipDisplayReference; public Long getId() { return id; @@ -88,12 +106,12 @@ public class ShareDTO implements Serializable { this.membershipId = membershipId; } - public String getMembershipAdmissionDocumentDate() { - return membershipAdmissionDocumentDate; + public String getMembershipDisplayReference() { + return membershipDisplayReference; } - public void setMembershipAdmissionDocumentDate(String membershipAdmissionDocumentDate) { - this.membershipAdmissionDocumentDate = membershipAdmissionDocumentDate; + public void setMembershipDisplayReference(String membershipDisplayReference) { + this.membershipDisplayReference = membershipDisplayReference; } @Override @@ -127,7 +145,7 @@ public class ShareDTO implements Serializable { ", quantity=" + getQuantity() + ", remark='" + getRemark() + "'" + ", membership=" + getMembershipId() + - ", membership='" + getMembershipAdmissionDocumentDate() + "'" + + ", membership='" + getMembershipDisplayReference() + "'" + "}"; } } diff --git a/src/main/java/org/hostsharing/hsadminng/service/mapper/AssetMapper.java b/src/main/java/org/hostsharing/hsadminng/service/mapper/AssetMapper.java index 95ee103d..40399960 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/mapper/AssetMapper.java +++ b/src/main/java/org/hostsharing/hsadminng/service/mapper/AssetMapper.java @@ -1,9 +1,9 @@ package org.hostsharing.hsadminng.service.mapper; -import org.hostsharing.hsadminng.domain.*; +import org.hostsharing.hsadminng.domain.Asset; import org.hostsharing.hsadminng.service.dto.AssetDTO; - -import org.mapstruct.*; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; /** * Mapper for the entity Asset and its DTO AssetDTO. @@ -12,7 +12,7 @@ import org.mapstruct.*; public interface AssetMapper extends EntityMapper { @Mapping(source = "membership.id", target = "membershipId") - @Mapping(source = "membership.admissionDocumentDate", target = "membershipAdmissionDocumentDate") + @Mapping(source = "membership.admissionDocumentDate", target = "membershipDisplayReference") AssetDTO toDto(Asset asset); @Mapping(source = "membershipId", target = "membership") diff --git a/src/main/java/org/hostsharing/hsadminng/service/mapper/ShareMapper.java b/src/main/java/org/hostsharing/hsadminng/service/mapper/ShareMapper.java index c7a85ab8..775ca7be 100644 --- a/src/main/java/org/hostsharing/hsadminng/service/mapper/ShareMapper.java +++ b/src/main/java/org/hostsharing/hsadminng/service/mapper/ShareMapper.java @@ -1,9 +1,9 @@ package org.hostsharing.hsadminng.service.mapper; -import org.hostsharing.hsadminng.domain.*; +import org.hostsharing.hsadminng.domain.Share; import org.hostsharing.hsadminng.service.dto.ShareDTO; - -import org.mapstruct.*; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; /** * Mapper for the entity Share and its DTO ShareDTO. @@ -12,7 +12,7 @@ import org.mapstruct.*; public interface ShareMapper extends EntityMapper { @Mapping(source = "membership.id", target = "membershipId") - @Mapping(source = "membership.admissionDocumentDate", target = "membershipAdmissionDocumentDate") + @Mapping(source = "membership.admissionDocumentDate", target = "membershipDisplayReference") ShareDTO toDto(Share share); @Mapping(source = "membershipId", target = "membership") diff --git a/src/main/java/org/hostsharing/hsadminng/service/util/ReflectionUtil.java b/src/main/java/org/hostsharing/hsadminng/service/util/ReflectionUtil.java new file mode 100644 index 00000000..377f2748 --- /dev/null +++ b/src/main/java/org/hostsharing/hsadminng/service/util/ReflectionUtil.java @@ -0,0 +1,47 @@ +package org.hostsharing.hsadminng.service.util; + +import java.lang.reflect.Field; + +public class ReflectionUtil { + + public static void setValue(final T dto, final String fieldName, final Object value) { + try { + final Field field = dto.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(dto, value); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static void setValue(final T dto, final Field field, final Object value) { + try { + field.setAccessible(true); + field.set(dto, value); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public static T getValue(final T dto, final Field field) { + try { + field.setAccessible(true); + return (T) field.get(dto); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @FunctionalInterface + public interface ThrowingSupplier { + T get() throws Exception; + } + + public static T unchecked(final ThrowingSupplier supplier) { + try { + return supplier.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/org/hostsharing/hsadminng/web/rest/AssetResource.java b/src/main/java/org/hostsharing/hsadminng/web/rest/AssetResource.java index 819dd519..c82ad9a1 100644 --- a/src/main/java/org/hostsharing/hsadminng/web/rest/AssetResource.java +++ b/src/main/java/org/hostsharing/hsadminng/web/rest/AssetResource.java @@ -1,25 +1,24 @@ package org.hostsharing.hsadminng.web.rest; + +import io.github.jhipster.web.util.ResponseUtil; +import org.hostsharing.hsadminng.service.AssetQueryService; import org.hostsharing.hsadminng.service.AssetService; +import org.hostsharing.hsadminng.service.dto.AssetCriteria; +import org.hostsharing.hsadminng.service.dto.AssetDTO; import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; import org.hostsharing.hsadminng.web.rest.util.HeaderUtil; import org.hostsharing.hsadminng.web.rest.util.PaginationUtil; -import org.hostsharing.hsadminng.service.dto.AssetDTO; -import org.hostsharing.hsadminng.service.dto.AssetCriteria; -import org.hostsharing.hsadminng.service.AssetQueryService; -import io.github.jhipster.web.util.ResponseUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.net.URI; import java.net.URISyntaxException; - import java.util.List; import java.util.Optional; diff --git a/src/main/java/org/hostsharing/hsadminng/web/rest/CustomerResource.java b/src/main/java/org/hostsharing/hsadminng/web/rest/CustomerResource.java index aa5e3710..b5a3b74e 100644 --- a/src/main/java/org/hostsharing/hsadminng/web/rest/CustomerResource.java +++ b/src/main/java/org/hostsharing/hsadminng/web/rest/CustomerResource.java @@ -1,25 +1,24 @@ package org.hostsharing.hsadminng.web.rest; + +import io.github.jhipster.web.util.ResponseUtil; +import org.hostsharing.hsadminng.service.CustomerQueryService; import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.dto.CustomerCriteria; +import org.hostsharing.hsadminng.service.dto.CustomerDTO; import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; import org.hostsharing.hsadminng.web.rest.util.HeaderUtil; import org.hostsharing.hsadminng.web.rest.util.PaginationUtil; -import org.hostsharing.hsadminng.service.dto.CustomerDTO; -import org.hostsharing.hsadminng.service.dto.CustomerCriteria; -import org.hostsharing.hsadminng.service.CustomerQueryService; -import io.github.jhipster.web.util.ResponseUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.net.URI; import java.net.URISyntaxException; - import java.util.List; import java.util.Optional; @@ -72,7 +71,7 @@ public class CustomerResource { * @throws URISyntaxException if the Location URI syntax is incorrect */ @PutMapping("/customers") - public ResponseEntity updateCustomer(@Valid @RequestBody CustomerDTO customerDTO) throws URISyntaxException { + public ResponseEntity updateCustomer(@RequestBody CustomerDTO customerDTO) { log.debug("REST request to update Customer : {}", customerDTO); if (customerDTO.getId() == null) { throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull"); diff --git a/src/main/java/org/hostsharing/hsadminng/web/rest/errors/BadRequestAlertException.java b/src/main/java/org/hostsharing/hsadminng/web/rest/errors/BadRequestAlertException.java index 0548500f..f395377a 100644 --- a/src/main/java/org/hostsharing/hsadminng/web/rest/errors/BadRequestAlertException.java +++ b/src/main/java/org/hostsharing/hsadminng/web/rest/errors/BadRequestAlertException.java @@ -11,32 +11,32 @@ public class BadRequestAlertException extends AbstractThrowableProblem { private static final long serialVersionUID = 1L; - private final String entityName; + private final String param; private final String errorKey; - public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) { - this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey); + public BadRequestAlertException(String defaultMessage, String param, String errorKey) { + this(ErrorConstants.DEFAULT_TYPE, defaultMessage, param, errorKey); } - public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) { - super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey)); - this.entityName = entityName; + public BadRequestAlertException(URI type, String defaultMessage, String param, String errorKey) { + super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(param, errorKey)); + this.param = param; this.errorKey = errorKey; } - public String getEntityName() { - return entityName; + public String getParam() { + return param; } public String getErrorKey() { return errorKey; } - private static Map getAlertParameters(String entityName, String errorKey) { + private static Map getAlertParameters(String param, String errorKey) { Map parameters = new HashMap<>(); parameters.put("message", "error." + errorKey); - parameters.put("params", entityName); + parameters.put("params", param); return parameters; } } diff --git a/src/main/java/org/hostsharing/hsadminng/web/rest/errors/ExceptionTranslator.java b/src/main/java/org/hostsharing/hsadminng/web/rest/errors/ExceptionTranslator.java index d810090c..ea414e84 100644 --- a/src/main/java/org/hostsharing/hsadminng/web/rest/errors/ExceptionTranslator.java +++ b/src/main/java/org/hostsharing/hsadminng/web/rest/errors/ExceptionTranslator.java @@ -104,7 +104,7 @@ public class ExceptionTranslator implements ProblemHandling { @ExceptionHandler public ResponseEntity handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) { - return create(ex, request, HeaderUtil.createFailureAlert(ex.getEntityName(), ex.getErrorKey(), ex.getMessage())); + return create(ex, request, HeaderUtil.createFailureAlert(ex.getParam(), ex.getErrorKey(), ex.getMessage())); } @ExceptionHandler diff --git a/src/main/resources/.h2.server.properties b/src/main/resources/.h2.server.properties index 909b4938..b775c018 100644 --- a/src/main/resources/.h2.server.properties +++ b/src/main/resources/.h2.server.properties @@ -1,5 +1,5 @@ #H2 Server Properties -#Wed Apr 03 13:36:25 CEST 2019 +#Thu Apr 25 12:42:42 CEST 2019 0=JHipster H2 (Memory)|org.h2.Driver|jdbc\:h2\:mem\:hsadminng|hsadminNg webAllowOthers=true webPort=8082 diff --git a/src/main/resources/config/liquibase/authorities.csv b/src/main/resources/config/liquibase/authorities.csv index af5c6dfa..f56c3aa4 100644 --- a/src/main/resources/config/liquibase/authorities.csv +++ b/src/main/resources/config/liquibase/authorities.csv @@ -1,3 +1,5 @@ name +ROLE_HOSTMASTER ROLE_ADMIN +ROLE_SUPPORTER ROLE_USER diff --git a/src/main/resources/config/liquibase/changelog/20190424123255_added_entity_Customer.xml b/src/main/resources/config/liquibase/changelog/20190424123255_added_entity_Customer.xml index 3b855a94..e98a308e 100644 --- a/src/main/resources/config/liquibase/changelog/20190424123255_added_entity_Customer.xml +++ b/src/main/resources/config/liquibase/changelog/20190424123255_added_entity_Customer.xml @@ -1,10 +1,8 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> diff --git a/src/main/resources/config/liquibase/changelog/20190424123256_added_entity_Membership.xml b/src/main/resources/config/liquibase/changelog/20190424123256_added_entity_Membership.xml index 14a40ce1..9a001791 100644 --- a/src/main/resources/config/liquibase/changelog/20190424123256_added_entity_Membership.xml +++ b/src/main/resources/config/liquibase/changelog/20190424123256_added_entity_Membership.xml @@ -1,10 +1,8 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> diff --git a/src/main/resources/config/liquibase/changelog/20190424123257_added_entity_Share.xml b/src/main/resources/config/liquibase/changelog/20190424123257_added_entity_Share.xml index 6e2bd896..122ac4eb 100644 --- a/src/main/resources/config/liquibase/changelog/20190424123257_added_entity_Share.xml +++ b/src/main/resources/config/liquibase/changelog/20190424123257_added_entity_Share.xml @@ -1,10 +1,8 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> diff --git a/src/main/resources/config/liquibase/changelog/20190424123258_added_entity_Asset.xml b/src/main/resources/config/liquibase/changelog/20190424123258_added_entity_Asset.xml index 4f7570bc..5a39564a 100644 --- a/src/main/resources/config/liquibase/changelog/20190424123258_added_entity_Asset.xml +++ b/src/main/resources/config/liquibase/changelog/20190424123258_added_entity_Asset.xml @@ -1,10 +1,8 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> diff --git a/src/main/resources/config/liquibase/changelog/20190424123259_added_entity_SepaMandate.xml b/src/main/resources/config/liquibase/changelog/20190424123259_added_entity_SepaMandate.xml index aa602736..e3cf003e 100644 --- a/src/main/resources/config/liquibase/changelog/20190424123259_added_entity_SepaMandate.xml +++ b/src/main/resources/config/liquibase/changelog/20190424123259_added_entity_SepaMandate.xml @@ -1,10 +1,8 @@ + xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.5.xsd"> diff --git a/src/main/resources/config/liquibase/users_authorities.csv b/src/main/resources/config/liquibase/users_authorities.csv index 06c5feee..bb482bfa 100644 --- a/src/main/resources/config/liquibase/users_authorities.csv +++ b/src/main/resources/config/liquibase/users_authorities.csv @@ -1,4 +1,5 @@ user_id;authority_name +1;ROLE_HOSTMASTER 1;ROLE_ADMIN 1;ROLE_USER 3;ROLE_ADMIN diff --git a/src/main/webapp/app/entities/asset/asset-detail.component.html b/src/main/webapp/app/entities/asset/asset-detail.component.html index 93f2e7f5..d31955d3 100644 --- a/src/main/webapp/app/entities/asset/asset-detail.component.html +++ b/src/main/webapp/app/entities/asset/asset-detail.component.html @@ -28,7 +28,7 @@
Membership
diff --git a/src/main/webapp/app/entities/asset/asset.component.html b/src/main/webapp/app/entities/asset/asset.component.html index 2b918714..29ac04a6 100644 --- a/src/main/webapp/app/entities/asset/asset.component.html +++ b/src/main/webapp/app/entities/asset/asset.component.html @@ -20,7 +20,7 @@ Action Amount Remark - Membership + Membership @@ -34,7 +34,7 @@ {{asset.remark}} diff --git a/src/main/webapp/app/entities/customer/customer-update.component.ts b/src/main/webapp/app/entities/customer/customer-update.component.ts index 33cbdd4f..e6c33ae8 100644 --- a/src/main/webapp/app/entities/customer/customer-update.component.ts +++ b/src/main/webapp/app/entities/customer/customer-update.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; -import * as moment from 'moment'; import { ICustomer } from 'app/shared/model/customer.model'; import { CustomerService } from './customer.service'; diff --git a/src/main/webapp/app/entities/customer/customer.component.ts b/src/main/webapp/app/entities/customer/customer.component.ts index a1d3ce51..3f95501d 100644 --- a/src/main/webapp/app/entities/customer/customer.component.ts +++ b/src/main/webapp/app/entities/customer/customer.component.ts @@ -1,8 +1,7 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { HttpErrorResponse, HttpHeaders, HttpResponse } from '@angular/common/http'; import { Subscription } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; -import { JhiEventManager, JhiParseLinks, JhiAlertService } from 'ng-jhipster'; +import { JhiAlertService, JhiEventManager, JhiParseLinks } from 'ng-jhipster'; import { ICustomer } from 'app/shared/model/customer.model'; import { AccountService } from 'app/core'; diff --git a/src/main/webapp/app/entities/membership/membership-update.component.ts b/src/main/webapp/app/entities/membership/membership-update.component.ts index d3a72e41..74140751 100644 --- a/src/main/webapp/app/entities/membership/membership-update.component.ts +++ b/src/main/webapp/app/entities/membership/membership-update.component.ts @@ -1,9 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import * as moment from 'moment'; import { JhiAlertService } from 'ng-jhipster'; import { IMembership } from 'app/shared/model/membership.model'; import { MembershipService } from './membership.service'; diff --git a/src/main/webapp/app/entities/sepa-mandate/sepa-mandate-update.component.ts b/src/main/webapp/app/entities/sepa-mandate/sepa-mandate-update.component.ts index bcafb5b0..8efa2127 100644 --- a/src/main/webapp/app/entities/sepa-mandate/sepa-mandate-update.component.ts +++ b/src/main/webapp/app/entities/sepa-mandate/sepa-mandate-update.component.ts @@ -1,9 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { HttpResponse, HttpErrorResponse } from '@angular/common/http'; +import { HttpErrorResponse, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { filter, map } from 'rxjs/operators'; -import * as moment from 'moment'; import { JhiAlertService } from 'ng-jhipster'; import { ISepaMandate } from 'app/shared/model/sepa-mandate.model'; import { SepaMandateService } from './sepa-mandate.service'; diff --git a/src/main/webapp/app/entities/share/share-detail.component.html b/src/main/webapp/app/entities/share/share-detail.component.html index bd3df716..d64180ab 100644 --- a/src/main/webapp/app/entities/share/share-detail.component.html +++ b/src/main/webapp/app/entities/share/share-detail.component.html @@ -28,7 +28,7 @@
Membership
diff --git a/src/main/webapp/app/entities/share/share.component.html b/src/main/webapp/app/entities/share/share.component.html index d42d00e1..7a7ba8e6 100644 --- a/src/main/webapp/app/entities/share/share.component.html +++ b/src/main/webapp/app/entities/share/share.component.html @@ -20,7 +20,7 @@ Action Quantity Remark - Membership + Membership @@ -34,7 +34,7 @@ {{share.remark}} diff --git a/src/main/webapp/app/shared/model/asset.model.ts b/src/main/webapp/app/shared/model/asset.model.ts index f5b8f1d1..caac8b37 100644 --- a/src/main/webapp/app/shared/model/asset.model.ts +++ b/src/main/webapp/app/shared/model/asset.model.ts @@ -16,7 +16,7 @@ export interface IAsset { action?: AssetAction; amount?: number; remark?: string; - membershipAdmissionDocumentDate?: string; + membershipDisplayReference?: string; membershipId?: number; } @@ -28,7 +28,7 @@ export class Asset implements IAsset { public action?: AssetAction, public amount?: number, public remark?: string, - public membershipAdmissionDocumentDate?: string, + public membershipDisplayReference?: string, public membershipId?: number ) {} } diff --git a/src/main/webapp/app/shared/model/share.model.ts b/src/main/webapp/app/shared/model/share.model.ts index 215243a7..eade53c3 100644 --- a/src/main/webapp/app/shared/model/share.model.ts +++ b/src/main/webapp/app/shared/model/share.model.ts @@ -12,7 +12,7 @@ export interface IShare { action?: ShareAction; quantity?: number; remark?: string; - membershipAdmissionDocumentDate?: string; + membershipDisplayReference?: string; membershipId?: number; } @@ -24,7 +24,7 @@ export class Share implements IShare { public action?: ShareAction, public quantity?: number, public remark?: string, - public membershipAdmissionDocumentDate?: string, + public membershipDisplayReference?: string, public membershipId?: number ) {} } diff --git a/src/main/webapp/i18n/de/custom-error.json b/src/main/webapp/i18n/de/custom-error.json index 8c5722c8..b82d687c 100644 --- a/src/main/webapp/i18n/de/custom-error.json +++ b/src/main/webapp/i18n/de/custom-error.json @@ -1,13 +1,16 @@ { "error": { + "idNotFound": "Technische Datensatz-ID nicht gefunden", "shareSubscriptionPositiveQuantity": "Zeichnungen von Geschäftsanteilen erfordern eine positive Stückzahl", "shareCancellationNegativeQuantity": "Kündigungen von Geschäftsanteilen erfordern eine negative Stückzahl", "shareTransactionImmutable": "Transaktionen mit Geschäftsanteilen sind unveränderlich", "membershipNotDeletable": "Mitgliedschaft kann nicht gelöscht werden, setze stattdessen das 'untilDate'", - "untilDateMustBeAfterSinceDate": "Mitgliedshaftsaustrittsdatum muss nach dem Beitrittsdatum liegen", + "untilDateMustBeAfterSinceDate": "Mitgliedshafts-Austrittsdatum muss nach dem Beitrittsdatum liegen", + "anotherUncancelledMembershipExists": "Nur eine einzige ungekündigte Mitgliedschaft pro Kunde ist zulässig", + "initializationProhibited": "Initialisierung des Feldes unzulässig", + "updateProhibited": "Aktualisierung des Feldes unzulässig", "documentDateMayNotBeAfterValueDate": "Belegdatum darf nicht vor dem Buchungsdatum liegen", "assetTransactionImmutable": "Transaktionen mit Geschäftsguthaben sind unveränderlich", - "anotherUncancelledMembershipExists": "Nur eine einzige ungekündigte Mitgliedschaft pro Kunde ist zulässig", "assetPaymentsPositiveAmount": "Einzahlungen von Geschäftsguthaben erfordern einen positiven Betrag", "assetAdoptionsPositiveAmount": "Übernahmen von Geschäftsguthaben erfordern einen positiven Betrag", "assetPaybacksNegativeAmount": "Auszahlungen von Geschäftsguthaben erfordern einen negativen Betrag", diff --git a/src/main/webapp/i18n/en/custom-error.json b/src/main/webapp/i18n/en/custom-error.json index b6f699a5..657e0361 100644 --- a/src/main/webapp/i18n/en/custom-error.json +++ b/src/main/webapp/i18n/en/custom-error.json @@ -1,12 +1,15 @@ { "error": { + "idNotFound": "Technical record-ID not found", "shareSubscriptionPositiveQuantity": "Share subscriptions require a positive quantity", "shareCancellationNegativeQuantity": "Share cancellations require a negative quantity", "shareTransactionImmutable": "Share transactions are immutable", "membershipNotDeletable": "Membership cannot be deleted, instead set 'untilDate'", "untilDateMustBeAfterSinceDate": "Membership until date must be after since date", - "documentDateMayNotBeAfterValueDate": "Document date may not be after value date", "anotherUncancelledMembershipExists": "Only a single uncancelled membership allowed per customer", + "initializationProhibited": "Initialization of the field prohibited", + "updateProhibited": "Update of the field prohibited", + "documentDateMayNotBeAfterValueDate": "Document date may not be after value date", "assetTransactionImmutable": "Asset transactions are immutable", "assetPaymentsPositiveAmount": "Asset payments require a positive amount", "assetAdoptionsPositiveAmount": "Asset adoptions require a positive amount", diff --git a/src/test/java/org/hostsharing/hsadminng/service/ShareValidatorUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/ShareValidatorUnitTest.java index d2ab4694..d521f510 100644 --- a/src/test/java/org/hostsharing/hsadminng/service/ShareValidatorUnitTest.java +++ b/src/test/java/org/hostsharing/hsadminng/service/ShareValidatorUnitTest.java @@ -3,7 +3,6 @@ package org.hostsharing.hsadminng.service; import org.apache.commons.lang3.RandomUtils; import org.assertj.core.api.AbstractThrowableAssert; import org.hostsharing.hsadminng.domain.enumeration.ShareAction; -import org.hostsharing.hsadminng.service.dto.AssetDTO; import org.hostsharing.hsadminng.service.dto.ShareDTO; import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; import org.junit.Test; diff --git a/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonBuilder.java b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonBuilder.java new file mode 100644 index 00000000..01e3832f --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonBuilder.java @@ -0,0 +1,27 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +public class JSonBuilder { + + @SafeVarargs + public static String asJSon(final ImmutablePair... properties) { + final StringBuilder json = new StringBuilder(); + for (ImmutablePair prop : properties) { + json.append(inQuotes(prop.left)); + json.append(": "); + if (prop.right instanceof Number) { + json.append(prop.right); + } else { + json.append(inQuotes(prop.right)); + } + json.append(",\n"); + } + return "{\n" + json.substring(0, json.length() - 2) + "\n}"; + } + + private static String inQuotes(Object value) { + return value != null ? "\"" + value.toString() + "\"" : "null"; + } + +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilterUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilterUnitTest.java new file mode 100644 index 00000000..686eff80 --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonDeserializerWithAccessFilterUnitTest.java @@ -0,0 +1,315 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.hostsharing.hsadminng.service.IdToDtoResolver; +import org.hostsharing.hsadminng.service.dto.FluentBuilder; +import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; + +import java.io.IOException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.hostsharing.hsadminng.service.accessfilter.JSonBuilder.asJSon; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole; +import static org.mockito.BDDMockito.given; + +@SuppressWarnings("ALL") +public class JSonDeserializerWithAccessFilterUnitTest { + + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private ApplicationContext ctx; + + @Mock + private AutowireCapableBeanFactory autowireCapableBeanFactory; + + @Mock + private JsonParser jsonParser; + + @Mock + private ObjectCodec codec; + + @Mock + private TreeNode treeNode; + + @Mock + private GivenService givenService; + + @Mock + private GivenChildService givenChildService; + + @Before + public void init() { + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1234L, Role.ACTUAL_CUSTOMER_USER); + + given (ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory); + given(autowireCapableBeanFactory.createBean(GivenService.class)).willReturn(givenService); + given(givenService.findOne(1234L)).willReturn(Optional.of(new GivenDto() + .with(dto -> dto.id = 1234L) + .with(dto -> dto.openIntegerField = 1) + .with(dto -> dto.openLongField = 2L) + .with(dto -> dto.openStringField = "3") + .with(dto -> dto.restrictedField = "initial value of restricted field") + )); + + given(jsonParser.getCodec()).willReturn(codec); + } + + @Test + public void shouldDeserializeNullField() throws IOException { + // given + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("openStringField", null))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.openStringField).isNull(); + } + + @Test + public void shouldDeserializeStringField() throws IOException { + // given + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("openStringField", "String Value"))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.openStringField).isEqualTo("String Value"); + } + + @Test + public void shouldDeserializeIntegerField() throws IOException { + // given + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("openIntegerField", 1234))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.openIntegerField).isEqualTo(1234); + } + + @Test + public void shouldDeserializeLongField() throws IOException { + // given + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("openLongField", 1234L))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.openLongField).isEqualTo(1234L); + } + + @Test + public void shouldDeserializeStringFieldIfRequiredRoleIsCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1234L, Role.FINANCIAL_CONTACT); + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("restrictedField", "update value of restricted field"))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.restrictedField).isEqualTo("update value of restricted field"); + } + + @Test + public void shouldDeserializeUnchangedStringFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1234L, Role.ANY_CUSTOMER_USER); + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("restrictedField", "initial value of restricted field"))); + + // when + GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize(); + + // then + assertThat(actualDto.restrictedField).isEqualTo("initial value of restricted field"); + } + + @Test + public void shouldNotDeserializeUpatedStringFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1L, Role.ANY_CUSTOMER_USER); + givenJSonTree(asJSon(ImmutablePair.of("restrictedField", "updated value of restricted field"))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("GivenDto.restrictedField"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("initializationProhibited"); + }); + } + + @Test + public void shouldInitializeFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1L, Role.ANY_CUSTOMER_USER); + givenJSonTree(asJSon(ImmutablePair.of("restrictedField", "another value of restricted field"))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("GivenDto.restrictedField"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("initializationProhibited"); + }); + } + + @Test + public void shouldNotCreateIfRoleRequiredByParentEntityIsNotCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 9999L, Role.CONTRACTUAL_CONTACT); + givenJSonTree(asJSon(ImmutablePair.of("parentId", 1234L))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenChildDto.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("GivenChildDto.parentId"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("referencingProhibited"); + }); + } + + @Test + public void shouldCreateIfRoleRequiredByReferencedEntityIsCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1234L, Role.CONTRACTUAL_CONTACT); + givenJSonTree(asJSon(ImmutablePair.of("parentId", 1234L))); + + // when + final GivenChildDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenChildDto.class).deserialize(); + + // then + assertThat(actualDto.parentId).isEqualTo(1234L); + } + + @Test + public void shouldNotUpdateFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(GivenDto.class, 1234L, Role.ANY_CUSTOMER_USER); + givenJSonTree(asJSon( + ImmutablePair.of("id", 1234L), + ImmutablePair.of("restrictedField", "Restricted String Value"))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("GivenDto.restrictedField"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("updateProhibited"); + }); + } + + @Test + public void shouldDetectMultipleSelfIdFields() throws IOException { + // given + givenJSonTree(asJSon(ImmutablePair.of("id", 1111L))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDtoWithMultipleSelfId.class).deserialize()); + + // then + assertThat(exception).isInstanceOf(AssertionError.class).hasMessage("multiple @SelfId detected in GivenDtoWithMultipleSelfId"); + } + + // --- only fixture code below --- + + private void givenJSonTree(String givenJSon) throws IOException { + given(codec.readTree(jsonParser)).willReturn(new ObjectMapper().readTree(givenJSon)); + } + + abstract class GivenService implements IdToDtoResolver { + } + + public static class GivenDto extends FluentBuilder { + + @SelfId(resolver = GivenService.class) + @AccessFor(read = Role.ANY_CUSTOMER_USER) + Long id; + + @AccessFor(init = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}, update = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}) + String restrictedField; + + @AccessFor(init = Role.ANYBODY, update = Role.ANYBODY) + String openStringField; + + @AccessFor(init = Role.ANYBODY, update = Role.ANYBODY) + Integer openIntegerField; + + @AccessFor(init = Role.ANYBODY, update = Role.ANYBODY) + Long openLongField; + } + + abstract class GivenChildService implements IdToDtoResolver { + } + + public static class GivenChildDto extends FluentBuilder { + + @SelfId(resolver = GivenChildService.class) + @AccessFor(read = Role.ANY_CUSTOMER_USER) + Long id; + + @AccessFor(init = Role.CONTRACTUAL_CONTACT, update = Role.CONTRACTUAL_CONTACT, read = Role.ACTUAL_CUSTOMER_USER) + @ParentId(resolver = GivenService.class) + Long parentId; + + @AccessFor(init = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}, update = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}) + String restrictedField; + } + + public static class GivenDtoWithMultipleSelfId { + + @SelfId(resolver = GivenChildService.class) + @AccessFor(read = Role.ANY_CUSTOMER_USER) + Long id; + + @SelfId(resolver = GivenChildService.class) + @AccessFor(read = Role.ANY_CUSTOMER_USER) + Long id2; + + } +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilterUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilterUnitTest.java new file mode 100644 index 00000000..cff8cba4 --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/JSonSerializerWithAccessFilterUnitTest.java @@ -0,0 +1,162 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import com.fasterxml.jackson.core.JsonGenerator; +import org.apache.commons.lang3.NotImplementedException; +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.RandomUtils; +import org.hostsharing.hsadminng.service.IdToDtoResolver; +import org.hostsharing.hsadminng.service.dto.FluentBuilder; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; + +import java.io.IOException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +public class JSonSerializerWithAccessFilterUnitTest { + + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private ApplicationContext ctx; + + @Mock + private AutowireCapableBeanFactory autowireCapableBeanFactory; + + @Mock + private JsonGenerator jsonGenerator; + + @Mock + private GivenCustomerService givenCustomerService; + + private final GivenDto givenDTO = createSampleDto(); + + @Before + public void init() { + MockSecurityContext.givenAuthenticatedUser(); + MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.ANY_CUSTOMER_USER); + + given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory); + given(autowireCapableBeanFactory.createBean(GivenCustomerService.class)).willReturn(givenCustomerService); + given(givenCustomerService.findOne(888L)).willReturn(Optional.of(new GivenCustomerDto() + .with(dto -> dto.id = 888L) + )); + } + + @Test + public void shouldSerializeStringField() throws IOException { + // when + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize(); + + // then + verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField); + } + + @Test + public void shouldSerializeRestrictedFieldIfRequiredRoleIsCoveredByUser() throws IOException { + + // given + MockSecurityContext.givenAuthenticatedUser(); + MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.FINANCIAL_CONTACT); + + // when + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize(); + + // then + verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField); + } + + @Test + public void shouldNotSerializeRestrictedFieldIfRequiredRoleIsNotCoveredByUser() throws IOException { + + // given + MockSecurityContext.givenAuthenticatedUser(); + MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.ANY_CUSTOMER_USER); + + // when + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize(); + + // then + verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField); + } + + @Test + public void shouldThrowExceptionForUnimplementedFieldType() { + + // given + class Arbitrary { + } + class GivenDtoWithUnimplementedFieldType { + @AccessFor(read = Role.ANYBODY) + Arbitrary fieldWithUnimplementedType = new Arbitrary(); + } + final GivenDtoWithUnimplementedFieldType givenDtoWithUnimplementedFieldType = new GivenDtoWithUnimplementedFieldType(); + + // when + final Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDtoWithUnimplementedFieldType).serialize()); + + // then + assertThat(actual).isInstanceOf(NotImplementedException.class); + } + + // --- fixture code below --- + + private GivenDto createSampleDto() { + final GivenDto dto = new GivenDto(); + dto.customerId = 888L; + dto.restrictedField = RandomStringUtils.randomAlphabetic(10); + dto.openStringField = RandomStringUtils.randomAlphabetic(10); + dto.openIntegerField = RandomUtils.nextInt(); + dto.openLongField = RandomUtils.nextLong(); + return dto; + } + + private static class GivenCustomerDto extends FluentBuilder { + @SelfId(resolver = GivenService.class) + @AccessFor(read = Role.ANYBODY) + Long id; + } + + private abstract class GivenCustomerService implements IdToDtoResolver { + } + + private static class GivenDto { + + @SelfId(resolver = GivenService.class) + @AccessFor(read = Role.ANYBODY) + Long id; + + @ParentId(resolver = GivenCustomerService.class) + @AccessFor(read = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}) + Long customerId; + + @AccessFor(read = {Role.TECHNICAL_CONTACT, Role.FINANCIAL_CONTACT}) + String restrictedField; + + @AccessFor(read = Role.ANYBODY) + String openStringField; + + @AccessFor(read = Role.ANYBODY) + Integer openIntegerField; + + @AccessFor(read = Role.ANYBODY) + Long openLongField; + } + + private abstract class GivenService implements IdToDtoResolver { + } + + +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/accessfilter/MockSecurityContext.java b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/MockSecurityContext.java new file mode 100644 index 00000000..dab9a8b6 --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/MockSecurityContext.java @@ -0,0 +1,32 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.hostsharing.hsadminng.security.SecurityUtils; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MockSecurityContext { + + public static void givenAuthenticatedUser() { + SecurityContext securityContext = SecurityContextHolder.createEmptyContext(); + securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("dummyUser", "dummyPassword")); + SecurityContextHolder.setContext(securityContext); + SecurityUtils.clearUserRoles(); + + assertThat(SecurityUtils.getCurrentUserLogin()).describedAs("precondition failed").hasValue("dummyUser"); + } + + public static void givenUserHavingRole(final Class onClass, final Long onId, final Role role) { + if ((onClass == null || onId == null) && !role.isIndependent()) { + throw new IllegalArgumentException("dependent roles like " + role + " missing DtoClass and ID"); + } + SecurityUtils.addUserRole(onClass, onId, role); + } + + public static void givenUserHavingRole(final Role role) { + givenUserHavingRole(null, null, role); + } + +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/accessfilter/RoleUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/RoleUnitTest.java new file mode 100644 index 00000000..66944774 --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/accessfilter/RoleUnitTest.java @@ -0,0 +1,83 @@ +package org.hostsharing.hsadminng.service.accessfilter; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class RoleUnitTest { + + @Test + public void allUserRolesShouldCoverSameRequiredRole() { + assertThat(Role.HOSTMASTER.covers(Role.HOSTMASTER)).isTrue(); + assertThat(Role.ADMIN.covers(Role.ADMIN)).isTrue(); + assertThat(Role.SUPPORTER.covers(Role.SUPPORTER)).isTrue(); + + assertThat(Role.CONTRACTUAL_CONTACT.covers(Role.CONTRACTUAL_CONTACT)).isTrue(); + assertThat(Role.FINANCIAL_CONTACT.covers(Role.FINANCIAL_CONTACT)).isTrue(); + assertThat(Role.TECHNICAL_CONTACT.covers(Role.TECHNICAL_CONTACT)).isTrue(); + + + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.ACTUAL_CUSTOMER_USER))).isTrue(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.ANY_CUSTOMER_USER))).isTrue(); + } + + @Test + public void lowerUserRolesShouldNotCoverHigherRequiredRoles() { + assertThat(Role.HOSTMASTER.covers(Role.NOBODY)).isFalse(); + assertThat(Role.ADMIN.covers(Role.HOSTMASTER)).isFalse(); + assertThat(Role.SUPPORTER.covers(Role.ADMIN)).isFalse(); + + assertThat(Role.ANY_CUSTOMER_CONTACT.covers(Role.SUPPORTER)).isFalse(); + assertThat(Role.ANY_CUSTOMER_CONTACT.covers(Role.CONTRACTUAL_CONTACT)).isFalse(); + assertThat(Role.FINANCIAL_CONTACT.covers(Role.CONTRACTUAL_CONTACT)).isFalse(); + assertThat(Role.FINANCIAL_CONTACT.covers(Role.TECHNICAL_CONTACT)).isFalse(); + assertThat(Role.TECHNICAL_CONTACT.covers(Role.CONTRACTUAL_CONTACT)).isFalse(); + assertThat(Role.TECHNICAL_CONTACT.covers(Role.FINANCIAL_CONTACT)).isFalse(); + + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.ANY_CUSTOMER_CONTACT))).isFalse(); + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.CONTRACTUAL_CONTACT))).isFalse(); + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.TECHNICAL_CONTACT))).isFalse(); + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.FINANCIAL_CONTACT))).isFalse(); + + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.ACTUAL_CUSTOMER_USER))).isFalse(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.ANY_CUSTOMER_CONTACT))).isFalse(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.CONTRACTUAL_CONTACT))).isFalse(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.TECHNICAL_CONTACT))).isFalse(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.FINANCIAL_CONTACT))).isFalse(); + + assertThat(Role.ANYBODY.covers((Role.ANY_CUSTOMER_USER))).isFalse(); + } + + @Test + public void higherUserRolesShouldCoverLowerRequiredRoles() { + assertThat(Role.HOSTMASTER.covers(Role.SUPPORTER)).isTrue(); + assertThat(Role.ADMIN.covers(Role.SUPPORTER)).isTrue(); + + assertThat(Role.SUPPORTER.covers(Role.ANY_CUSTOMER_CONTACT)).isTrue(); + + assertThat(Role.CONTRACTUAL_CONTACT.covers(Role.ANY_CUSTOMER_CONTACT)).isTrue(); + assertThat(Role.CONTRACTUAL_CONTACT.covers(Role.FINANCIAL_CONTACT)).isTrue(); + assertThat(Role.CONTRACTUAL_CONTACT.covers(Role.TECHNICAL_CONTACT)).isTrue(); + assertThat(Role.TECHNICAL_CONTACT.covers(Role.ANY_CUSTOMER_USER)).isTrue(); + + assertThat(Role.ACTUAL_CUSTOMER_USER.covers((Role.ANY_CUSTOMER_USER))).isTrue(); + assertThat(Role.ANY_CUSTOMER_USER.covers((Role.ANYBODY))).isTrue(); + } + + @Test + public void financialContactShouldNotCoverAnyCustomersUsersRoleRequirement() { + assertThat(Role.FINANCIAL_CONTACT.covers(Role.ACTUAL_CUSTOMER_USER)).isFalse(); + } + + @Test + public void isAllowedToInit() { + } + + @Test + public void isAllowedToUpdate() { + } + + @Test + public void isAllowedToRead() { + } +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java new file mode 100644 index 00000000..5d25cfea --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/CustomerDTOUnitTest.java @@ -0,0 +1,191 @@ +package org.hostsharing.hsadminng.service.dto; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.hostsharing.hsadminng.domain.Customer; +import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; +import org.hostsharing.hsadminng.domain.enumeration.VatRegion; +import org.hostsharing.hsadminng.repository.CustomerRepository; +import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.service.mapper.CustomerMapper; +import org.hostsharing.hsadminng.service.mapper.CustomerMapperImpl; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.json.JsonTest; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole; +import static org.junit.Assert.assertEquals; +import static org.mockito.BDDMockito.given; + +@JsonTest +@SpringBootTest(classes = {CustomerMapperImpl.class, CustomerRepository.class, CustomerService.class, CustomerDTO.CustomerJsonSerializer.class, CustomerDTO.CustomerJsonDeserializer.class}) +@RunWith(SpringRunner.class) +public class CustomerDTOUnitTest { + + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private CustomerMapper customerMapper; + + @MockBean + private CustomerRepository customerRepository; + + @MockBean + private CustomerService customerService; + + @Test + public void testSerializationAsContractualCustomerContact() throws JsonProcessingException { + + // given + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, 1234L, Role.CONTRACTUAL_CONTACT); + CustomerDTO given = createSomeCustomerDTO(1234L); + + // when + String actual = objectMapper.writeValueAsString(given); + + // then + given.setRemark(null); + assertEquals(createExpectedJSon(given), actual); + } + + @Test + public void testSerializationAsTechnicalCustomerUser() throws JsonProcessingException { + + // given + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, 1234L, Role.TECHNICAL_CONTACT); + CustomerDTO given = createSomeCustomerDTO(1234L); + + // when + String actual = objectMapper.writeValueAsString(given); + + // then + final String expectedJSon = "{" + + toJSonFieldDefinition("id", given.getId()) + "," + + toJSonFieldDefinition("reference", given.getReference()) + "," + + toJSonFieldDefinition("prefix", given.getPrefix()) + "," + + toJSonFieldDefinition("name", given.getName()) + + "}"; + assertEquals(expectedJSon, actual); + } + + @Test + public void testSerializationAsSupporter() throws JsonProcessingException { + + // given + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, null, Role.SUPPORTER); + CustomerDTO given = createSomeCustomerDTO(1234L); + + // when + String actual = objectMapper.writeValueAsString(given); + + // then + assertThat(actual).isEqualTo(createExpectedJSon(given)); + } + + @Test + public void testDeserializeAsContractualCustomerContact() throws IOException { + // given + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, 1234L, Role.CONTRACTUAL_CONTACT); + given(customerRepository.findById(1234L)).willReturn(Optional.of(new Customer().id(1234L))); + String json = "{\"id\":1234,\"contractualSalutation\":\"Hallo Updated\",\"billingSalutation\":\"Moin Updated\"}"; + + // when + CustomerDTO actual = objectMapper.readValue(json, CustomerDTO.class); + + // then + CustomerDTO expected = new CustomerDTO(); + expected.setId(1234L); + expected.setContractualSalutation("Hallo Updated"); + expected.setBillingSalutation("Moin Updated"); + assertThat(actual).isEqualToComparingFieldByField(expected); + } + + // --- only test fixture below --- + + private String createExpectedJSon(CustomerDTO dto) { + String json = // the fields in alphanumeric order: + toJSonFieldDefinitionIfPresent("id", dto.getId()) + + toJSonFieldDefinitionIfPresent("reference", dto.getReference()) + + toJSonFieldDefinitionIfPresent("prefix", dto.getPrefix()) + + toJSonFieldDefinitionIfPresent("name", dto.getName()) + + toJSonFieldDefinitionIfPresent("kind", "LEGAL") + + toJSonNullFieldDefinition("birthDate") + + toJSonNullFieldDefinition("birthPlace") + + toJSonFieldDefinitionIfPresent("registrationCourt", "Registergericht") + + toJSonFieldDefinitionIfPresent("registrationNumber", "Registernummer") + + toJSonFieldDefinitionIfPresent("vatRegion", "DOMESTIC") + + toJSonFieldDefinitionIfPresent("vatNumber", "DE1234") + + toJSonFieldDefinitionIfPresent("contractualSalutation", dto.getContractualSalutation()) + + toJSonFieldDefinitionIfPresent("contractualAddress", dto.getContractualAddress()) + + toJSonFieldDefinitionIfPresent("billingSalutation", dto.getBillingSalutation()) + + toJSonFieldDefinitionIfPresent("billingAddress", dto.getBillingAddress()) + + toJSonFieldDefinitionIfPresent("remark", dto.getRemark()); + return "{" + json.substring(0, json.length() - 1) + "}"; + } + + + + private String toJSonFieldDefinition(String name, String value) { + return inQuotes(name) + ":" + (value != null ? inQuotes(value) : "null"); + } + + private String toJSonFieldDefinition(String name, Number value) { + return inQuotes(name) + ":" + (value != null ? value : "null"); + } + + private String toJSonNullFieldDefinition(String name) { + return inQuotes(name) + ":null,"; + } + + private String toJSonFieldDefinitionIfPresent(String name, String value) { + return value != null ? inQuotes(name) + ":" + inQuotes(value) + "," : ""; + } + + private String toJSonFieldDefinitionIfPresent(String name, Number value) { + return value != null ? inQuotes(name) + ":" + value + "," : ""; + } + + private String inQuotes(Object value) { + return "\"" + value.toString() + "\""; + } + + private CustomerDTO createSomeCustomerDTO(final long id) { + final CustomerDTO given = new CustomerDTO(); + given.setId(id); + given.setReference(10001); + given.setPrefix("abc"); + given.setName("Mein Name"); + given.setKind(CustomerKind.LEGAL); + given.setRegistrationCourt("Registergericht"); + given.setRegistrationNumber("Registernummer"); + given.setVatRegion(VatRegion.DOMESTIC); + given.setVatNumber("DE1234"); + given.setContractualAddress("Eine Adresse"); + given.setContractualSalutation("Hallo"); + given.setBillingAddress("Noch eine Adresse"); + given.setBillingSalutation("Moin"); + given.setRemark("Eine Bemerkung"); + return given; + } +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/MembershipDTOUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/dto/MembershipDTOUnitTest.java new file mode 100644 index 00000000..90171bed --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/MembershipDTOUnitTest.java @@ -0,0 +1,105 @@ +package org.hostsharing.hsadminng.service.dto; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.MembershipService; +import org.hostsharing.hsadminng.service.accessfilter.JSonDeserializerWithAccessFilter; +import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; + +import java.io.IOException; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.hostsharing.hsadminng.service.accessfilter.JSonBuilder.asJSon; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole; +import static org.mockito.BDDMockito.given; + +public class MembershipDTOUnitTest { + + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private ApplicationContext ctx; + + @Mock + private AutowireCapableBeanFactory autowireCapableBeanFactory; + + @Mock + private JsonParser jsonParser; + + @Mock + private ObjectCodec codec; + + @Mock + private TreeNode treeNode; + + @Mock + private MembershipService membershipService; + + @Mock + private CustomerService customerService; + + @Before + public void init() { + given(jsonParser.getCodec()).willReturn(codec); + + given (ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory); + given(autowireCapableBeanFactory.createBean(MembershipService.class)).willReturn(membershipService); + given(autowireCapableBeanFactory.createBean(CustomerService.class)).willReturn(customerService); + given(customerService.findOne(1234L)).willReturn(Optional.of(new CustomerDTO() + .with(dto -> dto.setId(1234L)) + )); + } + + @Test + public void adminShouldHaveRightToCreate() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(null, null, Role.ADMIN); + givenJSonTree(asJSon(ImmutablePair.of("customerId", 1234L))); + + // when + final MembershipDTO actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, MembershipDTO.class).deserialize(); + + // then + assertThat(actualDto.getCustomerId()).isEqualTo(1234L); + } + + @Test + public void contractualContactShouldNotHaveRightToCreate() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, 1234L, Role.CONTRACTUAL_CONTACT); + givenJSonTree(asJSon(ImmutablePair.of("customerId", 1234L))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, MembershipDTO.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("MembershipDTO.customerId"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("referencingProhibited"); + }); + } + + // --- only fixture code below --- + + private void givenJSonTree(String givenJSon) throws IOException { + given(codec.readTree(jsonParser)).willReturn(new ObjectMapper().readTree(givenJSon)); + } + +} diff --git a/src/test/java/org/hostsharing/hsadminng/service/dto/ShareDTOUnitTest.java b/src/test/java/org/hostsharing/hsadminng/service/dto/ShareDTOUnitTest.java new file mode 100644 index 00000000..b9346faf --- /dev/null +++ b/src/test/java/org/hostsharing/hsadminng/service/dto/ShareDTOUnitTest.java @@ -0,0 +1,163 @@ +package org.hostsharing.hsadminng.service.dto; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.core.TreeNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.hostsharing.hsadminng.domain.enumeration.ShareAction; +import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.MembershipService; +import org.hostsharing.hsadminng.service.accessfilter.JSonDeserializerWithAccessFilter; +import org.hostsharing.hsadminng.service.accessfilter.JSonSerializerWithAccessFilter; +import org.hostsharing.hsadminng.service.accessfilter.Role; +import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.springframework.beans.factory.config.AutowireCapableBeanFactory; +import org.springframework.context.ApplicationContext; + +import java.io.IOException; +import java.time.LocalDate; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.hostsharing.hsadminng.service.accessfilter.JSonBuilder.asJSon; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +public class ShareDTOUnitTest { + + private static final long SOME_MEMBERSHIP_ID = 12345L; + private static final long SOME_CUSTOMER_ID = 1234L; + + @Rule + public MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private ApplicationContext ctx; + + @Mock + private AutowireCapableBeanFactory autowireCapableBeanFactory; + + @Mock + private JsonParser jsonParser; + + @Mock + private JsonGenerator jsonGenerator; + + @Mock + private ObjectCodec codec; + + @Mock + private TreeNode treeNode; + + @Mock + private CustomerService customerService; + + @Mock + private MembershipService membershipService; + + @Before + public void init() { + given(jsonParser.getCodec()).willReturn(codec); + + given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory); + given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory); + given(autowireCapableBeanFactory.createBean(CustomerService.class)).willReturn(customerService); + given(autowireCapableBeanFactory.createBean(MembershipService.class)).willReturn(membershipService); + + given(customerService.findOne(SOME_CUSTOMER_ID)).willReturn(Optional.of(new CustomerDTO())); + given(membershipService.findOne(SOME_MEMBERSHIP_ID)).willReturn(Optional.of(new MembershipDTO().with(dto -> dto.setCustomerId(SOME_CUSTOMER_ID)))); + } + + @Test + public void adminShouldHaveRightToCreate() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(null, null, Role.ADMIN); + givenJSonTree(asJSon(ImmutablePair.of("membershipId", SOME_MEMBERSHIP_ID))); + + // when + final ShareDTO actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, ShareDTO.class).deserialize(); + + // then + assertThat(actualDto.getMembershipId()).isEqualTo(SOME_MEMBERSHIP_ID); + } + + @Test + public void contractualContactShouldNotHaveRightToCreate() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.CONTRACTUAL_CONTACT); + givenJSonTree(asJSon(ImmutablePair.of("membershipId", ShareDTOUnitTest.SOME_MEMBERSHIP_ID))); + + // when + Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, ShareDTO.class).deserialize()); + + // then + assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> { + assertThat(badRequestAlertException.getParam()).isEqualTo("ShareDTO.membershipId"); + assertThat(badRequestAlertException.getErrorKey()).isEqualTo("referencingProhibited"); + }); + } + + @Test + public void financialContactShouldHaveRightToReadAllButRemark() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.FINANCIAL_CONTACT); + final ShareDTO givenDTO = createShareDto(); + + // when + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize(); + + // then + verify(jsonGenerator).writeNumberField("id", givenDTO.getId()); + verify(jsonGenerator).writeNumberField("membershipId", givenDTO.getMembershipId()); + verify(jsonGenerator, never()).writeStringField(eq("remark"), anyString()); + } + + @Test + public void supporterShouldHaveRightToRead() throws IOException { + givenAuthenticatedUser(); + givenUserHavingRole(null, null, Role.SUPPORTER); + final ShareDTO givenDTO = createShareDto(); + + // when + new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize(); + + // then + verify(jsonGenerator).writeNumberField("id", givenDTO.getId()); + verify(jsonGenerator).writeNumberField("membershipId", givenDTO.getMembershipId()); + verify(jsonGenerator).writeStringField("remark", givenDTO.getRemark()); + } + + // --- only fixture code below --- + + private void givenJSonTree(String givenJSon) throws IOException { + given(codec.readTree(jsonParser)).willReturn(new ObjectMapper().readTree(givenJSon)); + } + + private ShareDTO createShareDto() { + final ShareDTO givenDTO = new ShareDTO(); + givenDTO.setId(1234567L); + givenDTO.setMembershipId(SOME_MEMBERSHIP_ID); + givenDTO.setAction(ShareAction.SUBSCRIPTION); + givenDTO.setQuantity(3); + givenDTO.setDocumentDate(LocalDate.parse("2019-04-22")); + givenDTO.setMembershipDisplayReference("2019-04-21"); // TODO: why is this not a LocalDate? + givenDTO.setValueDate(LocalDate.parse("2019-04-30")); + givenDTO.setRemark("Some Remark"); + return givenDTO; + } + +} diff --git a/src/test/java/org/hostsharing/hsadminng/web/rest/AssetResourceIntTest.java b/src/test/java/org/hostsharing/hsadminng/web/rest/AssetResourceIntTest.java index de3cbaf3..ae7212be 100644 --- a/src/test/java/org/hostsharing/hsadminng/web/rest/AssetResourceIntTest.java +++ b/src/test/java/org/hostsharing/hsadminng/web/rest/AssetResourceIntTest.java @@ -1,17 +1,15 @@ package org.hostsharing.hsadminng.web.rest; import org.hostsharing.hsadminng.HsadminNgApp; - import org.hostsharing.hsadminng.domain.Asset; import org.hostsharing.hsadminng.domain.Membership; +import org.hostsharing.hsadminng.domain.enumeration.AssetAction; import org.hostsharing.hsadminng.repository.AssetRepository; +import org.hostsharing.hsadminng.service.AssetQueryService; import org.hostsharing.hsadminng.service.AssetService; import org.hostsharing.hsadminng.service.dto.AssetDTO; import org.hostsharing.hsadminng.service.mapper.AssetMapper; import org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator; -import org.hostsharing.hsadminng.service.dto.AssetCriteria; -import org.hostsharing.hsadminng.service.AssetQueryService; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,14 +31,11 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.List; - -import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasItem; +import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -import org.hostsharing.hsadminng.domain.enumeration.AssetAction; /** * Test class for the AssetResource REST controller. * diff --git a/src/test/java/org/hostsharing/hsadminng/web/rest/CustomerResourceIntTest.java b/src/test/java/org/hostsharing/hsadminng/web/rest/CustomerResourceIntTest.java index 329190ee..e63024a2 100644 --- a/src/test/java/org/hostsharing/hsadminng/web/rest/CustomerResourceIntTest.java +++ b/src/test/java/org/hostsharing/hsadminng/web/rest/CustomerResourceIntTest.java @@ -1,18 +1,18 @@ package org.hostsharing.hsadminng.web.rest; import org.hostsharing.hsadminng.HsadminNgApp; - import org.hostsharing.hsadminng.domain.Customer; import org.hostsharing.hsadminng.domain.Membership; import org.hostsharing.hsadminng.domain.SepaMandate; +import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; +import org.hostsharing.hsadminng.domain.enumeration.VatRegion; import org.hostsharing.hsadminng.repository.CustomerRepository; +import org.hostsharing.hsadminng.service.CustomerQueryService; import org.hostsharing.hsadminng.service.CustomerService; +import org.hostsharing.hsadminng.service.accessfilter.Role; import org.hostsharing.hsadminng.service.dto.CustomerDTO; import org.hostsharing.hsadminng.service.mapper.CustomerMapper; import org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator; -import org.hostsharing.hsadminng.service.dto.CustomerCriteria; -import org.hostsharing.hsadminng.service.CustomerQueryService; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,15 +33,14 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.List; - -import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasItem; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser; +import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole; +import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; -import org.hostsharing.hsadminng.domain.enumeration.CustomerKind; -import org.hostsharing.hsadminng.domain.enumeration.VatRegion; /** * Test class for the CustomerResource REST controller. * @@ -138,6 +137,10 @@ public class CustomerResourceIntTest { @Before public void setup() { MockitoAnnotations.initMocks(this); + + givenAuthenticatedUser(); + givenUserHavingRole(Role.ADMIN); + final CustomerResource customerResource = new CustomerResource(customerService, customerQueryService); this.restCustomerMockMvc = MockMvcBuilders.standaloneSetup(customerResource) .setCustomArgumentResolvers(pageableArgumentResolver) @@ -149,7 +152,7 @@ public class CustomerResourceIntTest { /** * Create an entity for this test. - * + *

* This is a static method, as tests for other entities might also need it, * if they test an entity which requires the current entity. */ @@ -175,7 +178,7 @@ public class CustomerResourceIntTest { /** * Create another entity for tests. - * + *

* This is a static method, as tests for other entities might also need it, * if they test an entity which requires the current entity. */ @@ -377,22 +380,22 @@ public class CustomerResourceIntTest { .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)) .andExpect(jsonPath("$.[*].id").value(hasItem(customer.getId().intValue()))) .andExpect(jsonPath("$.[*].reference").value(hasItem(DEFAULT_REFERENCE))) - .andExpect(jsonPath("$.[*].prefix").value(hasItem(DEFAULT_PREFIX.toString()))) - .andExpect(jsonPath("$.[*].name").value(hasItem(DEFAULT_NAME.toString()))) + .andExpect(jsonPath("$.[*].prefix").value(hasItem(DEFAULT_PREFIX))) + .andExpect(jsonPath("$.[*].name").value(hasItem(DEFAULT_NAME))) .andExpect(jsonPath("$.[*].kind").value(hasItem(DEFAULT_KIND.toString()))) .andExpect(jsonPath("$.[*].birthDate").value(hasItem(DEFAULT_BIRTH_DATE.toString()))) - .andExpect(jsonPath("$.[*].birthPlace").value(hasItem(DEFAULT_BIRTH_PLACE.toString()))) - .andExpect(jsonPath("$.[*].registrationCourt").value(hasItem(DEFAULT_REGISTRATION_COURT.toString()))) - .andExpect(jsonPath("$.[*].registrationNumber").value(hasItem(DEFAULT_REGISTRATION_NUMBER.toString()))) + .andExpect(jsonPath("$.[*].birthPlace").value(hasItem(DEFAULT_BIRTH_PLACE))) + .andExpect(jsonPath("$.[*].registrationCourt").value(hasItem(DEFAULT_REGISTRATION_COURT))) + .andExpect(jsonPath("$.[*].registrationNumber").value(hasItem(DEFAULT_REGISTRATION_NUMBER))) .andExpect(jsonPath("$.[*].vatRegion").value(hasItem(DEFAULT_VAT_REGION.toString()))) - .andExpect(jsonPath("$.[*].vatNumber").value(hasItem(DEFAULT_VAT_NUMBER.toString()))) - .andExpect(jsonPath("$.[*].contractualSalutation").value(hasItem(DEFAULT_CONTRACTUAL_SALUTATION.toString()))) - .andExpect(jsonPath("$.[*].contractualAddress").value(hasItem(DEFAULT_CONTRACTUAL_ADDRESS.toString()))) - .andExpect(jsonPath("$.[*].billingSalutation").value(hasItem(DEFAULT_BILLING_SALUTATION.toString()))) - .andExpect(jsonPath("$.[*].billingAddress").value(hasItem(DEFAULT_BILLING_ADDRESS.toString()))) - .andExpect(jsonPath("$.[*].remark").value(hasItem(DEFAULT_REMARK.toString()))); + .andExpect(jsonPath("$.[*].vatNumber").value(hasItem(DEFAULT_VAT_NUMBER))) + .andExpect(jsonPath("$.[*].contractualSalutation").value(hasItem(DEFAULT_CONTRACTUAL_SALUTATION))) + .andExpect(jsonPath("$.[*].contractualAddress").value(hasItem(DEFAULT_CONTRACTUAL_ADDRESS))) + .andExpect(jsonPath("$.[*].billingSalutation").value(hasItem(DEFAULT_BILLING_SALUTATION))) + .andExpect(jsonPath("$.[*].billingAddress").value(hasItem(DEFAULT_BILLING_ADDRESS))) + .andExpect(jsonPath("$.[*].remark").value(hasItem(DEFAULT_REMARK))); } - + @Test @Transactional public void getCustomer() throws Exception { @@ -1167,8 +1170,8 @@ public class CustomerResourceIntTest { // Disconnect from session so that the updates on updatedCustomer are not directly saved in db em.detach(updatedCustomer); updatedCustomer - .reference(UPDATED_REFERENCE) - .prefix(UPDATED_PREFIX) + .reference(null) + .prefix(null) .name(UPDATED_NAME) .kind(UPDATED_KIND) .birthDate(UPDATED_BIRTH_DATE) @@ -1193,8 +1196,8 @@ public class CustomerResourceIntTest { List customerList = customerRepository.findAll(); assertThat(customerList).hasSize(databaseSizeBeforeUpdate); Customer testCustomer = customerList.get(customerList.size() - 1); - assertThat(testCustomer.getReference()).isEqualTo(UPDATED_REFERENCE); - assertThat(testCustomer.getPrefix()).isEqualTo(UPDATED_PREFIX); + assertThat(testCustomer.getReference()).isEqualTo(DEFAULT_REFERENCE); + assertThat(testCustomer.getPrefix()).isEqualTo(DEFAULT_PREFIX); assertThat(testCustomer.getName()).isEqualTo(UPDATED_NAME); assertThat(testCustomer.getKind()).isEqualTo(UPDATED_KIND); assertThat(testCustomer.getBirthDate()).isEqualTo(UPDATED_BIRTH_DATE); diff --git a/src/test/java/org/hostsharing/hsadminng/web/rest/MembershipResourceIntTest.java b/src/test/java/org/hostsharing/hsadminng/web/rest/MembershipResourceIntTest.java index 579372c8..b85b8ffc 100644 --- a/src/test/java/org/hostsharing/hsadminng/web/rest/MembershipResourceIntTest.java +++ b/src/test/java/org/hostsharing/hsadminng/web/rest/MembershipResourceIntTest.java @@ -7,12 +7,10 @@ import org.hostsharing.hsadminng.domain.Membership; import org.hostsharing.hsadminng.domain.Share; import org.hostsharing.hsadminng.repository.MembershipRepository; import org.hostsharing.hsadminng.service.MembershipQueryService; - import org.hostsharing.hsadminng.service.MembershipService; import org.hostsharing.hsadminng.service.dto.MembershipDTO; import org.hostsharing.hsadminng.service.mapper.MembershipMapper; import org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,10 +34,6 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; - - -import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.Matchers.hasItem; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; diff --git a/src/test/java/org/hostsharing/hsadminng/web/rest/SepaMandateResourceIntTest.java b/src/test/java/org/hostsharing/hsadminng/web/rest/SepaMandateResourceIntTest.java index 899cd0c5..916a8c27 100644 --- a/src/test/java/org/hostsharing/hsadminng/web/rest/SepaMandateResourceIntTest.java +++ b/src/test/java/org/hostsharing/hsadminng/web/rest/SepaMandateResourceIntTest.java @@ -1,16 +1,14 @@ package org.hostsharing.hsadminng.web.rest; import org.hostsharing.hsadminng.HsadminNgApp; - -import org.hostsharing.hsadminng.domain.SepaMandate; import org.hostsharing.hsadminng.domain.Customer; +import org.hostsharing.hsadminng.domain.SepaMandate; import org.hostsharing.hsadminng.repository.SepaMandateRepository; +import org.hostsharing.hsadminng.service.SepaMandateQueryService; import org.hostsharing.hsadminng.service.SepaMandateService; import org.hostsharing.hsadminng.service.dto.SepaMandateDTO; import org.hostsharing.hsadminng.service.mapper.SepaMandateMapper; import org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator; -import org.hostsharing.hsadminng.service.SepaMandateQueryService; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,10 +29,9 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.List; - -import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasItem; +import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; diff --git a/src/test/java/org/hostsharing/hsadminng/web/rest/ShareResourceIntTest.java b/src/test/java/org/hostsharing/hsadminng/web/rest/ShareResourceIntTest.java index ab2dbae8..eacbe431 100644 --- a/src/test/java/org/hostsharing/hsadminng/web/rest/ShareResourceIntTest.java +++ b/src/test/java/org/hostsharing/hsadminng/web/rest/ShareResourceIntTest.java @@ -1,17 +1,15 @@ package org.hostsharing.hsadminng.web.rest; import org.hostsharing.hsadminng.HsadminNgApp; - -import org.hostsharing.hsadminng.domain.Share; import org.hostsharing.hsadminng.domain.Membership; +import org.hostsharing.hsadminng.domain.Share; +import org.hostsharing.hsadminng.domain.enumeration.ShareAction; import org.hostsharing.hsadminng.repository.ShareRepository; +import org.hostsharing.hsadminng.service.ShareQueryService; import org.hostsharing.hsadminng.service.ShareService; import org.hostsharing.hsadminng.service.dto.ShareDTO; import org.hostsharing.hsadminng.service.mapper.ShareMapper; import org.hostsharing.hsadminng.web.rest.errors.ExceptionTranslator; -import org.hostsharing.hsadminng.service.dto.ShareCriteria; -import org.hostsharing.hsadminng.service.ShareQueryService; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,14 +30,11 @@ import java.time.LocalDate; import java.time.ZoneId; import java.util.List; - -import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.hasItem; +import static org.hostsharing.hsadminng.web.rest.TestUtil.createFormattingConversionService; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; - -import org.hostsharing.hsadminng.domain.enumeration.ShareAction; /** * Test class for the ShareResource REST controller. * diff --git a/src/test/javascript/spec/app/entities/customer/customer.service.spec.ts b/src/test/javascript/spec/app/entities/customer/customer.service.spec.ts index 6bd1b1d1..6d717639 100644 --- a/src/test/javascript/spec/app/entities/customer/customer.service.spec.ts +++ b/src/test/javascript/spec/app/entities/customer/customer.service.spec.ts @@ -1,13 +1,11 @@ /* tslint:disable max-line-length */ -import { TestBed, getTestBed } from '@angular/core/testing'; +import { getTestBed, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { of } from 'rxjs'; -import { take, map } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import * as moment from 'moment'; import { DATE_FORMAT } from 'app/shared/constants/input.constants'; import { CustomerService } from 'app/entities/customer/customer.service'; -import { ICustomer, Customer, CustomerKind, VatRegion } from 'app/shared/model/customer.model'; +import { Customer, CustomerKind, ICustomer, VatRegion } from 'app/shared/model/customer.model'; describe('Service Tests', () => { describe('Customer Service', () => { diff --git a/src/test/javascript/spec/app/entities/membership/membership.service.spec.ts b/src/test/javascript/spec/app/entities/membership/membership.service.spec.ts index 52064002..1f5ced40 100644 --- a/src/test/javascript/spec/app/entities/membership/membership.service.spec.ts +++ b/src/test/javascript/spec/app/entities/membership/membership.service.spec.ts @@ -1,9 +1,7 @@ /* tslint:disable max-line-length */ -import { TestBed, getTestBed } from '@angular/core/testing'; +import { getTestBed, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { of } from 'rxjs'; -import { take, map } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import * as moment from 'moment'; import { DATE_FORMAT } from 'app/shared/constants/input.constants'; import { MembershipService } from 'app/entities/membership/membership.service'; diff --git a/src/test/javascript/spec/app/entities/sepa-mandate/sepa-mandate.service.spec.ts b/src/test/javascript/spec/app/entities/sepa-mandate/sepa-mandate.service.spec.ts index cbe6e89b..89b1dc0b 100644 --- a/src/test/javascript/spec/app/entities/sepa-mandate/sepa-mandate.service.spec.ts +++ b/src/test/javascript/spec/app/entities/sepa-mandate/sepa-mandate.service.spec.ts @@ -1,9 +1,7 @@ /* tslint:disable max-line-length */ -import { TestBed, getTestBed } from '@angular/core/testing'; +import { getTestBed, TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { of } from 'rxjs'; -import { take, map } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import * as moment from 'moment'; import { DATE_FORMAT } from 'app/shared/constants/input.constants'; import { SepaMandateService } from 'app/entities/sepa-mandate/sepa-mandate.service';