Skip to content

Commit bb8f6c9

Browse files
Merge pull request #13995 from SORMAS-Foundation/fix/13830-national-user-cannot-be-responsible-user
🐛: FIX: #13830: National user cannot assign case or event
2 parents e49575e + 7e09339 commit bb8f6c9

2 files changed

Lines changed: 100 additions & 64 deletions

File tree

sormas-backend/src/main/java/de/symeda/sormas/backend/user/UserService.java

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,15 @@
1515
package de.symeda.sormas.backend.user;
1616

1717
import java.text.MessageFormat;
18-
import java.util.Arrays;
19-
import java.util.Collection;
20-
import java.util.Collections;
21-
import java.util.HashMap;
22-
import java.util.List;
23-
import java.util.Map;
24-
import java.util.Random;
25-
import java.util.Set;
18+
import java.util.*;
2619
import java.util.stream.Collectors;
2720

2821
import javax.ejb.EJB;
2922
import javax.ejb.LocalBean;
3023
import javax.ejb.Stateless;
3124
import javax.inject.Inject;
3225
import javax.persistence.TypedQuery;
33-
import javax.persistence.criteria.CriteriaBuilder;
34-
import javax.persistence.criteria.CriteriaQuery;
35-
import javax.persistence.criteria.Expression;
36-
import javax.persistence.criteria.From;
37-
import javax.persistence.criteria.Join;
38-
import javax.persistence.criteria.JoinType;
39-
import javax.persistence.criteria.ParameterExpression;
40-
import javax.persistence.criteria.Predicate;
41-
import javax.persistence.criteria.Root;
42-
import javax.persistence.criteria.Subquery;
26+
import javax.persistence.criteria.*;
4327
import javax.transaction.Transactional;
4428

4529
import org.apache.commons.collections4.CollectionUtils;
@@ -48,13 +32,7 @@
4832
import de.symeda.sormas.api.infrastructure.InfrastructureHelper;
4933
import de.symeda.sormas.api.infrastructure.facility.FacilityType;
5034
import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto;
51-
import de.symeda.sormas.api.user.JurisdictionLevel;
52-
import de.symeda.sormas.api.user.NotificationProtocol;
53-
import de.symeda.sormas.api.user.NotificationType;
54-
import de.symeda.sormas.api.user.UserCriteria;
55-
import de.symeda.sormas.api.user.UserRight;
56-
import de.symeda.sormas.api.user.UserRoleDto;
57-
import de.symeda.sormas.api.user.UserRoleReferenceDto;
35+
import de.symeda.sormas.api.user.*;
5836
import de.symeda.sormas.api.utils.DataHelper;
5937
import de.symeda.sormas.api.utils.DefaultEntityHelper;
6038
import de.symeda.sormas.api.utils.PasswordHelper;
@@ -254,11 +232,21 @@ public List<UserReference> getUserReferences(
254232
boolean userEntityJoinUsed = false;
255233

256234
if (CollectionUtils.isNotEmpty(regionUuids)) {
235+
logger.debug("regionUuids: [{}]", regionUuids);
257236
Join<User, Region> regionJoin = userRoot.join(User.REGION, JoinType.LEFT);
258-
filter = CriteriaBuilderHelper.and(cb, filter, cb.in(regionJoin.get(AbstractDomainObject.UUID)).value(regionUuids));
237+
238+
filter = CriteriaBuilderHelper.and(
239+
cb,
240+
filter,
241+
CriteriaBuilderHelper.or(
242+
cb,
243+
cb.in(regionJoin.get(AbstractDomainObject.UUID)).value(regionUuids),
244+
createUserHasNationJurisdictionFilter(cb, userRoot)));
259245
userEntityJoinUsed = true;
260246
}
261247
if (CollectionUtils.isNotEmpty(districtUuids)) {
248+
logger.debug("districtUuids: [{}]", districtUuids);
249+
262250
Join<User, District> districtJoin = userRoot.join(User.DISTRICT, JoinType.LEFT);
263251
Join<User, Region> userRegionJoin = userRoot.join(User.REGION, JoinType.LEFT);
264252
Join<Region, District> districtRegionJoin = userRegionJoin.join(Region.DISTRICTS, JoinType.LEFT);
@@ -269,11 +257,17 @@ public List<UserReference> getUserReferences(
269257
cb.in(districtRegionJoin.get(AbstractDomainObject.UUID)).value(districtUuids),
270258
cb.equal(root.get(UserReference.JURISDICTION_LEVEL), JurisdictionLevel.REGION)));
271259

272-
filter = CriteriaBuilderHelper.and(cb, filter, districtFilter);
260+
filter = CriteriaBuilderHelper
261+
.and(cb, filter, CriteriaBuilderHelper.or(cb, districtFilter, createUserHasNationJurisdictionFilter(cb, userRoot)));
273262
userEntityJoinUsed = true;
274263
}
275264
if (!hasRight(UserRight.SEE_PERSONAL_DATA_OUTSIDE_JURISDICTION)) {
276-
filter = CriteriaBuilderHelper.and(cb, filter, createCurrentUserJurisdictionFilter(cb, userRoot));
265+
logger.debug("Not looking for user right [SEE_PERSONAL_DATA_OUTSIDE_JURISDICTION]");
266+
267+
filter = CriteriaBuilderHelper.and(
268+
cb,
269+
filter,
270+
CriteriaBuilderHelper.or(cb, createCurrentUserJurisdictionFilter(cb, userRoot), createUserHasNationJurisdictionFilter(cb, userRoot)));
277271
userEntityJoinUsed = true;
278272
}
279273

@@ -298,12 +292,20 @@ public List<UserReference> getUserReferences(
298292

299293
//exlude users with limited diseases
300294
if (excludeLimitedDiseaseUsers) {
295+
logger.debug("Search will be limited to diseases of the user");
301296
filter = CriteriaBuilderHelper.and(cb, filter, cb.isNull(userRoot.get(User.LIMITED_DISEASES)));
302297
}
303298

304299
if (CollectionUtils.isNotEmpty(communityUuids)) {
300+
logger.debug("communityUuids: [{}]", communityUuids);
305301
Join<User, Community> communityJoin = userRoot.join(User.COMMUNITY, JoinType.LEFT);
306-
filter = CriteriaBuilderHelper.and(cb, filter, cb.in(communityJoin.get(AbstractDomainObject.UUID)).value(communityUuids));
302+
filter = CriteriaBuilderHelper.and(
303+
cb,
304+
filter,
305+
CriteriaBuilderHelper.or(
306+
cb,
307+
cb.in(communityJoin.get(AbstractDomainObject.UUID)).value(communityUuids),
308+
createUserHasNationJurisdictionFilter(cb, userRoot)));
307309
}
308310

309311
if (filter != null) {
@@ -725,9 +727,14 @@ public Predicate createCurrentUserJurisdictionFilter(CriteriaBuilder cb, From<?,
725727
}
726728
}
727729

730+
public Predicate createUserHasNationJurisdictionFilter(CriteriaBuilder cb, From<?, User> from) {
731+
return cb.equal(from.get(User.JURISDICTION_LEVEL), JurisdictionLevel.NATION);
732+
}
733+
728734
public Predicate buildUserRightsFilter(Root<User> from, Collection<UserRight> userRights) {
729735

730736
if (userRights != null && !userRights.isEmpty()) {
737+
logger.debug("Requested user rights: [{}]", userRights);
731738
Join<User, UserRole> rolesJoin = from.join(User.USER_ROLES, JoinType.LEFT);
732739
Join<UserRole, UserRight> rightsJoin = rolesJoin.join(UserRole.USER_RIGHTS, JoinType.LEFT);
733740
return rightsJoin.in(Collections.singletonList(userRights));

sormas-backend/src/test/java/de/symeda/sormas/backend/user/UserFacadeEjbTest.java

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,21 @@
11
package de.symeda.sormas.backend.user;
22

3-
import static de.symeda.sormas.api.user.DefaultUserRole.ADMIN_SUPERVISOR;
4-
import static de.symeda.sormas.api.user.DefaultUserRole.CASE_OFFICER;
5-
import static de.symeda.sormas.api.user.DefaultUserRole.CONTACT_OFFICER;
6-
import static de.symeda.sormas.api.user.DefaultUserRole.CONTACT_SUPERVISOR;
7-
import static de.symeda.sormas.api.user.DefaultUserRole.DISTRICT_OBSERVER;
8-
import static de.symeda.sormas.api.user.DefaultUserRole.NATIONAL_USER;
9-
import static de.symeda.sormas.api.user.DefaultUserRole.POE_INFORMANT;
10-
import static de.symeda.sormas.api.user.DefaultUserRole.REST_EXTERNAL_VISITS_USER;
11-
import static de.symeda.sormas.api.user.DefaultUserRole.SURVEILLANCE_OFFICER;
12-
import static de.symeda.sormas.api.user.DefaultUserRole.SURVEILLANCE_SUPERVISOR;
3+
import static de.symeda.sormas.api.user.DefaultUserRole.*;
134
import static org.hamcrest.CoreMatchers.equalTo;
145
import static org.hamcrest.MatcherAssert.assertThat;
15-
import static org.hamcrest.Matchers.contains;
16-
import static org.hamcrest.Matchers.containsInAnyOrder;
17-
import static org.hamcrest.Matchers.hasItem;
18-
import static org.hamcrest.Matchers.hasItems;
19-
import static org.hamcrest.Matchers.hasSize;
20-
import static org.hamcrest.Matchers.is;
21-
import static org.hamcrest.Matchers.not;
22-
import static org.hamcrest.Matchers.nullValue;
23-
import static org.junit.jupiter.api.Assertions.assertEquals;
24-
import static org.junit.jupiter.api.Assertions.assertFalse;
25-
import static org.junit.jupiter.api.Assertions.assertNotNull;
26-
import static org.junit.jupiter.api.Assertions.assertNull;
27-
import static org.junit.jupiter.api.Assertions.assertThrows;
28-
import static org.junit.jupiter.api.Assertions.assertTrue;
6+
import static org.hamcrest.Matchers.*;
7+
import static org.junit.jupiter.api.Assertions.*;
298
import static org.mockito.ArgumentMatchers.any;
309
import static org.mockito.Mockito.mock;
3110
import static org.mockito.Mockito.mockStatic;
3211

33-
import java.util.ArrayList;
34-
import java.util.Arrays;
35-
import java.util.Collections;
36-
import java.util.List;
37-
import java.util.Set;
38-
import java.util.UUID;
12+
import java.util.*;
3913
import java.util.stream.Collectors;
4014

4115
import javax.persistence.EntityNotFoundException;
4216
import javax.validation.ValidationException;
4317

18+
import org.junit.jupiter.api.Assertions;
4419
import org.junit.jupiter.api.BeforeEach;
4520
import org.junit.jupiter.api.Test;
4621
import org.mockito.MockedStatic;
@@ -50,12 +25,9 @@
5025
import de.symeda.sormas.api.AuthProvider;
5126
import de.symeda.sormas.api.Disease;
5227
import de.symeda.sormas.api.EntityDto;
28+
import de.symeda.sormas.api.ReferenceDto;
5329
import de.symeda.sormas.api.infrastructure.region.RegionReferenceDto;
54-
import de.symeda.sormas.api.user.UserCriteria;
55-
import de.symeda.sormas.api.user.UserDto;
56-
import de.symeda.sormas.api.user.UserFacade;
57-
import de.symeda.sormas.api.user.UserReferenceDto;
58-
import de.symeda.sormas.api.user.UserRight;
30+
import de.symeda.sormas.api.user.*;
5931
import de.symeda.sormas.api.utils.AccessDeniedException;
6032
import de.symeda.sormas.api.utils.SortProperty;
6133
import de.symeda.sormas.backend.AbstractBeanTest;
@@ -309,6 +281,27 @@ public void testGetUserRefsByDistrictsWithLimitedDiseaseUsers() {
309281

310282
}
311283

284+
@Test
285+
public void testGetUserRefsByRegionForResponsibleSurveillanceOfficer() {
286+
RDCF rdcf = creator.createRDCF();
287+
RDCF rdcfOther = creator.createRDCF("otherRegion", "oderDistrict", "otherCommunity", "otherFacility");
288+
289+
UserDto surveilanceOfficerDefault = creator.createSurveillanceOfficer(rdcf);
290+
UserDto surveilanceSupervisorDefault = creator.createSurveillanceSupervisor(rdcf);
291+
UserDto adminSupervisorDefault = creator.createUser(rdcf, "Admin", "Supervisor", creator.getUserRoleReference(ADMIN_SUPERVISOR));
292+
UserDto adminSupervisorOther = creator.createUser(rdcfOther, "Admin", "Supervisor Other", creator.getUserRoleReference(ADMIN_SUPERVISOR));
293+
294+
List<UserReferenceDto> userReferenceDtos =
295+
getUserFacade().getUsersByRegionAndRights(rdcf.region, Disease.CORONAVIRUS, UserRight.CASE_RESPONSIBLE);
296+
assertNotNull(userReferenceDtos);
297+
assertEquals(3, userReferenceDtos.size());
298+
List<String> userReferenceUUIDs = userReferenceDtos.stream().map(u -> u.getUuid()).collect(Collectors.toList());
299+
assertTrue(userReferenceUUIDs.contains(surveilanceOfficerDefault.getUuid()));
300+
assertTrue(userReferenceUUIDs.contains(surveilanceSupervisorDefault.getUuid()));
301+
assertTrue(userReferenceUUIDs.contains(adminSupervisorDefault.getUuid()));
302+
assertFalse(userReferenceUUIDs.contains(adminSupervisorOther.getUuid()));
303+
}
304+
312305
@Test
313306
public void testGetUserRefsByDistrictsForResponsibleSurveillanceOfficer() {
314307
RDCF rdcf = creator.createRDCF();
@@ -329,6 +322,42 @@ public void testGetUserRefsByDistrictsForResponsibleSurveillanceOfficer() {
329322
assertFalse(userReferenceUUIDs.contains(adminSupervisorOther.getUuid()));
330323
}
331324

325+
@Test
326+
public void testGetUserRefsByDistrictsForResponsibleSurveillanceOfficer_national_user() {
327+
RDCF rdcf = creator.createRDCF();
328+
329+
UserDto surveilanceOfficerDefault = creator.createSurveillanceOfficer(rdcf);
330+
UserDto surveilanceSupervisorDefault = creator.createSurveillanceSupervisor(rdcf);
331+
UserDto nationalUser = creator.createUser(rdcf, "national", "user", creator.getUserRoleReference(NATIONAL_USER));
332+
333+
List<UserReferenceDto> userReferenceDtos = getUserFacade().getUserRefsByDistricts(Arrays.asList(rdcf.district), Disease.CORONAVIRUS);
334+
List<String> userReferenceUUIDs = userReferenceDtos.stream().map(ReferenceDto::getUuid).collect(Collectors.toList());
335+
336+
Assertions.assertAll(
337+
() -> assertEquals(4, userReferenceDtos.size()),
338+
() -> assertTrue(userReferenceUUIDs.contains(surveilanceOfficerDefault.getUuid())),
339+
() -> assertTrue(userReferenceUUIDs.contains(surveilanceSupervisorDefault.getUuid())),
340+
() -> assertTrue(userReferenceUUIDs.contains(nationalUser.getUuid())));
341+
}
342+
343+
@Test
344+
public void testGetUserRefsByRegionForResponsibleSurveillanceOfficer_national_user() {
345+
RDCF rdcf = creator.createRDCF();
346+
347+
UserDto surveilanceOfficerDefault = creator.createSurveillanceOfficer(rdcf);
348+
UserDto surveilanceSupervisorDefault = creator.createSurveillanceSupervisor(rdcf);
349+
UserDto nationalUser = creator.createUser(rdcf, "national", "user", creator.getUserRoleReference(NATIONAL_USER));
350+
351+
List<UserReferenceDto> userReferenceDtos = getUserFacade().getUsersByRegionAndRights(rdcf.region, Disease.CORONAVIRUS);
352+
List<String> userReferenceUUIDs = userReferenceDtos.stream().map(ReferenceDto::getUuid).collect(Collectors.toList());
353+
354+
Assertions.assertAll(
355+
() -> assertEquals(4, userReferenceDtos.size()),
356+
() -> assertTrue(userReferenceUUIDs.contains(surveilanceOfficerDefault.getUuid())),
357+
() -> assertTrue(userReferenceUUIDs.contains(surveilanceSupervisorDefault.getUuid())),
358+
() -> assertTrue(userReferenceUUIDs.contains(nationalUser.getUuid())));
359+
}
360+
332361
@Test
333362
public void testGetUserRefsByDistrictsWithLimitedDiseaseUsersSingleDistrict() {
334363

0 commit comments

Comments
 (0)