#145 [Rights-Module] preparation for module specific roles
This commit is contained in:
parent
7983aa7e52
commit
7db2c23de1
@ -1,22 +1,25 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.domain;
|
||||
|
||||
import org.hostsharing.hsadminng.repository.UserRepository;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
|
||||
import org.hostsharing.hsadminng.repository.UserRepository;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.Role.Admin;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.Role.Supporter;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.*;
|
||||
import static org.hostsharing.hsadminng.service.util.ReflectionUtil.of;
|
||||
|
||||
/**
|
||||
* A UserRoleAssignment.
|
||||
@ -24,41 +27,44 @@ import javax.validation.constraints.*;
|
||||
@Entity
|
||||
@Table(name = "user_role_assignment")
|
||||
@EntityTypeId(UserRoleAssignment.ENTITY_TYPE_ID)
|
||||
@JsonAutoDetect(
|
||||
fieldVisibility = JsonAutoDetect.Visibility.ANY,
|
||||
getterVisibility = JsonAutoDetect.Visibility.NONE,
|
||||
setterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
public class UserRoleAssignment implements AccessMappings {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String ENTITY_TYPE_ID = "rights.UserRoleAssignment";
|
||||
private static final String USER_FIELD_NAME = "user";
|
||||
|
||||
static final String USER_FIELD_NAME = "user";
|
||||
public static final String ENTITY_TYPE_ID = "rights.UserRoleAssignment";
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
|
||||
@SequenceGenerator(name = "sequenceGenerator")
|
||||
@SelfId(resolver = UserRoleAssignmentService.class)
|
||||
@AccessFor(read = Role.SUPPORTER)
|
||||
@AccessFor(read = Supporter.class)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 32)
|
||||
@Column(name = "entity_type_id", length = 32, nullable = false)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private String entityTypeId;
|
||||
|
||||
@NotNull
|
||||
@Column(name = "entity_object_id", nullable = false)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private Long entityObjectId;
|
||||
|
||||
@NotNull
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "assigned_role", nullable = false)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
private Role assignedRole;
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private String assignedRole;
|
||||
|
||||
@ManyToOne
|
||||
@JsonIgnoreProperties("requireds")
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private User user;
|
||||
|
||||
// jhipster-needle-entity-add-field - JHipster will add fields here, do not remove
|
||||
@ -103,16 +109,16 @@ public class UserRoleAssignment implements AccessMappings {
|
||||
}
|
||||
|
||||
public Role getAssignedRole() {
|
||||
return assignedRole;
|
||||
return assignedRole != null ? Role.of(assignedRole) : null;
|
||||
}
|
||||
|
||||
public UserRoleAssignment assignedRole(Role assignedRole) {
|
||||
this.assignedRole = assignedRole;
|
||||
this.assignedRole = of(assignedRole, Role::name);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setAssignedRole(Role assignedRole) {
|
||||
this.assignedRole = assignedRole;
|
||||
this.assignedRole = of(assignedRole, Role::name);
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
@ -154,9 +160,9 @@ public class UserRoleAssignment implements AccessMappings {
|
||||
public String toString() {
|
||||
return "UserRoleAssignment{" +
|
||||
"id=" + getId() +
|
||||
", entityTypeId='" + getEntityTypeId() + "'" +
|
||||
", entityObjectId=" + getEntityObjectId() +
|
||||
", assignedRole='" + getAssignedRole() + "'" +
|
||||
", entityTypeId='" + entityTypeId + "'" +
|
||||
", entityObjectId=" + entityObjectId +
|
||||
", assignedRole='" + assignedRole + "'" +
|
||||
"}";
|
||||
}
|
||||
|
||||
@ -172,9 +178,8 @@ public class UserRoleAssignment implements AccessMappings {
|
||||
@Override
|
||||
protected JSonFieldWriter<UserRoleAssignment> jsonFieldWriter(final Field field) {
|
||||
if (USER_FIELD_NAME.equals(field.getName())) {
|
||||
return (final UserRoleAssignment dto, final JsonGenerator jsonGenerator) -> {
|
||||
jsonGenerator.writeNumberField(USER_FIELD_NAME, dto.getUser().getId());
|
||||
};
|
||||
return (final UserRoleAssignment dto, final JsonGenerator jsonGenerator) -> jsonGenerator
|
||||
.writeNumberField(USER_FIELD_NAME, dto.getUser().getId());
|
||||
}
|
||||
return super.jsonFieldWriter(field);
|
||||
}
|
||||
@ -196,9 +201,8 @@ public class UserRoleAssignment implements AccessMappings {
|
||||
@Override
|
||||
protected JSonFieldReader<UserRoleAssignment> jsonFieldReader(final TreeNode treeNode, final Field field) {
|
||||
if ("user".equals(field.getName())) {
|
||||
return (final UserRoleAssignment target) -> {
|
||||
target.setUser(userRepository.getOne(getSubNode(treeNode, "id").asLong()));
|
||||
};
|
||||
return (final UserRoleAssignment target) -> target
|
||||
.setUser(userRepository.getOne(getSubNode(treeNode, "id").asLong()));
|
||||
}
|
||||
|
||||
return super.jsonFieldReader(treeNode, field);
|
||||
|
@ -1,6 +1,8 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.service.accessfilter;
|
||||
|
||||
import org.hostsharing.hsadminng.service.accessfilter.Role.Nobody;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Documented
|
||||
@ -8,9 +10,9 @@ import java.lang.annotation.*;
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AccessFor {
|
||||
|
||||
Role[] init() default Role.NOBODY;
|
||||
Class<? extends Role>[] init() default Nobody.class;
|
||||
|
||||
Role[] update() default Role.NOBODY;
|
||||
Class<? extends Role>[] update() default Nobody.class;
|
||||
|
||||
Role[] read() default Role.NOBODY;
|
||||
Class<? extends Role>[] read() default Nobody.class;
|
||||
}
|
||||
|
@ -1,27 +1,28 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.service.accessfilter;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static java.util.Collections.EMPTY_SET;
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
import org.hostsharing.hsadminng.security.SecurityUtils;
|
||||
import org.hostsharing.hsadminng.service.IdToDtoResolver;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
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 org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.collect.Sets.union;
|
||||
import static java.util.Collections.EMPTY_SET;
|
||||
import static java.util.Collections.emptySet;
|
||||
|
||||
abstract class JSonAccessFilter<T extends AccessMappings> {
|
||||
|
||||
private final ApplicationContext ctx;
|
||||
@ -58,11 +59,15 @@ abstract class JSonAccessFilter<T extends AccessMappings> {
|
||||
* @return all roles of the login user in relation to the dto, for which this filter is created.
|
||||
*/
|
||||
Set<Role> getLoginUserRoles() {
|
||||
final Set<Role> independentRoles = Arrays.stream(Role.values())
|
||||
.filter(
|
||||
role -> role.getAuthority()
|
||||
.map(authority -> SecurityUtils.isCurrentUserInRole(authority))
|
||||
.orElse(false))
|
||||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication == null) {
|
||||
return emptySet();
|
||||
}
|
||||
final Set<Role> independentRoles = authentication
|
||||
.getAuthorities()
|
||||
.stream()
|
||||
.map(GrantedAuthority::getAuthority)
|
||||
.map(Role::of)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
final Set<Role> rolesOnThis = getId() != null ? getLoginUserDirectRolesFor(dto.getClass(), getId()) : EMPTY_SET;
|
||||
@ -93,14 +98,10 @@ abstract class JSonAccessFilter<T extends AccessMappings> {
|
||||
}
|
||||
|
||||
private Set<Role> getLoginUserDirectRolesFor(final Class<?> dtoClass, final long id) {
|
||||
if (!SecurityUtils.isAuthenticated()) {
|
||||
return emptySet();
|
||||
}
|
||||
verify(SecurityUtils.isAuthenticated());
|
||||
|
||||
final EntityTypeId entityTypeId = dtoClass.getAnnotation(EntityTypeId.class);
|
||||
if (entityTypeId == null) {
|
||||
return emptySet();
|
||||
}
|
||||
verify(entityTypeId != null, "@" + EntityTypeId.class.getSimpleName() + " missing on " + dtoClass.getName());
|
||||
|
||||
return userRoleAssignmentService.getEffectiveRoleOfCurrentUser(entityTypeId.value(), id);
|
||||
}
|
||||
|
@ -1,13 +1,6 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.service.accessfilter;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static org.hostsharing.hsadminng.service.util.ReflectionUtil.unchecked;
|
||||
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
@ -15,9 +8,11 @@ import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.*;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
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;
|
||||
@ -26,6 +21,9 @@ import java.time.LocalDate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static org.hostsharing.hsadminng.service.util.ReflectionUtil.unchecked;
|
||||
|
||||
public abstract class JsonDeserializerWithAccessFilter<T extends AccessMappings> extends JsonDeserializer<T> {
|
||||
|
||||
private final ApplicationContext ctx;
|
||||
@ -85,31 +83,30 @@ public abstract class JsonDeserializerWithAccessFilter<T extends AccessMappings>
|
||||
|
||||
private Object readValueFromJSon(final TreeNode treeNode, final String fieldName, final Class<?> fieldClass) {
|
||||
// FIXME can be removed? final TreeNode fieldNode = treeNode.get(fieldName);
|
||||
final TreeNode fieldNode = treeNode;
|
||||
if (fieldNode instanceof NullNode) {
|
||||
if (treeNode instanceof NullNode) {
|
||||
return null;
|
||||
}
|
||||
if (fieldNode instanceof TextNode) {
|
||||
return ((TextNode) fieldNode).asText();
|
||||
if (treeNode instanceof TextNode) {
|
||||
return ((TextNode) treeNode).asText();
|
||||
}
|
||||
if (fieldNode instanceof IntNode) {
|
||||
return ((IntNode) fieldNode).asInt();
|
||||
if (treeNode instanceof IntNode) {
|
||||
return ((IntNode) treeNode).asInt();
|
||||
}
|
||||
if (fieldNode instanceof LongNode) {
|
||||
return ((LongNode) fieldNode).asLong();
|
||||
if (treeNode instanceof LongNode) {
|
||||
return ((LongNode) treeNode).asLong();
|
||||
}
|
||||
if (fieldNode instanceof DoubleNode) {
|
||||
if (treeNode instanceof DoubleNode) {
|
||||
// TODO: we need to figure out, why DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS does not work
|
||||
return ((DoubleNode) fieldNode).asDouble();
|
||||
return ((DoubleNode) treeNode).asDouble();
|
||||
}
|
||||
if (fieldNode instanceof ArrayNode && LocalDate.class.isAssignableFrom(fieldClass)) {
|
||||
if (treeNode instanceof ArrayNode && LocalDate.class.isAssignableFrom(fieldClass)) {
|
||||
return LocalDate.of(
|
||||
((ArrayNode) fieldNode).get(0).asInt(),
|
||||
((ArrayNode) fieldNode).get(1).asInt(),
|
||||
((ArrayNode) fieldNode).get(2).asInt());
|
||||
((ArrayNode) treeNode).get(0).asInt(),
|
||||
((ArrayNode) treeNode).get(1).asInt(),
|
||||
((ArrayNode) treeNode).get(2).asInt());
|
||||
}
|
||||
throw new NotImplementedException(
|
||||
"JSon node type not implemented: " + fieldNode.getClass() + " -> " + fieldName + ": " + fieldClass);
|
||||
"JSon node type not implemented: " + treeNode.getClass() + " -> " + fieldName + ": " + fieldClass);
|
||||
}
|
||||
|
||||
private void writeValueToDto(final T dto, final Field field, final Object value) {
|
||||
@ -223,25 +220,29 @@ public abstract class JsonDeserializerWithAccessFilter<T extends AccessMappings>
|
||||
throw new BadRequestAlertException(
|
||||
"Initialization of field " + toDisplay(field)
|
||||
+ " prohibited for current user role(s): "
|
||||
+ Joiner.on("+").join(roles),
|
||||
+ asString(roles),
|
||||
toDisplay(field),
|
||||
"initializationProhibited");
|
||||
} else {
|
||||
throw new BadRequestAlertException(
|
||||
"Referencing field " + toDisplay(field)
|
||||
+ " prohibited for current user role(s): "
|
||||
+ Joiner.on("+").join(roles),
|
||||
+ asString(roles),
|
||||
toDisplay(field),
|
||||
"referencingProhibited");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String asString(Set<Role> roles) {
|
||||
return Joiner.on("+").join(roles.stream().map(Role::name).toArray());
|
||||
}
|
||||
|
||||
private void validateUpdateAccess(Field field, Set<Role> roles) {
|
||||
if (!Role.toBeIgnoredForUpdates(field) && !isAllowedToUpdate(getLoginUserRoles(), field)) {
|
||||
throw new BadRequestAlertException(
|
||||
"Update of field " + toDisplay(field) + " prohibited for current user role(s): "
|
||||
+ Joiner.on("+").join(roles),
|
||||
+ asString(roles),
|
||||
toDisplay(field),
|
||||
"updateProhibited");
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.service.accessfilter;
|
||||
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -131,7 +129,7 @@ public abstract class JsonSerializerWithAccessFilter<T extends AccessMappings> e
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Role.ANYBODY.isAllowedToRead(field);
|
||||
return ReflectionUtil.newInstance(Role.Anybody.class).isAllowedToRead(field); // TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,35 +1,128 @@
|
||||
// Licensed under Apache-2.0
|
||||
package org.hostsharing.hsadminng.service.accessfilter;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.hostsharing.hsadminng.domain.Customer;
|
||||
import org.hostsharing.hsadminng.domain.User;
|
||||
import org.hostsharing.hsadminng.domain.UserRoleAssignment;
|
||||
import org.hostsharing.hsadminng.security.AuthoritiesConstants;
|
||||
import org.hostsharing.hsadminng.service.util.ReflectionUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Optional;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Verify.verify;
|
||||
import static org.hostsharing.hsadminng.service.util.ReflectionUtil.initialize;
|
||||
|
||||
/**
|
||||
* These enum values are used to specify the minimum role required to grant access to resources,
|
||||
* see usages of {@link AccessFor}.
|
||||
* also they can be assigned to users via {@link UserRoleAssignment}.
|
||||
* Also they can be assigned to users via {@link UserRoleAssignment}.
|
||||
* Some of the concrete values make only sense in one of these contexts.
|
||||
* <p>
|
||||
* Further, there are two kinds of roles: independent and dependent.
|
||||
* Independent roles like {@link #HOSTMASTER} are absolute roles which means unrelated to any concrete entity.
|
||||
* Dependent roles like {@link #CUSTOMER_CONTRACTUAL_CONTACT} are relative to a specific entity,
|
||||
* There are two kinds of roles: independent and dependent.
|
||||
* Independent roles like {@link Hostmaster} are absolute roles which means unrelated to any concrete entity.
|
||||
* Dependent roles like {@link CustomerContractualContact} are relative to a specific entity,
|
||||
* in this case to a specific {@link Customer}.
|
||||
* <p>
|
||||
* <p>
|
||||
* Separate classes are used to make it possible to use roles in Java annotations
|
||||
* and also make it possible to have roles spread over multiple modules.
|
||||
* </p>
|
||||
*/
|
||||
/*
|
||||
* 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 {
|
||||
public abstract class Role {
|
||||
|
||||
// TODO mhoennig: We need to make sure that the classes are loaded
|
||||
// and thus the static initializers were called
|
||||
// before these maps are used in production code.
|
||||
private static Map<Class<? extends Role>, Role> rolesByClass = new HashMap<>();
|
||||
private static Map<String, Role> rolesByName = new HashMap<>();
|
||||
|
||||
private final String authority;
|
||||
private final LazyRoles comprises;
|
||||
|
||||
Role() {
|
||||
this.authority = AuthoritiesConstants.USER;
|
||||
// noinspection unchecked
|
||||
this.comprises = new LazyRoles();
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
Role(final Class<? extends Role>... comprisedRoleClasses) {
|
||||
this.authority = AuthoritiesConstants.USER;
|
||||
// noinspection unchecked
|
||||
this.comprises = new LazyRoles(comprisedRoleClasses);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
Role(final String authority, final Class<? extends Role>... comprisedRoleClasses) {
|
||||
this.authority = authority;
|
||||
// noinspection unchecked
|
||||
this.comprises = new LazyRoles(comprisedRoleClasses);
|
||||
}
|
||||
|
||||
public static Role of(final String authority) {
|
||||
final Role role = rolesByName.get(authority);
|
||||
verify(
|
||||
role != null,
|
||||
"unknown authority: %s, available authorities: ",
|
||||
authority,
|
||||
ArrayUtils.toString(rolesByName.keySet()));
|
||||
return role;
|
||||
}
|
||||
|
||||
public static <T extends Role> T of(final Class<T> roleClass) {
|
||||
// prevent initialization and thus recursive call to `Role.of(...)` within `newInstance(...)`
|
||||
final Class<T> initializedRoleClass = initialize(roleClass);
|
||||
{
|
||||
final T role = (T) rolesByClass.get(initializedRoleClass);
|
||||
if (role != null) {
|
||||
return role;
|
||||
}
|
||||
}
|
||||
{
|
||||
T newRole = (T) ReflectionUtil.newInstance(initializedRoleClass);
|
||||
rolesByClass.put(initializedRoleClass, newRole);
|
||||
rolesByName.put(newRole.name(), newRole);
|
||||
return newRole;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + "(" + name() + ")";
|
||||
}
|
||||
|
||||
public abstract String name();
|
||||
|
||||
public static class IndependentRole extends Role {
|
||||
|
||||
@SafeVarargs
|
||||
IndependentRole(final String authority, final Class<? extends Role>... comprisedRoleClasses) {
|
||||
super(authority, comprisedRoleClasses);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return authority();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DependentRole extends Role {
|
||||
|
||||
DependentRole() {
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
DependentRole(final Class<? extends Role>... comprisedRoleClasses) {
|
||||
super(AuthoritiesConstants.USER, comprisedRoleClasses);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return getClass().getSimpleName(); // TODO: decide if it's ok for use in the DB table
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -37,31 +130,43 @@ public enum Role {
|
||||
* This role cannot be assigned to a user.
|
||||
* </p>
|
||||
*/
|
||||
NOBODY(0),
|
||||
public static class Nobody extends DependentRole {
|
||||
|
||||
public static final Nobody ROLE = Role.of(Nobody.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hostmasters are initialize/update/read and field which, except where NOBODY is allowed to.
|
||||
* <p>
|
||||
* This role can be assigned to a user via {@link User#setAuthorities}.
|
||||
* </p>
|
||||
*/
|
||||
HOSTMASTER(1, AuthoritiesConstants.HOSTMASTER),
|
||||
public static class Hostmaster extends IndependentRole {
|
||||
|
||||
/**
|
||||
* This role is for administrators, e.g. to create memberships and book shared and assets.
|
||||
* <p>
|
||||
* This role can be assigned to a user via {@link User#setAuthorities}.
|
||||
* </p>
|
||||
*/
|
||||
ADMIN(2, AuthoritiesConstants.ADMIN),
|
||||
/**
|
||||
* Hostmasters role to be assigned to users via via {@link User#setAuthorities}.
|
||||
*/
|
||||
public static final Hostmaster ROLE = Role.of(Hostmaster.class);
|
||||
|
||||
/**
|
||||
* This role is for members of the support team.
|
||||
* <p>
|
||||
* This role can be assigned to a user via {@link User#setAuthorities}.
|
||||
* </p>
|
||||
*/
|
||||
SUPPORTER(3, AuthoritiesConstants.SUPPORTER),
|
||||
Hostmaster() {
|
||||
super(AuthoritiesConstants.HOSTMASTER, Admin.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Admin extends IndependentRole {
|
||||
|
||||
public static final Admin ROLE = Role.of(Admin.class);
|
||||
|
||||
Admin() {
|
||||
super(AuthoritiesConstants.ADMIN, Supporter.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Supporter extends IndependentRole {
|
||||
|
||||
public static final Supporter ROLE = Role.of(Supporter.class);
|
||||
|
||||
Supporter() {
|
||||
super(AuthoritiesConstants.SUPPORTER, CustomerContractualContact.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This role is for contractual contacts of a customer, like a director of the company.
|
||||
@ -72,66 +177,76 @@ public enum Role {
|
||||
* This role can be assigned to a user via {@link UserRoleAssignment}.
|
||||
* </p>
|
||||
*/
|
||||
CUSTOMER_CONTRACTUAL_CONTACT(20),
|
||||
public static class CustomerContractualContact extends DependentRole {
|
||||
|
||||
/**
|
||||
* This role is for financial contacts of a customer, e.g. for accessing billing data.
|
||||
* <p>
|
||||
* The financial contact only covers {@link Role#CUSTOMER_FINANCIAL_CONTACT}, {@link Role#ANY_CUSTOMER_CONTACT} and
|
||||
* {@link Role#ANYBODY}, but not other <em>normal</em> user roles.
|
||||
* </p>
|
||||
* <p>
|
||||
* This role can be assigned to a user via {@link UserRoleAssignment}.
|
||||
* </p>
|
||||
*/
|
||||
CUSTOMER_FINANCIAL_CONTACT(22) {
|
||||
public static final CustomerContractualContact ROLE = Role.of(CustomerContractualContact.class);
|
||||
|
||||
@Override
|
||||
public boolean covers(final Role role) {
|
||||
return role == CUSTOMER_FINANCIAL_CONTACT || role == ANY_CUSTOMER_CONTACT || role == ANYBODY;
|
||||
CustomerContractualContact() {
|
||||
super(CustomerFinancialContact.class, CustomerTechnicalContact.class);
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* This role is for technical contacts of a customer.
|
||||
* <p>
|
||||
* This role can be assigned to a user via {@link UserRoleAssignment}.
|
||||
* </p>
|
||||
*/
|
||||
CUSTOMER_TECHNICAL_CONTACT(22),
|
||||
public static class CustomerFinancialContact extends DependentRole {
|
||||
|
||||
/**
|
||||
* This meta-role is to specify that any kind of customer contact can get access to the resource.
|
||||
* <p>
|
||||
* It's only used to specify the required role and cannot be assigned to a user.
|
||||
* </p>
|
||||
*/
|
||||
ANY_CUSTOMER_CONTACT(29),
|
||||
public static final CustomerFinancialContact ROLE = Role.of(CustomerFinancialContact.class);
|
||||
|
||||
/**
|
||||
* Some user belonging to a customer without a more precise role.
|
||||
*/
|
||||
// TODO: It's mostly a placeholder for more precise future roles like a "webspace admin".
|
||||
// This also shows that it's a bit ugly that we need the roles of all modules in this enum
|
||||
// because types for attributes of annotations are quite limited in Java.
|
||||
ACTUAL_CUSTOMER_USER(80),
|
||||
CustomerFinancialContact() {
|
||||
super(AnyCustomerContact.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to grant rights to any user, also special function users who have no
|
||||
* rights on other users resources.
|
||||
* <p>
|
||||
* It's only used to specify the required role and cannot be assigned to a user.
|
||||
* </p>
|
||||
*/
|
||||
ANY_CUSTOMER_USER(89),
|
||||
public static class CustomerTechnicalContact extends DependentRole {
|
||||
|
||||
public static final CustomerTechnicalContact ROLE = Role.of(CustomerTechnicalContact.class);
|
||||
|
||||
CustomerTechnicalContact() {
|
||||
super(
|
||||
AnyCustomerContact.class,
|
||||
AnyCustomerUser.class); // TODO mhoennig: how to add roles of other modules?
|
||||
}
|
||||
}
|
||||
|
||||
public static class AnyCustomerContact extends DependentRole {
|
||||
|
||||
public static final AnyCustomerContact ROLE = Role.of(AnyCustomerContact.class);
|
||||
|
||||
AnyCustomerContact() {
|
||||
super(Anybody.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ActualCustomerUser extends DependentRole {
|
||||
|
||||
public static final ActualCustomerUser ROLE = Role.of(ActualCustomerUser.class);
|
||||
|
||||
ActualCustomerUser() {
|
||||
super(AnyCustomerUser.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AnyCustomerUser extends DependentRole {
|
||||
|
||||
public static final Role ROLE = Role.of(AnyCustomerUser.class);
|
||||
|
||||
AnyCustomerUser() {
|
||||
super(Anybody.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This role is meant to specify that a resources can be accessed by anybody, even without login.
|
||||
* <p>
|
||||
* It can be used to specify the required role and is the implicit role for un-authenticated users.
|
||||
* It can be used to specify to grant rights to any use, even if unauthorized.
|
||||
* </p>
|
||||
*/
|
||||
ANYBODY(99, AuthoritiesConstants.ANONYMOUS),
|
||||
public static class Anybody extends IndependentRole {
|
||||
|
||||
public static final Role ROLE = Role.of(Anybody.class);
|
||||
|
||||
Anybody() {
|
||||
super(AuthoritiesConstants.ANONYMOUS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pseudo-role to mark init/update access as ignored because the field is display-only.
|
||||
@ -139,27 +254,12 @@ public enum Role {
|
||||
* This allows REST clients to send the whole response back as a new update request.
|
||||
* This role is not covered by any and covers itself no role.
|
||||
* <p>
|
||||
* It's only used to specify the required role and cannot be assigned to a user.
|
||||
* It's only used to ignore the field.
|
||||
* </p>
|
||||
*/
|
||||
IGNORED;
|
||||
public static class Ignored extends DependentRole {
|
||||
|
||||
private final Integer level;
|
||||
private final Optional<String> authority;
|
||||
|
||||
Role(final int level, final String authority) {
|
||||
this.level = level;
|
||||
this.authority = Optional.of(authority);
|
||||
}
|
||||
|
||||
Role(final int level) {
|
||||
this.level = level;
|
||||
this.authority = Optional.empty();
|
||||
}
|
||||
|
||||
Role() {
|
||||
this.level = null;
|
||||
this.authority = Optional.empty();
|
||||
public static final Role ROLE = Role.of(Ignored.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,32 +271,25 @@ public enum Role {
|
||||
if (accessForAnnot == null) {
|
||||
return true;
|
||||
}
|
||||
final Role[] updateAccessFor = field.getAnnotation(AccessFor.class).update();
|
||||
return updateAccessFor.length == 1 && updateAccessFor[0].isIgnored();
|
||||
final Class<? extends Role>[] updateAccessFor = field.getAnnotation(AccessFor.class).update();
|
||||
return updateAccessFor.length == 1 && updateAccessFor[0] == Ignored.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the independent authority related 1:1 to this Role or empty if no independent authority is related 1:1
|
||||
* @see AuthoritiesConstants
|
||||
*/
|
||||
public Optional<String> getAuthority() {
|
||||
public String authority() {
|
||||
return authority;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the role is the IGNORED role
|
||||
*/
|
||||
public boolean isIgnored() {
|
||||
return this == Role.IGNORED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)) {
|
||||
if (r.covers(broadests.getClass())) {
|
||||
broadests = r;
|
||||
}
|
||||
}
|
||||
@ -209,17 +302,25 @@ public enum Role {
|
||||
* Where 'this' means the Java instance itself as a role of a system user.
|
||||
* <p>
|
||||
* {@code
|
||||
* Role.HOSTMASTER.covers(Role.ANY_CUSTOMER_USER) == true
|
||||
* AssignedHostmaster.ROLE.covers(AssignedRole.ANY_CUSTOMER_USER) == true
|
||||
* }
|
||||
*
|
||||
* @param role The required role for a resource.
|
||||
* @param roleClass The required role for a resource.
|
||||
* @return whether this role comprises the given role
|
||||
*/
|
||||
public boolean covers(final Role role) {
|
||||
if (this.isIgnored() || role.isIgnored()) {
|
||||
public boolean covers(final Class<? extends Role> roleClass) {
|
||||
if (getClass() == Ignored.class || roleClass == Ignored.class) {
|
||||
return false;
|
||||
}
|
||||
return this == role || this.level < role.level;
|
||||
if (getClass() == roleClass) {
|
||||
return true;
|
||||
}
|
||||
for (Role role : comprises.get()) {
|
||||
if (role.covers(roleClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,17 +329,17 @@ public enum Role {
|
||||
* Where 'this' means the Java instance itself as a role of a system user.
|
||||
* <p>
|
||||
* {@code
|
||||
* Role.HOSTMASTER.coversAny(Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT) == true
|
||||
* AssignedHostmaster.ROLE.coversAny(AssignedRole.CUSTOMER_CONTRACTUAL_CONTACT, AssignedRole.CUSTOMER_FINANCIAL_CONTACT) == true
|
||||
* }
|
||||
*
|
||||
* @param roles The alternatively required roles for a resource. Must be at least one.
|
||||
* @param roleClasses The alternatively required roles for a resource. Must be at least one.
|
||||
* @return whether this role comprises any of the given roles
|
||||
*/
|
||||
public boolean coversAny(final Role... roles) {
|
||||
verify(roles != null && roles.length > 0, "roles expected");
|
||||
public boolean coversAny(final Class<? extends Role>... roleClasses) {
|
||||
verify(roleClasses != null && roleClasses.length > 0, "role classes expected");
|
||||
|
||||
for (Role role : roles) {
|
||||
if (this.covers(role)) {
|
||||
for (Class<? extends Role> roleClass : roleClasses) {
|
||||
if (this.covers(roleClass)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -258,7 +359,7 @@ public enum Role {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isRoleCovered(accessFor.init());
|
||||
return coversAny(accessFor.init());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +375,7 @@ public enum Role {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isRoleCovered(accessFor.update());
|
||||
return coversAny(accessFor.update());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -290,15 +391,26 @@ public enum Role {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isRoleCovered(accessFor.read());
|
||||
}
|
||||
|
||||
private boolean isRoleCovered(final Role[] requiredRoles) {
|
||||
for (Role accessAllowedForRole : requiredRoles) {
|
||||
if (this.covers(accessAllowedForRole)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return coversAny(accessFor.read());
|
||||
}
|
||||
}
|
||||
|
||||
class LazyRoles {
|
||||
|
||||
private final Class<? extends Role>[] comprisedRoleClasses;
|
||||
private Role[] comprisedRoles = null;
|
||||
|
||||
LazyRoles(Class<? extends Role>... comprisedRoleClasses) {
|
||||
this.comprisedRoleClasses = comprisedRoleClasses;
|
||||
}
|
||||
|
||||
Role[] get() {
|
||||
if (comprisedRoles == null) {
|
||||
comprisedRoles = new Role[comprisedRoleClasses.length];
|
||||
for (int n = 0; n < comprisedRoleClasses.length; ++n) {
|
||||
comprisedRoles[n] = Role.of(comprisedRoleClasses[n]);
|
||||
}
|
||||
}
|
||||
return comprisedRoles;
|
||||
}
|
||||
}
|
||||
|
@ -7,18 +7,17 @@ import org.hostsharing.hsadminng.service.AssetService;
|
||||
import org.hostsharing.hsadminng.service.MembershipService;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||
|
||||
import org.hostsharing.hsadminng.service.accessfilter.Role.*;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
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 javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* A DTO for the Asset entity.
|
||||
*/
|
||||
@ -26,34 +25,34 @@ import javax.validation.constraints.Size;
|
||||
public class AssetDTO implements Serializable, AccessMappings {
|
||||
|
||||
@SelfId(resolver = AssetService.class)
|
||||
@AccessFor(read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate documentDate;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate valueDate;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private AssetAction action;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private BigDecimal amount;
|
||||
|
||||
@Size(max = 160)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private String remark;
|
||||
|
||||
@ParentId(resolver = MembershipService.class)
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private Long membershipId;
|
||||
|
||||
@AccessFor(update = Role.IGNORED, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(update = Ignored.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String membershipDisplayLabel;
|
||||
|
||||
public Long getId() {
|
||||
|
@ -7,14 +7,14 @@ import org.hostsharing.hsadminng.domain.enumeration.VatRegion;
|
||||
import org.hostsharing.hsadminng.service.CustomerService;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.constraints.*;
|
||||
import static org.hostsharing.hsadminng.service.accessfilter.Role.*;
|
||||
|
||||
/**
|
||||
* A DTO for the Customer entity.
|
||||
@ -23,99 +23,99 @@ import javax.validation.constraints.*;
|
||||
public class CustomerDTO implements AccessMappings, FluentBuilder<CustomerDTO> {
|
||||
|
||||
@SelfId(resolver = CustomerService.class)
|
||||
@AccessFor(read = Role.ANY_CUSTOMER_USER)
|
||||
@AccessFor(read = AnyCustomerUser.class)
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@Min(value = 10000)
|
||||
@Max(value = 99999)
|
||||
@AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
|
||||
@AccessFor(init = Admin.class, read = AnyCustomerUser.class)
|
||||
private Integer reference;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 3)
|
||||
@Pattern(regexp = "[a-z][a-z0-9]+")
|
||||
@AccessFor(init = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
|
||||
@AccessFor(init = Admin.class, read = AnyCustomerUser.class)
|
||||
private String prefix;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 80)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.ANY_CUSTOMER_USER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = AnyCustomerUser.class)
|
||||
private String name;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CUSTOMER_CONTRACTUAL_CONTACT)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = CustomerContractualContact.class)
|
||||
private CustomerKind kind;
|
||||
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate birthDate;
|
||||
|
||||
@Size(max = 80)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String birthPlace;
|
||||
|
||||
@Size(max = 80)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String registrationCourt;
|
||||
|
||||
@Size(max = 80)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String registrationNumber;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private VatRegion vatRegion;
|
||||
|
||||
@Size(max = 40)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String vatNumber;
|
||||
|
||||
@Size(max = 80)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.CUSTOMER_CONTRACTUAL_CONTACT, read = Role.CUSTOMER_CONTRACTUAL_CONTACT)
|
||||
@AccessFor(init = Admin.class, update = CustomerContractualContact.class, read = CustomerContractualContact.class)
|
||||
private String contractualSalutation;
|
||||
|
||||
@NotNull
|
||||
@Size(max = 400)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.CUSTOMER_CONTRACTUAL_CONTACT)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = CustomerContractualContact.class)
|
||||
private String contractualAddress;
|
||||
|
||||
@Size(max = 80)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT },
|
||||
read = Role.CUSTOMER_CONTRACTUAL_CONTACT)
|
||||
init = Admin.class,
|
||||
update = { CustomerContractualContact.class, CustomerFinancialContact.class },
|
||||
read = CustomerContractualContact.class)
|
||||
private String billingSalutation;
|
||||
|
||||
@Size(max = 400)
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String billingAddress;
|
||||
|
||||
@Size(max = 160)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.SUPPORTER, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Supporter.class, read = Supporter.class)
|
||||
private String remark;
|
||||
|
||||
@AccessFor(init = Role.ANYBODY, update = Role.ANYBODY, read = Role.ANY_CUSTOMER_USER)
|
||||
@AccessFor(init = Anybody.class, update = Anybody.class, read = AnyCustomerUser.class)
|
||||
private String displayLabel;
|
||||
|
||||
public Long getId() {
|
||||
|
@ -6,15 +6,14 @@ import org.hostsharing.hsadminng.service.CustomerService;
|
||||
import org.hostsharing.hsadminng.service.MembershipService;
|
||||
import org.hostsharing.hsadminng.service.UserRoleAssignmentService;
|
||||
import org.hostsharing.hsadminng.service.accessfilter.*;
|
||||
|
||||
import org.hostsharing.hsadminng.service.accessfilter.Role.*;
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A DTO for the Membership entity.
|
||||
@ -23,44 +22,44 @@ import javax.validation.constraints.Size;
|
||||
public class MembershipDTO implements AccessMappings, FluentBuilder<MembershipDTO> {
|
||||
|
||||
@SelfId(resolver = MembershipService.class)
|
||||
@AccessFor(read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate admissionDocumentDate;
|
||||
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate cancellationDocumentDate;
|
||||
|
||||
@NotNull
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate memberFromDate;
|
||||
|
||||
@AccessFor(
|
||||
init = Role.ADMIN,
|
||||
update = Role.ADMIN,
|
||||
read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
init = Admin.class,
|
||||
update = Admin.class,
|
||||
read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private LocalDate memberUntilDate;
|
||||
|
||||
@Size(max = 160)
|
||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = Role.SUPPORTER)
|
||||
@AccessFor(init = Admin.class, update = Admin.class, read = Supporter.class)
|
||||
private String remark;
|
||||
|
||||
@ParentId(resolver = CustomerService.class)
|
||||
@AccessFor(init = Role.ADMIN, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(init = Admin.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private Long customerId;
|
||||
|
||||
@AccessFor(update = Role.IGNORED, read = { Role.CUSTOMER_CONTRACTUAL_CONTACT, Role.CUSTOMER_FINANCIAL_CONTACT })
|
||||
@AccessFor(update = Ignored.class, read = { CustomerContractualContact.class, CustomerFinancialContact.class })
|
||||
private String customerPrefix;
|
||||
|
||||
@AccessFor(update = Role.IGNORED, read = Role.CUSTOMER_FINANCIAL_CONTACT)
|
||||
@AccessFor(update = Ignored.class, read = CustomerFinancialContact.class)
|
||||
private String customerDisplayLabel;
|
||||
|
||||
@AccessFor(update = Role.IGNORED, read = Role.CUSTOMER_FINANCIAL_CONTACT)
|
||||
@AccessFor(update = Ignored.class, read = CustomerFinancialContact.class)
|
||||
private String displayLabel;
|
||||