JSonAccessFilter with initially working (hardcoded) grand parent role
This commit is contained in:
parent
a94516b3ce
commit
639ea06243
@ -1,15 +1,12 @@
|
|||||||
package org.hostsharing.hsadminng.domain;
|
package org.hostsharing.hsadminng.domain;
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.*;
|
import javax.validation.constraints.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Customer.
|
* A Customer.
|
||||||
@ -65,13 +62,21 @@ public class Customer implements Serializable {
|
|||||||
|
|
||||||
@OneToMany(mappedBy = "customer")
|
@OneToMany(mappedBy = "customer")
|
||||||
private Set<Membership> memberships = new HashSet<>();
|
private Set<Membership> memberships = new HashSet<>();
|
||||||
|
|
||||||
@OneToMany(mappedBy = "customer")
|
@OneToMany(mappedBy = "customer")
|
||||||
private Set<SepaMandate> sepamandates = new HashSet<>();
|
private Set<SepaMandate> sepamandates = new HashSet<>();
|
||||||
|
|
||||||
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
|
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Customer id(long id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@ -229,6 +234,7 @@ public class Customer implements Serializable {
|
|||||||
public void setSepamandates(Set<SepaMandate> sepaMandates) {
|
public void setSepamandates(Set<SepaMandate> sepaMandates) {
|
||||||
this.sepamandates = sepaMandates;
|
this.sepamandates = sepaMandates;
|
||||||
}
|
}
|
||||||
|
|
||||||
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
|
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
package org.hostsharing.hsadminng.domain;
|
package org.hostsharing.hsadminng.domain;
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import javax.validation.constraints.*;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Membership.
|
* A Membership.
|
||||||
@ -46,18 +45,26 @@ public class Membership implements Serializable {
|
|||||||
|
|
||||||
@OneToMany(mappedBy = "membership")
|
@OneToMany(mappedBy = "membership")
|
||||||
private Set<Share> shares = new HashSet<>();
|
private Set<Share> shares = new HashSet<>();
|
||||||
|
|
||||||
@OneToMany(mappedBy = "membership")
|
@OneToMany(mappedBy = "membership")
|
||||||
private Set<Asset> assets = new HashSet<>();
|
private Set<Asset> assets = new HashSet<>();
|
||||||
|
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@NotNull
|
@NotNull
|
||||||
@JsonIgnoreProperties("memberships")
|
@JsonIgnoreProperties("memberships")
|
||||||
private Customer customer;
|
private Customer customer;
|
||||||
|
|
||||||
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
|
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Membership id(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public void setId(Long id) {
|
public void setId(Long id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
@ -176,6 +183,7 @@ public class Membership implements Serializable {
|
|||||||
public void setCustomer(Customer customer) {
|
public void setCustomer(Customer customer) {
|
||||||
this.customer = customer;
|
this.customer = customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
|
// jhipster-needle-entity-add-getters-setters - JHipster will add getters and setters here, do not remove
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,7 +6,6 @@ import org.hostsharing.hsadminng.service.dto.CustomerDTO;
|
|||||||
import org.hostsharing.hsadminng.service.mapper.CustomerMapper;
|
import org.hostsharing.hsadminng.service.mapper.CustomerMapper;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -19,7 +18,7 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
public class CustomerService {
|
public class CustomerService implements DtoLoader<CustomerDTO> {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(CustomerService.class);
|
private final Logger log = LoggerFactory.getLogger(CustomerService.class);
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.hostsharing.hsadminng.service;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface DtoLoader<T> {
|
||||||
|
Optional<? extends T> findOne(Long id);
|
||||||
|
}
|
@ -19,7 +19,7 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
public class MembershipService {
|
public class MembershipService implements DtoLoader<MembershipDTO> {
|
||||||
|
|
||||||
private final Logger log = LoggerFactory.getLogger(MembershipService.class);
|
private final Logger log = LoggerFactory.getLogger(MembershipService.class);
|
||||||
|
|
||||||
@ -73,6 +73,7 @@ public class MembershipService {
|
|||||||
* @param id the id of the entity
|
* @param id the id of the entity
|
||||||
* @return the entity
|
* @return the entity
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Optional<MembershipDTO> findOne(Long id) {
|
public Optional<MembershipDTO> findOne(Long id) {
|
||||||
log.debug("Request to get Membership : {}", id);
|
log.debug("Request to get Membership : {}", id);
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
package org.hostsharing.hsadminng.service.accessfilter;
|
package org.hostsharing.hsadminng.service.accessfilter;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.hostsharing.hsadminng.security.SecurityUtils;
|
import org.hostsharing.hsadminng.security.SecurityUtils;
|
||||||
|
import org.hostsharing.hsadminng.service.CustomerService;
|
||||||
|
import org.hostsharing.hsadminng.service.DtoLoader;
|
||||||
|
import org.hostsharing.hsadminng.service.MembershipService;
|
||||||
|
import org.hostsharing.hsadminng.service.dto.CustomerDTO;
|
||||||
|
import org.hostsharing.hsadminng.service.dto.MembershipDTO;
|
||||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
abstract class JSonAccessFilter<T> {
|
abstract class JSonAccessFilter<T> {
|
||||||
|
private final ApplicationContext ctx;
|
||||||
final T dto;
|
final T dto;
|
||||||
Field selfIdField = null;
|
final Field selfIdField;
|
||||||
Field parentIdField = null;
|
final Field parentIdField;
|
||||||
|
|
||||||
JSonAccessFilter(final T dto) {
|
JSonAccessFilter(final ApplicationContext ctx, final T dto) {
|
||||||
|
this.ctx = ctx;
|
||||||
this.dto = dto;
|
this.dto = dto;
|
||||||
determineIdFields();
|
this.selfIdField = determineFieldWithAnnotation(dto.getClass(), SelfId.class);
|
||||||
|
this.parentIdField = determineFieldWithAnnotation(dto.getClass(), ParentId.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
void determineIdFields() {
|
boolean isParentIdField(final Field field) {
|
||||||
for (Field field : dto.getClass().getDeclaredFields()) {
|
return field.equals(parentIdField);
|
||||||
if (field.isAnnotationPresent(SelfId.class)) {
|
|
||||||
if (selfIdField != null) {
|
|
||||||
throw new AssertionError("multiple @" + SelfId.class.getSimpleName() + " detected in " + field.getDeclaringClass().getSimpleName());
|
|
||||||
}
|
|
||||||
selfIdField = field;
|
|
||||||
}
|
|
||||||
if (field.isAnnotationPresent(ParentId.class)) {
|
|
||||||
if (parentIdField != null) {
|
|
||||||
throw new AssertionError("multiple @" + ParentId.class.getSimpleName() + " detected in " + field.getDeclaringClass().getSimpleName());
|
|
||||||
}
|
|
||||||
parentIdField = field;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Long getId() {
|
Long getId() {
|
||||||
@ -39,27 +37,68 @@ abstract class JSonAccessFilter<T> {
|
|||||||
return (Long) ReflectionUtil.getValue(dto, selfIdField);
|
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) {
|
String toDisplay(final Field field) {
|
||||||
return field.getDeclaringClass().getSimpleName() + "." + field.getName();
|
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() {
|
Role getLoginUserRole() {
|
||||||
final Role roleOnSelf = getLoginUserRoleOnSelf();
|
final Role roleOnSelf = getLoginUserRoleOnSelf();
|
||||||
final Role roleOnParent = getLoginUserRoleOnParent();
|
if ( roleOnSelf.isIndependent() ) {
|
||||||
return roleOnSelf.covers(roleOnParent) ? roleOnSelf : roleOnParent;
|
return roleOnSelf;
|
||||||
|
}
|
||||||
|
return getLoginUserRoleOnAncestorOfDtoClassIfHigher(roleOnSelf, dto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Role getLoginUserRoleOnSelf() {
|
private Role getLoginUserRoleOnSelf() {
|
||||||
// TODO: find broadest role in self and recursively in parent
|
|
||||||
return SecurityUtils.getLoginUserRoleFor(dto.getClass(), getId() );
|
return SecurityUtils.getLoginUserRoleFor(dto.getClass(), getId() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private Role getLoginUserRoleOnParent() {
|
private Role getLoginUserRoleOnAncestorOfDtoClassIfHigher(final Role baseRole, final Object dto) {
|
||||||
|
final Field parentIdField = determineFieldWithAnnotation(dto.getClass(), ParentId.class);
|
||||||
|
|
||||||
if ( parentIdField == null ) {
|
if ( parentIdField == null ) {
|
||||||
return Role.ANYBODY;
|
return baseRole;
|
||||||
}
|
}
|
||||||
final ParentId parentId = parentIdField.getAnnotation(ParentId.class);
|
|
||||||
return SecurityUtils.getLoginUserRoleFor(parentId.value(), (Long) ReflectionUtil.getValue(dto, parentIdField) );
|
final ParentId parentIdAnnot = parentIdField.getAnnotation(ParentId.class);
|
||||||
|
final Class<?> parentDtoClass = parentIdAnnot.value();
|
||||||
|
final Long parentId = (Long) ReflectionUtil.getValue(dto, parentIdField);
|
||||||
|
final Role roleOnParent = SecurityUtils.getLoginUserRoleFor(parentDtoClass, parentId);
|
||||||
|
|
||||||
|
final Object parentEntity = findParentDto(parentDtoClass, parentId);
|
||||||
|
return Role.broadest(baseRole, getLoginUserRoleOnAncestorOfDtoClassIfHigher(roleOnParent, parentEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object findParentDto(Class<?> parentDtoClass, Long parentId) {
|
||||||
|
// TODO: generalize, e.g. via "all beans that implement DtoLoader<CustomerDTO>
|
||||||
|
if ( parentDtoClass == MembershipDTO.class ) {
|
||||||
|
final DtoLoader<MembershipDTO> dtoLoader = ctx.getAutowireCapableBeanFactory().createBean(MembershipService.class);
|
||||||
|
return dtoLoader.findOne(parentId).get();
|
||||||
|
}
|
||||||
|
if ( parentDtoClass == CustomerDTO.class ) {
|
||||||
|
final DtoLoader<CustomerDTO> dtoLoader = ctx.getAutowireCapableBeanFactory().createBean(CustomerService.class);
|
||||||
|
return dtoLoader.findOne(parentId).get();
|
||||||
|
}
|
||||||
|
throw new NotImplementedException("no DtoLoader implemented for " + parentDtoClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Field determineFieldWithAnnotation(final Class<?> dtoClass, final Class<? extends Annotation> 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import com.fasterxml.jackson.databind.node.TextNode;
|
|||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
|
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -21,8 +22,8 @@ public class JSonDeserializerWithAccessFilter<T> extends JSonAccessFilter<T> {
|
|||||||
private final TreeNode treeNode;
|
private final TreeNode treeNode;
|
||||||
private final Set<Field> modifiedFields = new HashSet<>();
|
private final Set<Field> modifiedFields = new HashSet<>();
|
||||||
|
|
||||||
public JSonDeserializerWithAccessFilter(final JsonParser jsonParser, final DeserializationContext deserializationContext, Class<T> dtoClass) {
|
public JSonDeserializerWithAccessFilter(final ApplicationContext ctx, final JsonParser jsonParser, final DeserializationContext deserializationContext, Class<T> dtoClass) {
|
||||||
super(unchecked(dtoClass::newInstance));
|
super(ctx, unchecked(dtoClass::newInstance));
|
||||||
this.treeNode = unchecked(() -> jsonParser.getCodec().readTree(jsonParser));
|
this.treeNode = unchecked(() -> jsonParser.getCodec().readTree(jsonParser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,18 +4,21 @@ package org.hostsharing.hsadminng.service.accessfilter;
|
|||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
import org.apache.commons.lang3.NotImplementedException;
|
import org.apache.commons.lang3.NotImplementedException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
public class JSonSerializerWithAccessFilter <T> extends JSonAccessFilter<T> {
|
public class JSonSerializerWithAccessFilter <T> extends JSonAccessFilter<T> {
|
||||||
private final JsonGenerator jsonGenerator;
|
private final JsonGenerator jsonGenerator;
|
||||||
private final SerializerProvider serializerProvider;
|
private final SerializerProvider serializerProvider;
|
||||||
|
|
||||||
public JSonSerializerWithAccessFilter(final JsonGenerator jsonGenerator,
|
public JSonSerializerWithAccessFilter(final ApplicationContext ctx,
|
||||||
|
final JsonGenerator jsonGenerator,
|
||||||
final SerializerProvider serializerProvider,
|
final SerializerProvider serializerProvider,
|
||||||
final T dto) {
|
final T dto) {
|
||||||
super(dto);
|
super(ctx, dto);
|
||||||
this.jsonGenerator = jsonGenerator;
|
this.jsonGenerator = jsonGenerator;
|
||||||
this.serializerProvider = serializerProvider;
|
this.serializerProvider = serializerProvider;
|
||||||
}
|
}
|
||||||
@ -42,6 +45,10 @@ public class JSonSerializerWithAccessFilter <T> extends JSonAccessFilter<T> {
|
|||||||
jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
|
jsonGenerator.writeNumberField(fieldName, (int) get(dto, prop));
|
||||||
} else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
|
} else if (Long.class.isAssignableFrom(prop.getType()) || long.class.isAssignableFrom(prop.getType())) {
|
||||||
jsonGenerator.writeNumberField(fieldName, (long) get(dto, prop));
|
jsonGenerator.writeNumberField(fieldName, (long) get(dto, prop));
|
||||||
|
} else if (LocalDate.class.isAssignableFrom(prop.getType())) {
|
||||||
|
jsonGenerator.writeStringField(fieldName, get(dto, prop).toString()); // TODO proper format
|
||||||
|
} else if (Enum.class.isAssignableFrom(prop.getType())) {
|
||||||
|
jsonGenerator.writeStringField(fieldName, get(dto, prop).toString()); // TODO proper representation
|
||||||
} else if (String.class.isAssignableFrom(prop.getType())) {
|
} else if (String.class.isAssignableFrom(prop.getType())) {
|
||||||
jsonGenerator.writeStringField(fieldName, (String) get(dto, prop));
|
jsonGenerator.writeStringField(fieldName, (String) get(dto, prop));
|
||||||
} else {
|
} else {
|
||||||
|
@ -87,6 +87,26 @@ public enum Role {
|
|||||||
this.level = 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.
|
* Determines if the given role is covered by this role.
|
||||||
*
|
*
|
||||||
@ -163,5 +183,4 @@ public enum Role {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.JsonSerializer;
|
|||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||||
import org.springframework.boot.jackson.JsonComponent;
|
import org.springframework.boot.jackson.JsonComponent;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import javax.validation.constraints.*;
|
import javax.validation.constraints.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -172,24 +173,34 @@ public class CustomerDTO implements Serializable {
|
|||||||
@JsonComponent
|
@JsonComponent
|
||||||
public static class CustomerJsonSerializer extends JsonSerializer<CustomerDTO> {
|
public static class CustomerJsonSerializer extends JsonSerializer<CustomerDTO> {
|
||||||
|
|
||||||
|
private final ApplicationContext ctx;
|
||||||
|
|
||||||
|
public CustomerJsonSerializer(final ApplicationContext ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(final CustomerDTO customerDTO, final JsonGenerator jsonGenerator,
|
public void serialize(final CustomerDTO customerDTO, final JsonGenerator jsonGenerator,
|
||||||
final SerializerProvider serializerProvider) throws IOException {
|
final SerializerProvider serializerProvider) throws IOException {
|
||||||
|
|
||||||
new JSonSerializerWithAccessFilter<>(jsonGenerator, serializerProvider, customerDTO).serialize();
|
new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, serializerProvider, customerDTO).serialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
public static class CustomerJsonDeserializer extends JsonDeserializer<CustomerDTO> {
|
public static class CustomerJsonDeserializer extends JsonDeserializer<CustomerDTO> {
|
||||||
|
|
||||||
|
private final ApplicationContext ctx;
|
||||||
|
|
||||||
|
public CustomerJsonDeserializer(final ApplicationContext ctx) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CustomerDTO deserialize(final JsonParser jsonParser,
|
public CustomerDTO deserialize(final JsonParser jsonParser,
|
||||||
final DeserializationContext deserializationContext) {
|
final DeserializationContext deserializationContext) {
|
||||||
|
|
||||||
return new JSonDeserializerWithAccessFilter<>(jsonParser, deserializationContext, CustomerDTO.class).deserialize();
|
return new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, deserializationContext, CustomerDTO.class).deserialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,10 +37,10 @@ public class MembershipDTO implements Serializable {
|
|||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@ParentId(CustomerDTO.class)
|
@ParentId(CustomerDTO.class)
|
||||||
@AccessFor(init = Role.ADMIN, read = Role.SUPPORTER)
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Long customerId;
|
private Long customerId;
|
||||||
|
|
||||||
@AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private String customerPrefix;
|
private String customerPrefix;
|
||||||
|
|
||||||
public MembershipDTO with(
|
public MembershipDTO with(
|
||||||
|
@ -1,35 +1,51 @@
|
|||||||
package org.hostsharing.hsadminng.service.dto;
|
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.domain.enumeration.ShareAction;
|
||||||
|
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.
|
* A DTO for the Share entity.
|
||||||
*/
|
*/
|
||||||
public class ShareDTO implements Serializable {
|
public class ShareDTO implements Serializable {
|
||||||
|
|
||||||
|
@SelfId
|
||||||
|
@AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private LocalDate documentDate;
|
private LocalDate documentDate;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private LocalDate valueDate;
|
private LocalDate valueDate;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private ShareAction action;
|
private ShareAction action;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Integer quantity;
|
private Integer quantity;
|
||||||
|
|
||||||
@Size(max = 160)
|
@Size(max = 160)
|
||||||
|
@AccessFor(init = Role.ADMIN, read = Role.SUPPORTER)
|
||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
|
@ParentId(MembershipDTO.class)
|
||||||
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Long membershipId;
|
private Long membershipId;
|
||||||
|
|
||||||
|
@AccessFor(init = Role.ADMIN, read = Role.SUPPORTER)
|
||||||
private String membershipDocumentDate;
|
private String membershipDocumentDate;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
|
@ -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<String, Object>... properties) {
|
||||||
|
final StringBuilder json = new StringBuilder();
|
||||||
|
for (ImmutablePair<String, Object> 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.toString() + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -12,11 +12,13 @@ import org.junit.Test;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
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.givenAuthenticatedUser;
|
||||||
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole;
|
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
@ -27,6 +29,9 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
@Rule
|
@Rule
|
||||||
public MockitoRule mockitoRule = MockitoJUnit.rule();
|
public MockitoRule mockitoRule = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
public ApplicationContext ctx;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
public JsonParser jsonParser;
|
public JsonParser jsonParser;
|
||||||
|
|
||||||
@ -52,7 +57,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
ImmutablePair.of("openStringField", "String Value")));
|
ImmutablePair.of("openStringField", "String Value")));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize();
|
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actualDto.openStringField).isEqualTo("String Value");
|
assertThat(actualDto.openStringField).isEqualTo("String Value");
|
||||||
@ -66,7 +71,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
ImmutablePair.of("openIntegerField", 1234)));
|
ImmutablePair.of("openIntegerField", 1234)));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize();
|
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actualDto.openIntegerField).isEqualTo(1234);
|
assertThat(actualDto.openIntegerField).isEqualTo(1234);
|
||||||
@ -80,7 +85,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
ImmutablePair.of("openLongField", 1234L)));
|
ImmutablePair.of("openLongField", 1234L)));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize();
|
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actualDto.openLongField).isEqualTo(1234L);
|
assertThat(actualDto.openLongField).isEqualTo(1234L);
|
||||||
@ -96,7 +101,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
ImmutablePair.of("restrictedField", "Restricted String Value")));
|
ImmutablePair.of("restrictedField", "Restricted String Value")));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize();
|
GivenDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actualDto.restrictedField).isEqualTo("Restricted String Value");
|
assertThat(actualDto.restrictedField).isEqualTo("Restricted String Value");
|
||||||
@ -110,7 +115,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
givenJSonTree(asJSon(ImmutablePair.of("restrictedField", "Restricted String Value")));
|
givenJSonTree(asJSon(ImmutablePair.of("restrictedField", "Restricted String Value")));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize());
|
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
||||||
@ -127,7 +132,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
givenJSonTree(asJSon(ImmutablePair.of("parentId", 1111L)));
|
givenJSonTree(asJSon(ImmutablePair.of("parentId", 1111L)));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenChildDto.class).deserialize());
|
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenChildDto.class).deserialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
||||||
@ -144,7 +149,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
givenJSonTree(asJSon(ImmutablePair.of("parentId", 1111L)));
|
givenJSonTree(asJSon(ImmutablePair.of("parentId", 1111L)));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
final GivenChildDto actualDto = new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenChildDto.class).deserialize();
|
final GivenChildDto actualDto = new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenChildDto.class).deserialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actualDto.parentId).isEqualTo(1111L);
|
assertThat(actualDto.parentId).isEqualTo(1111L);
|
||||||
@ -160,7 +165,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
ImmutablePair.of("restrictedField", "Restricted String Value")));
|
ImmutablePair.of("restrictedField", "Restricted String Value")));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDto.class).deserialize());
|
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDto.class).deserialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
assertThat(exception).isInstanceOfSatisfying(BadRequestAlertException.class, badRequestAlertException -> {
|
||||||
@ -175,7 +180,7 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
givenJSonTree(asJSon(ImmutablePair.of("id", 1111L)));
|
givenJSonTree(asJSon(ImmutablePair.of("id", 1111L)));
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(jsonParser, null, GivenDtoWithMultipleSelfId.class).deserialize());
|
Throwable exception = catchThrowable(() -> new JSonDeserializerWithAccessFilter<>(ctx, jsonParser, null, GivenDtoWithMultipleSelfId.class).deserialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(exception).isInstanceOf(AssertionError.class).hasMessage("multiple @SelfId detected in GivenDtoWithMultipleSelfId");
|
assertThat(exception).isInstanceOf(AssertionError.class).hasMessage("multiple @SelfId detected in GivenDtoWithMultipleSelfId");
|
||||||
@ -183,30 +188,10 @@ public class JSonDeserializerWithAccessFilterUnitTest {
|
|||||||
|
|
||||||
// --- only fixture code below ---
|
// --- only fixture code below ---
|
||||||
|
|
||||||
@SafeVarargs
|
|
||||||
private final String asJSon(final ImmutablePair<String, Object>... properties) {
|
|
||||||
final StringBuilder json = new StringBuilder();
|
|
||||||
for (ImmutablePair<String, Object> 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 void givenJSonTree(String givenJSon) throws IOException {
|
private void givenJSonTree(String givenJSon) throws IOException {
|
||||||
given(codec.readTree(jsonParser)).willReturn(new ObjectMapper().readTree(givenJSon));
|
given(codec.readTree(jsonParser)).willReturn(new ObjectMapper().readTree(givenJSon));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String inQuotes(Object value) {
|
|
||||||
return "\"" + value.toString() + "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class GivenDto {
|
public static class GivenDto {
|
||||||
|
|
||||||
@SelfId
|
@SelfId
|
||||||
|
@ -10,6 +10,7 @@ import org.junit.Test;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.MockitoJUnit;
|
import org.mockito.junit.MockitoJUnit;
|
||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@ -23,6 +24,9 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
@Rule
|
@Rule
|
||||||
public MockitoRule mockitoRule = MockitoJUnit.rule();
|
public MockitoRule mockitoRule = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
public ApplicationContext ctx;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
public JsonGenerator jsonGenerator;
|
public JsonGenerator jsonGenerator;
|
||||||
|
|
||||||
@ -37,7 +41,7 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldSerializeStringField() throws IOException {
|
public void shouldSerializeStringField() throws IOException {
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField);
|
verify(jsonGenerator).writeStringField("openStringField", givenDTO.openStringField);
|
||||||
@ -51,7 +55,7 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.FINANCIAL_CONTACT);
|
MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.FINANCIAL_CONTACT);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField);
|
verify(jsonGenerator).writeStringField("restrictedField", givenDTO.restrictedField);
|
||||||
@ -65,7 +69,7 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.ANY_CUSTOMER_USER);
|
MockSecurityContext.givenUserHavingRole(GivenCustomerDto.class, 888L, Role.ANY_CUSTOMER_USER);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDTO).serialize();
|
new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDTO).serialize();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField);
|
verify(jsonGenerator, never()).writeStringField("restrictedField", givenDTO.restrictedField);
|
||||||
@ -84,7 +88,7 @@ public class JSonSerializerWithAccessFilterUnitTest {
|
|||||||
final GivenDtoWithUnimplementedFieldType givenDtoWithUnimplementedFieldType = new GivenDtoWithUnimplementedFieldType();
|
final GivenDtoWithUnimplementedFieldType givenDtoWithUnimplementedFieldType = new GivenDtoWithUnimplementedFieldType();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter<>(jsonGenerator, null, givenDtoWithUnimplementedFieldType).serialize());
|
final Throwable actual = catchThrowable(() -> new JSonSerializerWithAccessFilter<>(ctx, jsonGenerator, null, givenDtoWithUnimplementedFieldType).serialize());
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(actual).isInstanceOf(NotImplementedException.class);
|
assertThat(actual).isInstanceOf(NotImplementedException.class);
|
||||||
|
@ -19,6 +19,9 @@ public class MockSecurityContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void givenUserHavingRole(final Class<?> onClass, final Long onId, final Role role) {
|
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 + " depend on DtoClass and ID");
|
||||||
|
}
|
||||||
SecurityUtils.addUserRole(onClass, onId, role);
|
SecurityUtils.addUserRole(onClass, onId, role);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,85 @@
|
|||||||
|
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.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.context.ApplicationContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
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
|
||||||
|
public ApplicationContext ctx;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
public JsonParser jsonParser;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
public ObjectCodec codec;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
public TreeNode treeNode;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
given(jsonParser.getCodec()).willReturn(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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.setMembershipDocumentDate("2019-04-21"); // TODO: why is this not a LocalDate?
|
||||||
|
givenDTO.setValueDate(LocalDate.parse("2019-04-30"));
|
||||||
|
givenDTO.setRemark("Some Remark");
|
||||||
|
return givenDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user