@@ -126,6 +126,10 @@ class TrackerAccessManagerTest extends PostgresIntegrationTestBase {
126126
127127 private TrackerEvent eventB ;
128128
129+ private TrackerEvent trackerEvent ;
130+
131+ private org .hisp .dhis .tracker .model .Enrollment enrollmentForAoc ;
132+
129133 private SingleEvent singleEvent ;
130134
131135 private CategoryOption oldCatOption ;
@@ -243,6 +247,48 @@ void setUp() {
243247 newCatOption .getCategoryOptionCombos ().add (newAoc );
244248 categoryService .updateCategoryOption (newCatOption );
245249
250+ trackedEntityType .setPublicAccess (AccessStringHelper .FULL );
251+ manager .update (trackedEntityType );
252+
253+ ProgramStage trackerEventProgramStage = createProgramStage ('M' , 0 );
254+ manager .save (trackerEventProgramStage );
255+
256+ Program trackerEventProgram = createProgram ('M' , new HashSet <>(), orgUnitA );
257+ trackerEventProgram .setProgramType (ProgramType .WITH_REGISTRATION );
258+ trackerEventProgram .setAccessLevel (AccessLevel .PROTECTED );
259+ trackerEventProgram .setTrackedEntityType (trackedEntityType );
260+ trackerEventProgramStage .setProgram (trackerEventProgram );
261+ trackerEventProgram .getProgramStages ().add (trackerEventProgramStage );
262+ manager .save (trackerEventProgram );
263+ trackerEventProgram .setPublicAccess (AccessStringHelper .DATA_READ_WRITE );
264+ manager .update (trackerEventProgram );
265+ trackerEventProgramStage .setPublicAccess (AccessStringHelper .DATA_READ_WRITE );
266+ manager .update (trackerEventProgramStage );
267+
268+ TrackedEntity trackerEventTe = createTrackedEntity (orgUnitA , trackedEntityType );
269+ manager .save (trackerEventTe );
270+
271+ Enrollment trackerEventEnrollment =
272+ createEnrollment (trackerEventProgram , trackerEventTe , orgUnitA );
273+ manager .save (trackerEventEnrollment );
274+ trackerEventTe .getEnrollments ().add (trackerEventEnrollment );
275+ manager .update (trackerEventTe );
276+
277+ trackedEntityProgramOwnerService .createTrackedEntityProgramOwner (
278+ trackerEventTe , trackerEventProgram , orgUnitA );
279+
280+ trackerEvent = new TrackerEvent ();
281+ trackerEvent .setEnrollment (trackerEventEnrollment );
282+ trackerEvent .setProgramStage (trackerEventProgramStage );
283+ trackerEvent .setOrganisationUnit (orgUnitA );
284+ trackerEvent .setAttributeOptionCombo (oldAoc );
285+ trackerEvent .setOccurredDate (new Date ());
286+ manager .save (trackerEvent , false );
287+
288+ enrollmentForAoc = createEnrollment (trackerEventProgram , trackerEventTe , orgUnitA );
289+ enrollmentForAoc .setAttributeOptionCombo (oldAoc );
290+ manager .save (enrollmentForAoc );
291+
246292 ProgramStage singleEventProgramStage = createProgramStage ('C' , 0 );
247293 manager .save (singleEventProgramStage );
248294
@@ -357,7 +403,11 @@ void checkAccessPermissionForEnrollmentInClosedProgram()
357403 assertNoErrors (trackerAccessManager .canCreate (userDetails , enrollment ));
358404 // Can update enrollment
359405 assertNoErrors (
360- trackerAccessManager .canUpdate (userDetails , enrollment , enrollment .getOrganisationUnit ()));
406+ trackerAccessManager .canUpdate (
407+ userDetails ,
408+ enrollment ,
409+ enrollment .getOrganisationUnit (),
410+ enrollment .getAttributeOptionCombo ()));
361411 // Can delete enrollment
362412 assertNoErrors (trackerAccessManager .canDelete (userDetails , enrollment ));
363413 // Can read enrollment
@@ -373,7 +423,11 @@ void checkAccessPermissionForEnrollmentInClosedProgram()
373423 assertHasErrorMessage (trackerAccessManager .canCreate (userDetails , enrollment ), E1102 );
374424 // Cannot update enrollment if not owner
375425 assertHasErrorMessage (
376- trackerAccessManager .canUpdate (userDetails , enrollment , enrollment .getOrganisationUnit ()),
426+ trackerAccessManager .canUpdate (
427+ userDetails ,
428+ enrollment ,
429+ enrollment .getOrganisationUnit (),
430+ enrollment .getAttributeOptionCombo ()),
377431 E1102 );
378432 // Cannot delete enrollment if not owner
379433 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , enrollment ), E1102 );
@@ -399,7 +453,11 @@ void checkAccessPermissionForEnrollmentInOpenProgram()
399453 assertHasError (trackerAccessManager .canCreate (userDetails , enrollment ));
400454 // Can update enrollment if ownerOU falls inside search scope
401455 assertNoErrors (
402- trackerAccessManager .canUpdate (userDetails , enrollment , enrollment .getOrganisationUnit ()));
456+ trackerAccessManager .canUpdate (
457+ userDetails ,
458+ enrollment ,
459+ enrollment .getOrganisationUnit (),
460+ enrollment .getAttributeOptionCombo ()));
403461 // Cannot delete enrollment if enrollmentOU fails outside capture scope
404462 assertHasError (trackerAccessManager .canDelete (userDetails , enrollment ));
405463 // Can read enrollment if ownerOU falls inside search scope
@@ -412,7 +470,11 @@ void checkAccessPermissionForEnrollmentInOpenProgram()
412470 assertHasErrorMessage (trackerAccessManager .canCreate (userDetails , enrollment ), E1000 );
413471 // Can update enrollment
414472 assertNoErrors (
415- trackerAccessManager .canUpdate (userDetails , enrollment , enrollment .getOrganisationUnit ()));
473+ trackerAccessManager .canUpdate (
474+ userDetails ,
475+ enrollment ,
476+ enrollment .getOrganisationUnit (),
477+ enrollment .getAttributeOptionCombo ()));
416478 // Cannot delete enrollment if enrollmentOU falls outside capture scope,
417479 // even if user is owner
418480 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , enrollment ), E1000 );
@@ -430,7 +492,11 @@ void checkAccessPermissionForEnrollmentInOpenProgram()
430492 assertHasErrorMessage (trackerAccessManager .canCreate (userDetails , enrollment ), E1000 );
431493 // Can update enrollment if ownerOU is in search scope
432494 assertNoErrors (
433- trackerAccessManager .canUpdate (userDetails , enrollment , enrollment .getOrganisationUnit ()));
495+ trackerAccessManager .canUpdate (
496+ userDetails ,
497+ enrollment ,
498+ enrollment .getOrganisationUnit (),
499+ enrollment .getAttributeOptionCombo ()));
434500 // Cannot delete enrollment if enrollment OU is outside capture scope
435501 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , enrollment ), E1000 );
436502 // Can read enrollment if ownerOU is in search scope
@@ -465,7 +531,8 @@ void checkAccessPermissionsForEventInClosedProgram()
465531 assertNoErrors (trackerAccessManager .canRead (userDetails , eventA ));
466532 // Can update events if owner org unit falls into users search scope
467533 assertNoErrors (
468- trackerAccessManager .canUpdate (userDetails , eventA , eventA .getOrganisationUnit ()));
534+ trackerAccessManager .canUpdate (
535+ userDetails , eventA , eventA .getOrganisationUnit (), eventA .getAttributeOptionCombo ()));
469536 // Can delete events if event org unit and owner org unit in capture scope
470537 assertNoErrors (trackerAccessManager .canDelete (userDetails , eventA ));
471538
@@ -482,7 +549,8 @@ void checkAccessPermissionsForEventInClosedProgram()
482549 assertNoErrors (trackerAccessManager .canRead (userDetails , eventB ));
483550 // Can update events if user is owner irrespective of eventOU
484551 assertNoErrors (
485- trackerAccessManager .canUpdate (userDetails , eventB , eventB .getOrganisationUnit ()));
552+ trackerAccessManager .canUpdate (
553+ userDetails , eventB , eventB .getOrganisationUnit (), eventB .getAttributeOptionCombo ()));
486554 // Cannot delete events outside capture scope even if user is owner
487555 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , eventB ), E1000 );
488556 trackerOwnershipManager .transferOwnership (trackedEntityA , programA .getUID (), orgUnitB .getUID ());
@@ -492,7 +560,9 @@ void checkAccessPermissionsForEventInClosedProgram()
492560 assertHasErrorMessage (trackerAccessManager .canRead (userDetails , eventB ), E1102 );
493561 // Cannot update events if user is not owner (OwnerOU falls into capture scope)
494562 assertHasErrorMessage (
495- trackerAccessManager .canUpdate (userDetails , eventB , eventB .getOrganisationUnit ()), E1102 );
563+ trackerAccessManager .canUpdate (
564+ userDetails , eventB , eventB .getOrganisationUnit (), eventB .getAttributeOptionCombo ()),
565+ E1102 );
496566 // Cannot delete events anywhere if user is not owner and event org unit not in capture scope
497567 assertHasErrors (2 , trackerAccessManager .canDelete (userDetails , eventB ));
498568 }
@@ -519,7 +589,8 @@ void checkAccessPermissionsForEventInOpenProgram()
519589 assertNoErrors (trackerAccessManager .canRead (userDetails , eventA ));
520590 // Can update events if owner org unit falls into users search scope
521591 assertNoErrors (
522- trackerAccessManager .canUpdate (userDetails , eventA , eventA .getOrganisationUnit ()));
592+ trackerAccessManager .canUpdate (
593+ userDetails , eventA , eventA .getOrganisationUnit (), eventA .getAttributeOptionCombo ()));
523594 // Can delete events if event org unit and owner org unit in capture scope
524595 assertNoErrors (trackerAccessManager .canDelete (userDetails , eventA ));
525596
@@ -532,7 +603,8 @@ void checkAccessPermissionsForEventInOpenProgram()
532603 assertNoErrors (trackerAccessManager .canRead (userDetails , eventA ));
533604 // Can update events if ownerOu falls into users search scope
534605 assertNoErrors (
535- trackerAccessManager .canUpdate (userDetails , eventA , eventA .getOrganisationUnit ()));
606+ trackerAccessManager .canUpdate (
607+ userDetails , eventA , eventA .getOrganisationUnit (), eventA .getAttributeOptionCombo ()));
536608 // Cannot delete events with event ou outside capture scope
537609 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , eventA ), E1000 );
538610 trackerOwnershipManager .transferOwnership (trackedEntityA , programA .getUID (), orgUnitB .getUID ());
@@ -544,7 +616,8 @@ void checkAccessPermissionsForEventInOpenProgram()
544616 assertNoErrors (trackerAccessManager .canRead (userDetails , eventA ));
545617 // Can update events if ownerOu falls into users capture scope
546618 assertNoErrors (
547- trackerAccessManager .canUpdate (userDetails , eventA , eventA .getOrganisationUnit ()));
619+ trackerAccessManager .canUpdate (
620+ userDetails , eventA , eventA .getOrganisationUnit (), eventA .getAttributeOptionCombo ()));
548621 // Cannot delete events with eventOu outside capture scope, even if ownerOu is also in capture
549622 // scope
550623 assertHasErrorMessage (trackerAccessManager .canDelete (userDetails , eventA ), E1000 );
@@ -561,7 +634,10 @@ void shouldFailToUpdateEnrollmentWhenUserLacksAccess() {
561634 assertEnrollmentCategoryOptionAccessFails (
562635 (userDetails , enrollment ) ->
563636 trackerAccessManager .canUpdate (
564- userDetails , enrollment , enrollment .getOrganisationUnit ()));
637+ userDetails ,
638+ enrollment ,
639+ enrollment .getOrganisationUnit (),
640+ enrollment .getAttributeOptionCombo ()));
565641 }
566642
567643 @ Test
@@ -677,4 +753,88 @@ private void assertHasError(List<?> errors) {
677753 private void assertHasErrors (int errorNumber , List <?> errors ) {
678754 assertEquals (errorNumber , errors .size ());
679755 }
756+
757+ @ Test
758+ void shouldPassWhenUpdatingEnrollmentWithAccessToBothOldAndNewAoc () {
759+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
760+ assertNoErrors (
761+ trackerAccessManager .canUpdate (fromUser (user ), enrollmentForAoc , orgUnitA , newAoc ));
762+ }
763+
764+ @ Test
765+ void shouldFailWhenUpdatingEnrollmentWithAccessOnlyToNewAoc () {
766+ oldCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
767+ manager .update (oldCatOption );
768+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
769+ assertHasErrorMessage (
770+ trackerAccessManager .canUpdate (fromUser (user ), enrollmentForAoc , orgUnitA , newAoc ), E1099 );
771+ }
772+
773+ @ Test
774+ void shouldFailWhenUpdatingEnrollmentWithAccessOnlyToOldAoc () {
775+ newCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
776+ manager .update (newCatOption );
777+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
778+ assertHasErrorMessage (
779+ trackerAccessManager .canUpdate (fromUser (user ), enrollmentForAoc , orgUnitA , newAoc ), E1099 );
780+ }
781+
782+ @ Test
783+ void shouldPassWhenUpdatingEnrollmentWithNoAocChangeAndUserHasAccess () {
784+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
785+ assertNoErrors (
786+ trackerAccessManager .canUpdate (fromUser (user ), enrollmentForAoc , orgUnitA , oldAoc ));
787+ }
788+
789+ @ Test
790+ void shouldFailWhenUpdatingEnrollmentWithNoAccessToEitherAoc () {
791+ oldCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
792+ manager .update (oldCatOption );
793+ newCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
794+ manager .update (newCatOption );
795+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
796+ assertHasErrors (
797+ 2 , trackerAccessManager .canUpdate (fromUser (user ), enrollmentForAoc , orgUnitA , newAoc ));
798+ }
799+
800+ @ Test
801+ void shouldPassWhenUpdatingTrackerEventWithAccessToBothOldAndNewAoc () {
802+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
803+ assertNoErrors (trackerAccessManager .canUpdate (fromUser (user ), trackerEvent , orgUnitA , newAoc ));
804+ }
805+
806+ @ Test
807+ void shouldFailWhenUpdatingTrackerEventWithAccessOnlyToNewAoc () {
808+ oldCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
809+ manager .update (oldCatOption );
810+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
811+ assertHasErrorMessage (
812+ trackerAccessManager .canUpdate (fromUser (user ), trackerEvent , orgUnitA , newAoc ), E1099 );
813+ }
814+
815+ @ Test
816+ void shouldFailWhenUpdatingTrackerEventWithAccessOnlyToOldAoc () {
817+ newCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
818+ manager .update (newCatOption );
819+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
820+ assertHasErrorMessage (
821+ trackerAccessManager .canUpdate (fromUser (user ), trackerEvent , orgUnitA , newAoc ), E1099 );
822+ }
823+
824+ @ Test
825+ void shouldPassWhenUpdatingTrackerEventWithNoAocChangeAndUserHasAccess () {
826+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
827+ assertNoErrors (trackerAccessManager .canUpdate (fromUser (user ), trackerEvent , orgUnitA , oldAoc ));
828+ }
829+
830+ @ Test
831+ void shouldFailWhenUpdatingTrackerEventWithNoAccessToEitherAoc () {
832+ oldCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
833+ manager .update (oldCatOption );
834+ newCatOption .getSharing ().setPublicAccess (CATEGORY_NO_DATA_SHARING_DEFAULT );
835+ manager .update (newCatOption );
836+ User user = createUserWithAuth ("user1" ).setOrganisationUnits (Sets .newHashSet (orgUnitA ));
837+ assertHasErrors (
838+ 2 , trackerAccessManager .canUpdate (fromUser (user ), trackerEvent , orgUnitA , newAoc ));
839+ }
680840}
0 commit comments