View Javadoc
1   /*
2    * Copyright (C) 2023 B3Partners B.V.
3    *
4    * SPDX-License-Identifier: MIT
5    */
6   package org.tailormap.api.persistence;
7   
8   import jakarta.persistence.Column;
9   import jakarta.persistence.Entity;
10  import jakarta.persistence.EntityListeners;
11  import jakarta.persistence.Id;
12  import jakarta.persistence.ManyToMany;
13  import jakarta.persistence.PreRemove;
14  import jakarta.persistence.Table;
15  import jakarta.persistence.Version;
16  import jakarta.validation.constraints.Pattern;
17  import java.util.ArrayList;
18  import java.util.HashSet;
19  import java.util.List;
20  import java.util.Set;
21  import java.util.function.Function;
22  import org.hibernate.annotations.Type;
23  import org.tailormap.api.persistence.helper.AdminAdditionalPropertyHelper;
24  import org.tailormap.api.persistence.json.AdminAdditionalProperty;
25  import org.tailormap.api.persistence.listener.EntityEventPublisher;
26  import org.tailormap.api.util.Constants;
27  
28  @Entity
29  @Table(name = "groups")
30  @EntityListeners(EntityEventPublisher.class)
31  public class Group {
32    // Group to make authorization rules for anonymous users
33    public static final String ANONYMOUS = "anonymous";
34    // Group to make authorization rules for authenticated users
35    public static final String AUTHENTICATED = "authenticated";
36    public static final String ADMIN = "admin";
37    public static final String ACTUATOR = "actuator";
38  
39    @Id
40    @Pattern(regexp = Constants.NAME_REGEX, message = "Group " + Constants.NAME_REGEX_INVALID_MESSAGE) private String name;
41  
42    @Version
43    private Long version;
44  
45    private boolean systemGroup;
46  
47    private String description;
48  
49    @Column(columnDefinition = "text")
50    private String notes;
51  
52    @ManyToMany(mappedBy = "groups")
53    private Set<User> members = new HashSet<>();
54  
55    /**
56     * Enables the use of a group as an alias for another group. This is useful for example when the 'admin' group name
57     * can't be sent from a single sign-on provider. In that case, the single sign-on provider can send a different
58     * group name and the viewer can map that group name to the 'admin' group.
59     */
60    private String aliasForGroup;
61  
62    /**
63     * Generic additional properties which can be set on a group. A viewer admin frontend extension component can define
64     * attributes for the purposes of the extension and the viewer admin UI will show a control to edit the attribute in
65     * the group detail form.
66     */
67    @Type(value = io.hypersistence.utils.hibernate.type.json.JsonBinaryType.class)
68    @Column(columnDefinition = "jsonb")
69    private List<AdminAdditionalProperty> additionalProperties = new ArrayList<>();
70  
71    public String getName() {
72      return name;
73    }
74  
75    public Group setName(String name) {
76      this.name = name;
77      return this;
78    }
79  
80    public Long getVersion() {
81      return version;
82    }
83  
84    public Group setVersion(Long version) {
85      this.version = version;
86      return this;
87    }
88  
89    public boolean isSystemGroup() {
90      return systemGroup;
91    }
92  
93    public Group setSystemGroup(boolean systemGroup) {
94      this.systemGroup = systemGroup;
95      return this;
96    }
97  
98    public String getDescription() {
99      return description;
100   }
101 
102   public Group setDescription(String title) {
103     this.description = title;
104     return this;
105   }
106 
107   public String getNotes() {
108     return notes;
109   }
110 
111   public Group setNotes(String notes) {
112     this.notes = notes;
113     return this;
114   }
115 
116   public Set<User> getMembers() {
117     return members;
118   }
119 
120   public Group setMembers(Set<User> members) {
121     this.members = members;
122     return this;
123   }
124 
125   public String getAliasForGroup() {
126     return aliasForGroup;
127   }
128 
129   public Group setAliasForGroup(String aliasFor) {
130     this.aliasForGroup = aliasFor;
131     return this;
132   }
133 
134   public List<AdminAdditionalProperty> getAdditionalProperties() {
135     return additionalProperties;
136   }
137 
138   public Group setAdditionalProperties(List<AdminAdditionalProperty> additionalProperties) {
139     this.additionalProperties = additionalProperties;
140     return this;
141   }
142 
143   @PreRemove
144   @SuppressWarnings("PMD.UnusedPrivateMethod")
145   private void removeMembers() {
146     for (User user : this.members) {
147       user.getGroups().remove(this);
148     }
149   }
150 
151   public void addOrUpdateAdminProperty(String key, Object value, boolean isPublic) {
152     AdminAdditionalPropertyHelper.addOrUpdateAdminProperty(additionalProperties, key, value, isPublic);
153   }
154 
155   /**
156    * Maps a property value in the additional properties of the group. If the property does not exist, it will be
157    * created and the valueMapper function will be called with a null value.
158    *
159    * @param key the key of the property
160    * @param isPublic whether the property is public
161    * @param valueMapper the function to map the value
162    */
163   public void mapAdminPropertyValue(String key, boolean isPublic, Function<Object, Object> valueMapper) {
164     AdminAdditionalPropertyHelper.mapAdminPropertyValue(additionalProperties, key, isPublic, valueMapper);
165   }
166 }