Skip to content

Commit

Permalink
Merge pull request #12835 from SORMAS-Foundation/feature-12697_limit_…
Browse files Browse the repository at this point in the history
…acces_to_assigned_cases_for_a_user

#12697 - Assign case(s) to a User and allow them to see the data of o…
  • Loading branch information
sergiupacurariu authored Dec 15, 2023
2 parents b977bfa + 52b0617 commit b893fb4
Show file tree
Hide file tree
Showing 44 changed files with 1,032 additions and 299 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2644,6 +2644,7 @@ public interface Captions {
String userrole_main = "userrole.main";
String userrole_notifications = "userrole.notifications";
String UserRole_portHealthUser = "UserRole.portHealthUser";
String UserRole_restrictAccessToAssignedEntities = "UserRole.restrictAccessToAssignedEntities";
String UserRole_smsNotificationTypes = "UserRole.smsNotificationTypes";
String UserRole_templateUserRole = "UserRole.templateUserRole";
String UserRole_userRights = "UserRole.userRights";
Expand All @@ -2652,6 +2653,7 @@ public interface Captions {
String userRoleNotifications = "userRoleNotifications";
String userRoleNotificationTypeEmail = "userRoleNotificationTypeEmail";
String userRoleNotificationTypeSms = "userRoleNotificationTypeSms";
String userRoleShowOnlyRestrictedAccessToAssignCases = "userRoleShowOnlyRestrictedAccessToAssignCases";
String userRoleUserrolesView = "userRoleUserrolesView";
String userUpdatePasswordConfirmation = "userUpdatePasswordConfirmation";
String Vaccination = "Vaccination";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class UserCriteria extends BaseCriteria implements Serializable {
private RegionReferenceDto region;
private DistrictReferenceDto district;
private String freeText;
private Boolean showOnlyRestrictedAccessToAssignedEntities;

public UserCriteria active(Boolean active) {
this.active = active;
Expand Down Expand Up @@ -62,4 +63,12 @@ public UserCriteria freeText(String freeText) {
public String getFreeText() {
return freeText;
}

public Boolean getShowOnlyRestrictedAccessToAssignedEntities() {
return showOnlyRestrictedAccessToAssignedEntities;
}

public void setShowOnlyRestrictedAccessToAssignedEntities(Boolean showOnlyRestrictedAccessToAssignedEntities) {
this.showOnlyRestrictedAccessToAssignedEntities = showOnlyRestrictedAccessToAssignedEntities;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class UserRoleCriteria extends BaseCriteria implements Serializable {
private Boolean enabled;
private UserRight userRight;
private JurisdictionLevel jurisdictionLevel;
private Boolean showOnlyRestrictedAccessToAssignedEntities;

public UserRoleCriteria enabled(Boolean enabled) {
this.enabled = enabled;
Expand Down Expand Up @@ -40,4 +41,12 @@ public JurisdictionLevel getJurisdictionLevel() {
public void setUserRight(UserRight userRight) {
this.userRight = userRight;
}

public Boolean getShowOnlyRestrictedAccessToAssignedEntities() {
return showOnlyRestrictedAccessToAssignedEntities;
}

public void setShowOnlyRestrictedAccessToAssignedEntities(Boolean showOnlyRestrictedAccessToAssignedEntities) {
this.showOnlyRestrictedAccessToAssignedEntities = showOnlyRestrictedAccessToAssignedEntities;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public class UserRoleDto extends EntityDto {
public static final String PORT_HEALTH_USER = "portHealthUser";
public static final String NOTIFICATION_TYPES = "notificationTypes";
public static final String LINKED_DEFAULT_USER_ROLE = "linkedDefaultUserRole";
public static final String RESTRICT_ACCESS_TO_ASSIGNED_ENTITIES = "restrictAccessToAssignedEntities";

private Set<UserRight> userRights;
private boolean enabled = true;
Expand All @@ -68,6 +69,7 @@ public class UserRoleDto extends EntityDto {
private JurisdictionLevel jurisdictionLevel;
private Set<NotificationType> emailNotificationTypes = Collections.emptySet();
private Set<NotificationType> smsNotificationTypes = Collections.emptySet();
private boolean restrictAccessToAssignedEntities = false;

public static UserRoleDto build(UserRight... userRights) {

Expand Down Expand Up @@ -207,6 +209,14 @@ public void setNotificationTypes(NotificationTypes notificationTypes) {
this.emailNotificationTypes = notificationTypes.email;
}

public boolean isRestrictAccessToAssignedEntities() {
return restrictAccessToAssignedEntities;
}

public void setRestrictAccessToAssignedEntities(boolean restrictAccessToAssignedEntities) {
this.restrictAccessToAssignedEntities = restrictAccessToAssignedEntities;
}

@Override
public String buildCaption() {
return caption;
Expand Down
2 changes: 2 additions & 0 deletions sormas-api/src/main/resources/captions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2855,6 +2855,8 @@ UserRole.linkedDefaultUserRole=Linked default user role
UserRole.portHealthUser=Port health user
UserRole.smsNotificationTypes=SMS notification types
UserRole.templateUserRole=User role template
UserRole.restrictAccessToAssignedEntities=Restrict access to assigned entities
userRoleShowOnlyRestrictedAccessToAssignCases=Only show user roles with access restricted to assigned entities
userRoleUserrolesView=User role list
userRoleNotifications=Notifications
userRoleNotificationTypeSms = SMS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ private <T> CriteriaQuery<T> buildIndexCriteria(
if (caseCriteria != null) {
caseUserFilterCriteria.setIncludeCasesFromOtherJurisdictions(caseCriteria.getIncludeCasesFromOtherJurisdictions());
}

if (currentUserService.hasRestrictedAccessToAssignedEntities()) {
caseUserFilterCriteria.setRestrictAccessToAssignedEntities(true);
}
Predicate filter = caseService.createUserFilter(caseQueryContext, caseUserFilterCriteria);

if (!prefetchIds) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,11 @@ public Predicate createUserFilter(CaseQueryContext caseQueryContext, CaseUserFil
Predicate filter = null;

final JurisdictionLevel jurisdictionLevel = currentUser.getJurisdictionLevel();

if (currentUserHasRestrictedAccessToAssignedEntities()) {
filter = CriteriaBuilderHelper.and(cb, filter, cb.equal(casePath.get(Case.SURVEILLANCE_OFFICER).get(User.ID), currentUser.getId()));
}

if (jurisdictionLevel != JurisdictionLevel.NATION) {
// whoever created the case or is assigned to it is allowed to access it
if (userFilterCriteria == null || (userFilterCriteria.getIncludeCasesFromOtherJurisdictions())) {
Expand All @@ -1405,61 +1410,63 @@ public Predicate createUserFilter(CaseQueryContext caseQueryContext, CaseUserFil
filterResponsible = cb.disjunction();
}

switch (jurisdictionLevel) {
case REGION:
final Region region = currentUser.getRegion();
if (region != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.REGION).get(Region.ID), region.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_REGION).get(Region.ID), region.getId()));
}
break;
case DISTRICT:
final District district = currentUser.getDistrict();
if (district != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.DISTRICT).get(District.ID), district.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_DISTRICT).get(District.ID), district.getId()));
}
break;
case HEALTH_FACILITY:
final Facility healthFacility = currentUser.getHealthFacility();
if (healthFacility != null) {
filter =
CriteriaBuilderHelper.or(cb, filter, cb.equal(casePath.get(Case.HEALTH_FACILITY).get(Facility.ID), healthFacility.getId()));
}
break;
case COMMUNITY:
final Community community = currentUser.getCommunity();
if (community != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.COMMUNITY).get(Community.ID), community.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_COMMUNITY).get(Community.ID), community.getId()));
}
break;
case POINT_OF_ENTRY:
final PointOfEntry pointOfEntry = currentUser.getPointOfEntry();
if (pointOfEntry != null) {
filter =
CriteriaBuilderHelper.or(cb, filter, cb.equal(casePath.get(Case.POINT_OF_ENTRY).get(PointOfEntry.ID), pointOfEntry.getId()));
if (!currentUserHasRestrictedAccessToAssignedEntities()) {
switch (jurisdictionLevel) {
case REGION:
final Region region = currentUser.getRegion();
if (region != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.REGION).get(Region.ID), region.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_REGION).get(Region.ID), region.getId()));
}
break;
case DISTRICT:
final District district = currentUser.getDistrict();
if (district != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.DISTRICT).get(District.ID), district.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_DISTRICT).get(District.ID), district.getId()));
}
break;
case HEALTH_FACILITY:
final Facility healthFacility = currentUser.getHealthFacility();
if (healthFacility != null) {
filter = CriteriaBuilderHelper
.or(cb, filter, cb.equal(casePath.get(Case.HEALTH_FACILITY).get(Facility.ID), healthFacility.getId()));
}
break;
case COMMUNITY:
final Community community = currentUser.getCommunity();
if (community != null) {
filter = CriteriaBuilderHelper.or(
cb,
filter,
cb.equal(casePath.get(Case.COMMUNITY).get(Community.ID), community.getId()),
cb.equal(casePath.get(Case.RESPONSIBLE_COMMUNITY).get(Community.ID), community.getId()));
}
break;
case POINT_OF_ENTRY:
final PointOfEntry pointOfEntry = currentUser.getPointOfEntry();
if (pointOfEntry != null) {
filter = CriteriaBuilderHelper
.or(cb, filter, cb.equal(casePath.get(Case.POINT_OF_ENTRY).get(PointOfEntry.ID), pointOfEntry.getId()));
}
break;
case LABORATORY:
final Subquery<Long> sampleSubQuery = cq.subquery(Long.class);
final Root<Sample> sampleRoot = sampleSubQuery.from(Sample.class);
final SampleJoins joins = new SampleJoins(sampleRoot);
final Join cazeJoin = joins.getCaze();
sampleSubQuery.where(cb.and(cb.equal(cazeJoin, casePath), sampleService.createUserFilterWithoutAssociations(cb, joins)));
sampleSubQuery.select(sampleRoot.get(Sample.ID));
filter = CriteriaBuilderHelper.or(cb, filter, cb.exists(sampleSubQuery));
break;
default:
}
break;
case LABORATORY:
final Subquery<Long> sampleSubQuery = cq.subquery(Long.class);
final Root<Sample> sampleRoot = sampleSubQuery.from(Sample.class);
final SampleJoins joins = new SampleJoins(sampleRoot);
final Join cazeJoin = joins.getCaze();
sampleSubQuery.where(cb.and(cb.equal(cazeJoin, casePath), sampleService.createUserFilterWithoutAssociations(cb, joins)));
sampleSubQuery.select(sampleRoot.get(Sample.ID));
filter = CriteriaBuilderHelper.or(cb, filter, cb.exists(sampleSubQuery));
break;
default:
}

// get all cases based on the user's contact association
Expand Down Expand Up @@ -1680,12 +1687,20 @@ public EditPermissionType isAddContactAllowed(Case caze) {
return EditPermissionType.REFUSED;
}

if (currentUserHasRestrictedAccessToAssignedEntities() && !DataHelper.equal(caze.getSurveillanceOfficer(), getCurrentUser())) {
return EditPermissionType.REFUSED;
}

return super.getEditPermissionType(caze);
}

@Override
public EditPermissionType getEditPermissionType(Case caze) {

if (currentUserHasRestrictedAccessToAssignedEntities() && !DataHelper.equal(caze.getSurveillanceOfficer(), getCurrentUser())) {
return EditPermissionType.REFUSED;
}

if (!inJurisdictionOrOwned(caze)) {
return EditPermissionType.OUTSIDE_JURISDICTION;
}
Expand Down Expand Up @@ -2337,11 +2352,11 @@ public String getCaseUuidForAutomaticSampleAssignment(Set<String> uuids, Disease
cb.lessThanOrEqualTo(
CriteriaBuilderHelper.dateDiff(
cb,
cb.function(
ExtendedPostgreSQL94Dialect.DATE,
Date.class,
CriteriaBuilderHelper.coalesce(cb, Date.class, earliestSampleSq, caseRoot.get(Case.REPORT_DATE))),
cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(new Date()))),
cb.function(
ExtendedPostgreSQL94Dialect.DATE,
Date.class,
CriteriaBuilderHelper.coalesce(cb, Date.class, earliestSampleSq, caseRoot.get(Case.REPORT_DATE))),
cb.function(ExtendedPostgreSQL94Dialect.DATE, Date.class, cb.literal(new Date()))),
Long.valueOf(TimeUnit.DAYS.toSeconds(automaticSampleAssignmentThreshold)).doubleValue()));

List<String> caseUuids = em.createQuery(cq).getResultList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public class CaseUserFilterCriteria {
private boolean excludeCasesFromContacts;
private Boolean includeCasesFromOtherJurisdictions = Boolean.FALSE;
private boolean excludeLimitedSyncRestrictions;
private boolean restrictAccessToAssignedEntities;

public boolean isExcludeCasesFromContacts() {
return excludeCasesFromContacts;
Expand Down Expand Up @@ -39,4 +40,12 @@ public CaseUserFilterCriteria excludeLimitedSyncRestrictions(boolean excludeLimi
this.excludeLimitedSyncRestrictions = excludeLimitedSyncRestrictions;
return this;
}

public boolean isRestrictAccessToAssignedEntities() {
return restrictAccessToAssignedEntities;
}

public void setRestrictAccessToAssignedEntities(boolean restrictAccessToAssignedEntities) {
this.restrictAccessToAssignedEntities = restrictAccessToAssignedEntities;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ public User getCurrentUser() {
return currentUserService.getCurrentUser();
}

public boolean currentUserHasRestrictedAccessToAssignedEntities() {
return currentUserService.hasRestrictedAccessToAssignedEntities();
}

public boolean hasRight(UserRight right) {
return currentUserService.hasUserRight(right);
}
Expand Down
Loading

0 comments on commit b893fb4

Please sign in to comment.