blob: afd6086dd5125565f7f6ed5bbd93a5a222689f04 [file] [log] [blame]
margarethabf11d8d2017-10-24 19:31:44 +02001package de.ids_mannheim.korap.dao;
2
margarethac942eac2024-07-17 11:55:53 +02003import java.time.ZonedDateTime;
margaretha18533fd2018-03-28 16:01:06 +02004import java.util.HashSet;
margarethabf11d8d2017-10-24 19:31:44 +02005import java.util.List;
margaretha18533fd2018-03-28 16:01:06 +02006import java.util.Set;
margarethabf11d8d2017-10-24 19:31:44 +02007
margaretha6e796842023-08-17 15:10:45 +02008import jakarta.persistence.EntityManager;
9import jakarta.persistence.NoResultException;
10import jakarta.persistence.PersistenceContext;
11import jakarta.persistence.Query;
12import jakarta.persistence.criteria.CriteriaBuilder;
13import jakarta.persistence.criteria.CriteriaQuery;
14import jakarta.persistence.criteria.Join;
15import jakarta.persistence.criteria.ListJoin;
16import jakarta.persistence.criteria.Predicate;
17import jakarta.persistence.criteria.Root;
margarethabf11d8d2017-10-24 19:31:44 +020018
margarethab42b9632017-10-25 18:34:12 +020019import org.springframework.beans.factory.annotation.Autowired;
margarethad3c0fc92017-10-25 15:03:32 +020020import org.springframework.stereotype.Repository;
margarethabf11d8d2017-10-24 19:31:44 +020021import org.springframework.transaction.annotation.Transactional;
22
margarethaf438c592017-10-25 15:23:50 +020023import de.ids_mannheim.korap.constant.GroupMemberStatus;
margarethab42b9632017-10-25 18:34:12 +020024import de.ids_mannheim.korap.constant.PredefinedRole;
margarethac942eac2024-07-17 11:55:53 +020025import de.ids_mannheim.korap.constant.PrivilegeType;
margarethaf438c592017-10-25 15:23:50 +020026import de.ids_mannheim.korap.constant.UserGroupStatus;
margarethab097fb02021-02-22 19:28:33 +010027import de.ids_mannheim.korap.constant.QueryAccessStatus;
margarethab42b9632017-10-25 18:34:12 +020028import de.ids_mannheim.korap.entity.Role;
margarethabf11d8d2017-10-24 19:31:44 +020029import de.ids_mannheim.korap.entity.UserGroup;
30import de.ids_mannheim.korap.entity.UserGroupMember;
margarethad3c0fc92017-10-25 15:03:32 +020031import de.ids_mannheim.korap.entity.UserGroupMember_;
32import de.ids_mannheim.korap.entity.UserGroup_;
margarethab097fb02021-02-22 19:28:33 +010033import de.ids_mannheim.korap.entity.QueryDO;
34import de.ids_mannheim.korap.entity.QueryAccess;
35import de.ids_mannheim.korap.entity.QueryAccess_;
36import de.ids_mannheim.korap.entity.QueryDO_;
margaretha61966dd2017-10-26 19:32:21 +020037import de.ids_mannheim.korap.exceptions.KustvaktException;
38import de.ids_mannheim.korap.exceptions.StatusCodes;
39import de.ids_mannheim.korap.utils.ParameterChecker;
margarethabf11d8d2017-10-24 19:31:44 +020040
margaretha398f4722019-01-09 19:07:20 +010041/**
42 * Manages database queries and transactions regarding
43 * {@link UserGroup} entity and database table.
margaretha69e8adc2018-03-15 15:14:22 +010044 *
45 * @author margaretha
46 *
47 * @see UserGroup
48 *
49 */
margarethabf11d8d2017-10-24 19:31:44 +020050@Transactional
margarethad3c0fc92017-10-25 15:03:32 +020051@Repository
margarethabf11d8d2017-10-24 19:31:44 +020052public class UserGroupDao {
53
54 @PersistenceContext
55 private EntityManager entityManager;
56
margaretha35e1ca22023-11-16 22:00:01 +010057 public int createGroup (String name, String description, String createdBy,
58 UserGroupStatus status) throws KustvaktException {
margaretha61966dd2017-10-26 19:32:21 +020059 ParameterChecker.checkStringValue(name, "name");
60 ParameterChecker.checkStringValue(createdBy, "createdBy");
61 ParameterChecker.checkObjectValue(status, "UserGroupStatus");
62
margarethabf11d8d2017-10-24 19:31:44 +020063 UserGroup group = new UserGroup();
64 group.setName(name);
margarethad8aa1352019-12-19 11:04:41 +010065 group.setDescription(description);
margarethabf11d8d2017-10-24 19:31:44 +020066 group.setStatus(status);
67 group.setCreatedBy(createdBy);
margarethac942eac2024-07-17 11:55:53 +020068 group.setCreatedDate(ZonedDateTime.now());
margarethabf11d8d2017-10-24 19:31:44 +020069 entityManager.persist(group);
margarethac942eac2024-07-17 11:55:53 +020070 entityManager.flush();
71
72 Set<Role> roles = createUserGroupAdminRoles(group);
73 for (Role role : roles) {
74 entityManager.persist(role);
75 }
76 entityManager.flush();
77
margarethab42b9632017-10-25 18:34:12 +020078 UserGroupMember owner = new UserGroupMember();
margaretha61966dd2017-10-26 19:32:21 +020079 owner.setUserId(createdBy);
margarethab42b9632017-10-25 18:34:12 +020080 owner.setCreatedBy(createdBy);
81 owner.setStatus(GroupMemberStatus.ACTIVE);
82 owner.setGroup(group);
83 owner.setRoles(roles);
84 entityManager.persist(owner);
margarethac942eac2024-07-17 11:55:53 +020085 entityManager.flush();
86
margaretha61966dd2017-10-26 19:32:21 +020087 return group.getId();
margarethabf11d8d2017-10-24 19:31:44 +020088 }
margarethac942eac2024-07-17 11:55:53 +020089
90 private Set<Role> createUserGroupAdminRoles (UserGroup group) {
91 Set<Role> roles = new HashSet<Role>();
margaretha777ef102024-07-22 10:10:50 +020092 roles.add(new Role(PredefinedRole.GROUP_ADMIN,
93 PrivilegeType.DELETE_MEMBER, group));
94 roles.add(new Role(PredefinedRole.GROUP_ADMIN, PrivilegeType.READ_MEMBER,
95 group));
96 roles.add(new Role(PredefinedRole.GROUP_ADMIN, PrivilegeType.WRITE_MEMBER,
97 group));
98 roles.add(new Role(PredefinedRole.GROUP_ADMIN, PrivilegeType.SHARE_QUERY,
99 group));
100 roles.add(new Role(PredefinedRole.GROUP_ADMIN, PrivilegeType.DELETE_QUERY,
101 group));
margarethac942eac2024-07-17 11:55:53 +0200102 return roles;
103 }
margarethabf11d8d2017-10-24 19:31:44 +0200104
105 public void deleteGroup (int groupId, String deletedBy,
margaretha61966dd2017-10-26 19:32:21 +0200106 boolean isSoftDelete) throws KustvaktException {
107 ParameterChecker.checkIntegerValue(groupId, "groupId");
108 ParameterChecker.checkStringValue(deletedBy, "deletedBy");
109
margaretha9d3eb042017-12-22 11:02:30 +0100110 UserGroup group = null;
111 try {
112 group = retrieveGroupById(groupId);
113 }
114 catch (NoResultException e) {
margarethab5e1e0a2019-01-29 22:11:57 +0100115 throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
116 "Group " + groupId + " is not found.",
margaretha9d3eb042017-12-22 11:02:30 +0100117 "groupId: " + groupId);
118 }
119
margarethabf11d8d2017-10-24 19:31:44 +0200120 if (isSoftDelete) {
121 group.setStatus(UserGroupStatus.DELETED);
122 group.setDeletedBy(deletedBy);
margarethab874ef52018-01-23 20:26:31 +0100123 entityManager.merge(group);
margarethabf11d8d2017-10-24 19:31:44 +0200124 }
125 else {
margarethac9f1dfa2018-02-07 17:50:33 +0100126 if (!entityManager.contains(group)) {
margarethab874ef52018-01-23 20:26:31 +0100127 group = entityManager.merge(group);
128 }
margarethabf11d8d2017-10-24 19:31:44 +0200129 entityManager.remove(group);
130 }
131 }
132
margarethad8aa1352019-12-19 11:04:41 +0100133 public void updateGroup (UserGroup group) throws KustvaktException {
134 ParameterChecker.checkObjectValue(group, "user-group");
margaretha541b8cc2018-01-10 13:02:46 +0100135 entityManager.merge(group);
136 }
margaretha35e1ca22023-11-16 22:00:01 +0100137
margaretha398f4722019-01-09 19:07:20 +0100138 /**
139 * Retrieves the UserGroup by the given group id. This methods
140 * does not
141 * fetch group members because only group admin is allowed to see
142 * them.
143 * Group members have to be retrieved separately.
margaretha61966dd2017-10-26 19:32:21 +0200144 *
145 * @see UserGroupMember
margaretha398f4722019-01-09 19:07:20 +0100146 * @param groupId
147 * group id
margaretha61966dd2017-10-26 19:32:21 +0200148 * @return UserGroup
margaretha398f4722019-01-09 19:07:20 +0100149 * @throws KustvaktException
margaretha61966dd2017-10-26 19:32:21 +0200150 */
151 public UserGroup retrieveGroupById (int groupId) throws KustvaktException {
margaretha71e6fca2018-01-18 18:11:48 +0100152 return retrieveGroupById(groupId, false);
margarethabf11d8d2017-10-24 19:31:44 +0200153 }
154
margaretha71e6fca2018-01-18 18:11:48 +0100155 public UserGroup retrieveGroupById (int groupId, boolean fetchMembers)
margaretha61966dd2017-10-26 19:32:21 +0200156 throws KustvaktException {
margaretha61966dd2017-10-26 19:32:21 +0200157 ParameterChecker.checkIntegerValue(groupId, "groupId");
158
159 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100160 CriteriaQuery<UserGroup> query = criteriaBuilder
161 .createQuery(UserGroup.class);
margaretha61966dd2017-10-26 19:32:21 +0200162
163 Root<UserGroup> root = query.from(UserGroup.class);
margaretha71e6fca2018-01-18 18:11:48 +0100164 if (fetchMembers) {
165 root.fetch(UserGroup_.members);
166 }
margaretha61966dd2017-10-26 19:32:21 +0200167 query.select(root);
168 query.where(criteriaBuilder.equal(root.get(UserGroup_.id), groupId));
169 Query q = entityManager.createQuery(query);
170
margaretha61966dd2017-10-26 19:32:21 +0200171 try {
margaretha541b8cc2018-01-10 13:02:46 +0100172 return (UserGroup) q.getSingleResult();
margaretha61966dd2017-10-26 19:32:21 +0200173 }
174 catch (NoResultException e) {
margarethad8aa1352019-12-19 11:04:41 +0100175 throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
margarethac9f1dfa2018-02-07 17:50:33 +0100176 "Group with id " + groupId + " is not found",
margaretha61966dd2017-10-26 19:32:21 +0200177 String.valueOf(groupId), e);
178 }
margaretha61966dd2017-10-26 19:32:21 +0200179 }
180
margaretha398f4722019-01-09 19:07:20 +0100181 /**
182 * Retrieves only user-groups that are active (not hidden or
183 * deleted).
margaretha61966dd2017-10-26 19:32:21 +0200184 *
margaretha398f4722019-01-09 19:07:20 +0100185 * @param userId
186 * user id
margaretha61966dd2017-10-26 19:32:21 +0200187 * @return a list of UserGroup
188 * @throws KustvaktException
189 */
margarethadc515072018-08-03 17:01:19 +0200190 @SuppressWarnings("unchecked")
margaretha61966dd2017-10-26 19:32:21 +0200191 public List<UserGroup> retrieveGroupByUserId (String userId)
192 throws KustvaktException {
193 ParameterChecker.checkStringValue(userId, "userId");
194
margarethad3c0fc92017-10-25 15:03:32 +0200195 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100196 CriteriaQuery<UserGroup> query = criteriaBuilder
197 .createQuery(UserGroup.class);
margarethad3c0fc92017-10-25 15:03:32 +0200198
199 Root<UserGroup> root = query.from(UserGroup.class);
200
margaretha35e1ca22023-11-16 22:00:01 +0100201 ListJoin<UserGroup, UserGroupMember> members = root
202 .join(UserGroup_.members);
margaretha61966dd2017-10-26 19:32:21 +0200203 Predicate restrictions = criteriaBuilder.and(
204 criteriaBuilder.equal(root.get(UserGroup_.status),
205 UserGroupStatus.ACTIVE),
margarethad3c0fc92017-10-25 15:03:32 +0200206 criteriaBuilder.equal(members.get(UserGroupMember_.userId),
207 userId),
margaretha45667922018-01-25 21:23:03 +0100208 criteriaBuilder.notEqual(members.get(UserGroupMember_.status),
209 GroupMemberStatus.DELETED));
margaretha398f4722019-01-09 19:07:20 +0100210 // criteriaBuilder.equal(members.get(UserGroupMember_.status),
211 // GroupMemberStatus.ACTIVE));
margarethad3c0fc92017-10-25 15:03:32 +0200212
213 query.select(root);
margaretha61966dd2017-10-26 19:32:21 +0200214 query.where(restrictions);
margarethad3c0fc92017-10-25 15:03:32 +0200215 Query q = entityManager.createQuery(query);
margaretha541b8cc2018-01-10 13:02:46 +0100216
217 try {
218 return q.getResultList();
219 }
220 catch (NoResultException e) {
221 throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
margarethab5e1e0a2019-01-29 22:11:57 +0100222 "No group for username: " + userId + " is found", userId,
223 e);
margaretha541b8cc2018-01-10 13:02:46 +0100224 }
margarethad3c0fc92017-10-25 15:03:32 +0200225 }
226
margaretha35e1ca22023-11-16 22:00:01 +0100227 public UserGroup retrieveGroupByName (String groupName,
228 boolean fetchMembers) throws KustvaktException {
margaretha45dde682018-01-04 21:33:46 +0100229 ParameterChecker.checkStringValue(groupName, "groupName");
230
margaretha0b63de42017-12-20 18:48:09 +0100231 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100232 CriteriaQuery<UserGroup> query = criteriaBuilder
233 .createQuery(UserGroup.class);
margaretha0b63de42017-12-20 18:48:09 +0100234
margaretha45dde682018-01-04 21:33:46 +0100235 Root<UserGroup> root = query.from(UserGroup.class);
margarethaa18ab2b2019-11-11 12:55:26 +0100236 if (fetchMembers) {
237 root.fetch(UserGroup_.members);
238 }
margaretha45dde682018-01-04 21:33:46 +0100239 query.select(root);
240 query.where(
241 criteriaBuilder.equal(root.get(UserGroup_.name), groupName));
242 Query q = entityManager.createQuery(query);
margaretha0b63de42017-12-20 18:48:09 +0100243
margaretha45dde682018-01-04 21:33:46 +0100244 try {
margaretha541b8cc2018-01-10 13:02:46 +0100245 return (UserGroup) q.getSingleResult();
margaretha45dde682018-01-04 21:33:46 +0100246 }
247 catch (NoResultException e) {
margarethab5e1e0a2019-01-29 22:11:57 +0100248 throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND,
249 "Group " + groupName + " is not found", groupName, e);
margaretha45dde682018-01-04 21:33:46 +0100250 }
margaretha0b63de42017-12-20 18:48:09 +0100251 }
margaretha9d3eb042017-12-22 11:02:30 +0100252
margarethab097fb02021-02-22 19:28:33 +0100253 public UserGroup retrieveHiddenGroupByQuery (int queryId)
margarethac9f1dfa2018-02-07 17:50:33 +0100254 throws KustvaktException {
margarethab097fb02021-02-22 19:28:33 +0100255 ParameterChecker.checkIntegerValue(queryId, "queryId");
margaretha71e6fca2018-01-18 18:11:48 +0100256
257 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100258 CriteriaQuery<UserGroup> criteriaQuery = criteriaBuilder
259 .createQuery(UserGroup.class);
margaretha71e6fca2018-01-18 18:11:48 +0100260
margarethab097fb02021-02-22 19:28:33 +0100261 Root<UserGroup> root = criteriaQuery.from(UserGroup.class);
margaretha35e1ca22023-11-16 22:00:01 +0100262 Join<UserGroup, QueryAccess> access = root.join(UserGroup_.queryAccess);
263 Join<QueryAccess, QueryDO> query = access.join(QueryAccess_.query);
margaretha71e6fca2018-01-18 18:11:48 +0100264
265 Predicate p = criteriaBuilder.and(
266 criteriaBuilder.equal(root.get(UserGroup_.status),
267 UserGroupStatus.HIDDEN),
margarethab097fb02021-02-22 19:28:33 +0100268 criteriaBuilder.equal(query.get(QueryDO_.id), queryId));
margarethac9f1dfa2018-02-07 17:50:33 +0100269
margarethab097fb02021-02-22 19:28:33 +0100270 criteriaQuery.select(root);
271 criteriaQuery.where(p);
272 Query q = entityManager.createQuery(criteriaQuery);
margaretha71e6fca2018-01-18 18:11:48 +0100273
274 try {
275 return (UserGroup) q.getSingleResult();
276 }
277 catch (NoResultException e) {
278 throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
margarethab097fb02021-02-22 19:28:33 +0100279 "No hidden group for query with id " + queryId
margarethab5e1e0a2019-01-29 22:11:57 +0100280 + " is found",
margarethab097fb02021-02-22 19:28:33 +0100281 String.valueOf(queryId), e);
margaretha71e6fca2018-01-18 18:11:48 +0100282 }
283
284 }
margaretha45dde682018-01-04 21:33:46 +0100285
margaretha398f4722019-01-09 19:07:20 +0100286 /**
287 * This is an admin function. It retrieves all groups given the
288 * userId
margaretha293ee032018-03-20 20:11:52 +0100289 * and status.
290 *
291 * @param userId
292 * @param status
293 * @return a list of {@link UserGroup}s
294 * @throws KustvaktException
295 */
margarethadc515072018-08-03 17:01:19 +0200296 @SuppressWarnings("unchecked")
margaretha293ee032018-03-20 20:11:52 +0100297 public List<UserGroup> retrieveGroupByStatus (String userId,
298 UserGroupStatus status) throws KustvaktException {
299
300 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100301 CriteriaQuery<UserGroup> query = criteriaBuilder
302 .createQuery(UserGroup.class);
margaretha293ee032018-03-20 20:11:52 +0100303
304 Root<UserGroup> root = query.from(UserGroup.class);
305
306 Predicate restrictions = null;
307
308 if (userId != null && !userId.isEmpty()) {
309
margaretha35e1ca22023-11-16 22:00:01 +0100310 ListJoin<UserGroup, UserGroupMember> members = root
311 .join(UserGroup_.members);
margaretha18533fd2018-03-28 16:01:06 +0200312 restrictions = criteriaBuilder.and(criteriaBuilder
313 .equal(members.get(UserGroupMember_.userId), userId));
314
315 if (status != null) {
margaretha293ee032018-03-20 20:11:52 +0100316 restrictions = criteriaBuilder.and(restrictions, criteriaBuilder
317 .equal(root.get(UserGroup_.status), status));
318 }
319 }
320 else if (status != null) {
margaretha35e1ca22023-11-16 22:00:01 +0100321 restrictions = criteriaBuilder.equal(root.get(UserGroup_.status),
322 status);
margaretha18533fd2018-03-28 16:01:06 +0200323
margaretha293ee032018-03-20 20:11:52 +0100324 }
325
326 query.select(root);
margaretha18533fd2018-03-28 16:01:06 +0200327 if (restrictions != null) {
margaretha293ee032018-03-20 20:11:52 +0100328 query.where(restrictions);
329 }
330 Query q = entityManager.createQuery(query);
331
332 try {
333 return q.getResultList();
334 }
335 catch (NoResultException e) {
336 throw new KustvaktException(StatusCodes.NO_RESULT_FOUND,
margarethab5e1e0a2019-01-29 22:11:57 +0100337 "No group with status " + status + " is found",
338 status.toString());
margaretha293ee032018-03-20 20:11:52 +0100339 }
340
341 }
342
margarethab097fb02021-02-22 19:28:33 +0100343 public void addQueryToGroup (QueryDO query, String createdBy,
344 QueryAccessStatus status, UserGroup group) {
345 QueryAccess accessGroup = new QueryAccess();
margarethad3c0fc92017-10-25 15:03:32 +0200346 accessGroup.setCreatedBy(createdBy);
347 accessGroup.setStatus(status);
348 accessGroup.setUserGroup(group);
margarethab097fb02021-02-22 19:28:33 +0100349 accessGroup.setQuery(query);;
margarethad3c0fc92017-10-25 15:03:32 +0200350 entityManager.persist(accessGroup);
351 }
352
margaretha35e1ca22023-11-16 22:00:01 +0100353 public void addQueryToGroup (List<QueryDO> queries, String createdBy,
354 UserGroup group, QueryAccessStatus status) {
margarethad3c0fc92017-10-25 15:03:32 +0200355
margarethab097fb02021-02-22 19:28:33 +0100356 for (QueryDO q : queries) {
357 addQueryToGroup(q, createdBy, status, group);
margarethabf11d8d2017-10-24 19:31:44 +0200358 }
359 }
margarethad3c0fc92017-10-25 15:03:32 +0200360
margarethab097fb02021-02-22 19:28:33 +0100361 public void deleteQueryFromGroup (int queryId, int groupId)
margaretha9d3eb042017-12-22 11:02:30 +0100362 throws KustvaktException {
margarethab097fb02021-02-22 19:28:33 +0100363 ParameterChecker.checkIntegerValue(queryId, "queryId");
margaretha61966dd2017-10-26 19:32:21 +0200364 ParameterChecker.checkIntegerValue(groupId, "groupId");
365
366 CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
margaretha35e1ca22023-11-16 22:00:01 +0100367 CriteriaQuery<QueryAccess> criteriaQuery = criteriaBuilder
368 .createQuery(QueryAccess.class);
margaretha61966dd2017-10-26 19:32:21 +0200369
margarethab097fb02021-02-22 19:28:33 +0100370 Root<QueryAccess> root = criteriaQuery.from(QueryAccess.class);
margaretha35e1ca22023-11-16 22:00:01 +0100371 Join<QueryAccess, QueryDO> queryAccess = root.join(QueryAccess_.query);
372 Join<QueryAccess, UserGroup> group = root.join(QueryAccess_.userGroup);
margaretha61966dd2017-10-26 19:32:21 +0200373
margaretha35e1ca22023-11-16 22:00:01 +0100374 Predicate query = criteriaBuilder.equal(queryAccess.get(QueryDO_.id),
375 queryId);
376 Predicate userGroup = criteriaBuilder.equal(group.get(UserGroup_.id),
377 groupId);
margaretha9d3eb042017-12-22 11:02:30 +0100378
margarethab097fb02021-02-22 19:28:33 +0100379 criteriaQuery.select(root);
380 criteriaQuery.where(criteriaBuilder.and(query, userGroup));
381 Query q = entityManager.createQuery(criteriaQuery);
margaretha35e1ca22023-11-16 22:00:01 +0100382 QueryAccess access = (QueryAccess) q.getSingleResult();
margarethab097fb02021-02-22 19:28:33 +0100383 entityManager.remove(access);
margaretha61966dd2017-10-26 19:32:21 +0200384 }
385
margarethabf11d8d2017-10-24 19:31:44 +0200386}