Skip to content

Commit

Permalink
#663 | Do not remove members when group is removed from user. Do not …
Browse files Browse the repository at this point in the history
…allow removal of members when group is still assigned to user.

(cherry picked from commit 38e5b4e)
  • Loading branch information
himeshr committed Dec 12, 2023
1 parent 42576a9 commit f95af67
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ default GroupSubject findByNameIgnoreCase(String name) {
GroupSubject findByGroupSubjectAndGroupRoleAndIsVoidedFalse(Individual groupSubject, GroupRole headOfHousehold);

List<GroupSubject> findAllByGroupSubjectAndIsVoidedFalse(Individual groupSubject);
List<GroupSubject> findAllByMemberSubjectAndIsVoidedFalse(Individual memberSubject);

List<GroupSubject> findAllByMemberSubjectAndGroupRoleIsVoidedFalseAndIsVoidedFalse(Individual memberSubject);

Expand Down Expand Up @@ -164,4 +165,5 @@ default void updateSyncAttributesForMemberSubject(Long individualId, Long addres
default void updateConceptSyncAttributesForSubjectType(Long subjectTypeId, String syncAttribute1, String syncAttribute2) {
this.updateConceptSyncAttributesForSubjectType(subjectTypeId, syncAttribute1, syncAttribute2, new Date(), UserContextHolder.getUserId());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,4 @@ public class AvniMetaDataRuleService {
public AvniMetaDataRuleService(GroupRoleRepository groupRoleRepository) {
this.groupRoleRepository = groupRoleRepository;
}

/**
* **IMPORTANT** : The response of this method only indicates whether the SubjectType is ** capable ** of being configured for Direct Assignment.
* It **does not** indicate whether the SubjectType has been configured by the organisation administrators to be directly assignable.
*
* @param subjectType
* @return Boolean value indicating whether the SubjectType is capable of being configured for Direct Assignment.
*/
public boolean isDirectAssignmentAllowedFor(SubjectType subjectType) {
return true;
// if (subjectType.isGroup()) return true;
//
// List<GroupRole> groupRolesSubjectTypeIsPartOf = groupRoleRepository.findByMemberSubjectTypeAndIsVoidedFalse(subjectType);
// return groupRolesSubjectTypeIsPartOf.stream().noneMatch(groupRole -> groupRole.getGroupSubjectType().isDirectlyAssignable());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,26 +139,47 @@ public List<UserSubjectAssignment> assignSubjects(UserSubjectAssignmentContract
}

public List<UserSubjectAssignment> assignSubjects(User user, List<Individual> subjectList, boolean assignmentVoided) throws ValidationException {
List<String> errors = new ArrayList<>();
List<UserSubjectAssignment> userSubjectAssignmentList = new ArrayList<>();
Map<SubjectType, List<Individual>> subjectTypeListMap = subjectList.stream().collect(groupingBy(Individual::getSubjectType));
for (Map.Entry<SubjectType, List<Individual>> subjectTypeList : subjectTypeListMap.entrySet()) {
SubjectType subjectType = subjectTypeList.getKey();
List<Individual> listOfSubjects = subjectTypeList.getValue();
List<Long> addressLevels = addressLevelService.getAllRegistrationAddressIdsBySubjectType(user.getCatchment(), subjectType);
for (Individual subject : listOfSubjects) {
if (!avniMetaDataRuleService.isDirectAssignmentAllowedFor(subject.getSubjectType())) {
throw new ValidationException("Assigment of this subject cannot be done because it is of subject type that is part of another group");
try {
checkIfSubjectLiesWithinUserCatchment(assignmentVoided, subject, addressLevels);
checkIfSubjectIsPartOfGroupAssignedToUser(assignmentVoided, user, subject);
createUpdateAssignment(assignmentVoided, userSubjectAssignmentList, user, subject);
} catch (Exception ve) {
errors.add(ve.getMessage());
}
checkIfSubjectLiesWithinUserCatchment(assignmentVoided, subject, addressLevels);
createUpdateAssignment(assignmentVoided, userSubjectAssignmentList, user, subject);
}
}
return this.saveAll(userSubjectAssignmentList);
if(errors.isEmpty()) {
return this.saveAll(userSubjectAssignmentList);
} else {
throw new ValidationException("Errors: \n"+ String.join(";\n", errors));
}
}

private void checkIfSubjectIsPartOfGroupAssignedToUser(boolean assignmentVoided, User user, Individual subject) throws ValidationException {
if (assignmentVoided && !subject.getSubjectType().isGroup()) {
List<GroupSubject> groupSubjects = groupSubjectRepository.findAllByMemberSubjectAndIsVoidedFalse(subject);
for (GroupSubject groupSubject : groupSubjects) {
UserSubjectAssignment userGroupSubjectAssignment = userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user, groupSubject.getGroupSubject());
if(userGroupSubjectAssignment != null && !groupSubject.getGroupSubject().isVoided()) {
throw new ValidationException(String.format("Individual (%s) cant be unassigned from the user (%s), since group (%s) that the member (%s) belongs to, is assigned to the user (%s)",
subject.getFullName(), user.getUsername(), groupSubject.getGroupSubject().getFullName(), subject.getFullName(), user.getUsername()));
}
}

}
}

private void checkIfSubjectLiesWithinUserCatchment(boolean assignmentVoided, Individual subject, List<Long> addressLevels) throws ValidationException {
if(!assignmentVoided && !addressLevels.contains(subject.getAddressLevel().getId())) {
throw new ValidationException("Assigment of subject(s) cannot be done because they are outside the User's Catchment");
throw new ValidationException(String.format("Assigment of Individual (%s) cannot be done because it is outside the User's Catchment", subject.getFullName()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.jdbc.Sql;

import java.util.Arrays;
import java.util.Collections;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.*;

@Sql(scripts = {"/tear-down.sql"}, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@Sql(scripts = {"/tear-down.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
Expand Down Expand Up @@ -72,4 +72,77 @@ public void on_addition_of_member_to_a_group__assign_member_to_the_user_assigned
testGroupSubjectService.save(new TestGroupSubjectBuilder().withGroupRole(groupRoleInvolvingDirectAssignment).withMember(directlyAssignableMember).withGroup(group2).build());
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember));
}

@Test
public void on_removal_of_a_group__retain_members_assigned_to_the_user() throws ValidationException {
TestDataSetupService.TestOrganisationData testOrganisationData = testDataSetupService.setupOrganisation();
TestDataSetupService.TestCatchmentData testCatchmentData = testDataSetupService.setupACatchment();

SubjectType groupSubjectType = testSubjectTypeService.createWithDefaults(new SubjectTypeBuilder().setMandatoryFieldsForNewEntity().setUuid("st_GroupForDirectAssignment").setName("st_GroupForDirectAssignment").setDirectlyAssignable(true).setGroup(true).build());
SubjectType memberSubjectType = testSubjectTypeService.createWithDefaults(new SubjectTypeBuilder().setMandatoryFieldsForNewEntity().setUuid("st_DirectAssignment").setName("st_DirectAssignment").setDirectlyAssignable(true).build());
GroupRole groupRoleInvolvingDirectAssignment = groupRoleRepository.save(new TestGroupRoleBuilder().withMandatoryFieldsForNewEntity().withGroupSubjectType(groupSubjectType).withMemberSubjectType(memberSubjectType).build());

Individual group = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(groupSubjectType).withLocation(testCatchmentData.getAddressLevel1()).build());
Individual directlyAssignableMember1 = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withLocation(testCatchmentData.getAddressLevel1()).withSubjectType(memberSubjectType).build());
Individual directlyAssignableMember2 = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withLocation(testCatchmentData.getAddressLevel1()).withSubjectType(memberSubjectType).build());

User user1 = userRepository.save(new UserBuilder().withCatchment(testCatchmentData.getCatchment()).withDefaultValuesForNewEntity().userName("user1@example").withAuditUser(testOrganisationData.getUser()).organisationId(testOrganisationData.getOrganisationId()).build());

testGroupSubjectService.save(new TestGroupSubjectBuilder().withGroupRole(groupRoleInvolvingDirectAssignment).withMember(directlyAssignableMember1).withGroup(group).build());
userSubjectAssignmentService.assignSubjects(user1, Collections.singletonList(group), false);
testGroupSubjectService.save(new TestGroupSubjectBuilder().withGroupRole(groupRoleInvolvingDirectAssignment).withMember(directlyAssignableMember2).withGroup(group).build());

// Confirm that User has the 2 members as well as the group assigned
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, group));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember1));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember2));

// Remove group from user
userSubjectAssignmentService.assignSubjects(user1, Collections.singletonList(group), true);

// Confirm that User still has the 2 members assigned, but not the group
assertNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, group));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember1));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember2));

}

@Test
public void on_removal_of_members_whose_group_is_still_assigned_to_user__retain_members_and_group_and_throw_error() throws ValidationException {
TestDataSetupService.TestOrganisationData testOrganisationData = testDataSetupService.setupOrganisation();
TestDataSetupService.TestCatchmentData testCatchmentData = testDataSetupService.setupACatchment();

SubjectType groupSubjectType = testSubjectTypeService.createWithDefaults(new SubjectTypeBuilder().setMandatoryFieldsForNewEntity().setUuid("st_GroupForDirectAssignment").setName("st_GroupForDirectAssignment").setDirectlyAssignable(true).setGroup(true).build());
SubjectType memberSubjectType = testSubjectTypeService.createWithDefaults(new SubjectTypeBuilder().setMandatoryFieldsForNewEntity().setUuid("st_DirectAssignment").setName("st_DirectAssignment").setDirectlyAssignable(true).build());
GroupRole groupRoleInvolvingDirectAssignment = groupRoleRepository.save(new TestGroupRoleBuilder().withMandatoryFieldsForNewEntity().withGroupSubjectType(groupSubjectType).withMemberSubjectType(memberSubjectType).build());

Individual group = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withSubjectType(groupSubjectType).withLocation(testCatchmentData.getAddressLevel1()).build());
Individual directlyAssignableMember1 = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withLocation(testCatchmentData.getAddressLevel1()).withSubjectType(memberSubjectType).build());
Individual directlyAssignableMember2 = individualService.save(new SubjectBuilder().withMandatoryFieldsForNewEntity().withLocation(testCatchmentData.getAddressLevel1()).withSubjectType(memberSubjectType).build());

User user1 = userRepository.save(new UserBuilder().withCatchment(testCatchmentData.getCatchment()).withDefaultValuesForNewEntity().userName("user1@example").withAuditUser(testOrganisationData.getUser()).organisationId(testOrganisationData.getOrganisationId()).build());

testGroupSubjectService.save(new TestGroupSubjectBuilder().withGroupRole(groupRoleInvolvingDirectAssignment).withMember(directlyAssignableMember1).withGroup(group).build());
testGroupSubjectService.save(new TestGroupSubjectBuilder().withGroupRole(groupRoleInvolvingDirectAssignment).withMember(directlyAssignableMember2).withGroup(group).build());
userSubjectAssignmentService.assignSubjects(user1, Collections.singletonList(group), false);

// Confirm that User has the 2 members as well as the group assigned
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, group));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember1));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember2));

// Remove member1 from user
try {
userSubjectAssignmentService.assignSubjects(user1, Arrays.asList(directlyAssignableMember1, directlyAssignableMember2),
true);
fail("Members should not have got removed from group");
} catch (Exception e) {
}

// Confirm that User still has the 2 members assigned, along with the group
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, group));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember1));
assertNotNull(userSubjectAssignmentRepository.findByUserAndSubjectAndIsVoidedFalse(user1, directlyAssignableMember2));

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ public void assigningSubjectShouldAssignMemberSubjects() throws ValidationExcept
when(groupSubjectRepository.findAllByGroupSubjectAndIsVoidedFalse(group)).thenReturn(Collections.singletonList(new TestGroupSubjectBuilder().setId(1l).withGroup(group)
.withMember(new SubjectBuilder().setId(2).withLocation(addressLevelWithinCatchment).withSubjectType(new SubjectTypeBuilder().setGroup(false).build()).setId(2).build()).build()));
when(groupPrivilegeService.getGroupPrivileges(any())).thenReturn(new GroupPrivileges(false));
when(avniMetaDataRuleService.isDirectAssignmentAllowedFor(any())).thenReturn(true);
when(addressLevelService.getAllRegistrationAddressIdsBySubjectType(any(), any())).thenReturn(catchment.getAddressLevels().stream().map(AddressLevel::getId).collect(Collectors.toList()));


Expand All @@ -104,7 +103,6 @@ public void assigningSubjectOutsideUserCatchmentShouldFail() throws ValidationEx
when(groupSubjectRepository.findAllByGroupSubjectAndIsVoidedFalse(group)).thenReturn(Collections.singletonList(new TestGroupSubjectBuilder().setId(1l).withGroup(group)
.withMember(new SubjectBuilder().setId(2).withLocation(addressLevelWithinCatchment).withSubjectType(new SubjectTypeBuilder().setGroup(false).build()).setId(2).build()).build()));
when(groupPrivilegeService.getGroupPrivileges(any())).thenReturn(new GroupPrivileges(false));
when(avniMetaDataRuleService.isDirectAssignmentAllowedFor(any())).thenReturn(true);
when(addressLevelService.getAllRegistrationAddressIdsBySubjectType(any(), any())).thenReturn(catchment.getAddressLevels().stream().map(AddressLevel::getId).collect(Collectors.toList()));

userSubjectAssignmentService.assignSubjects(userSubjectAssignmentContract);
Expand All @@ -119,7 +117,6 @@ public void assigningGrpSubjectInsideCatchmentWithMemberSubjectOutsideUserCatchm
when(groupSubjectRepository.findAllByGroupSubjectAndIsVoidedFalse(group)).thenReturn(Collections.singletonList(new TestGroupSubjectBuilder().setId(1l).withGroup(group)
.withMember(new SubjectBuilder().setId(2).withLocation(addressLevelOutsideCatchment).withSubjectType(new SubjectTypeBuilder().setGroup(false).build()).setId(2).build()).build()));
when(groupPrivilegeService.getGroupPrivileges(any())).thenReturn(new GroupPrivileges(false));
when(avniMetaDataRuleService.isDirectAssignmentAllowedFor(any())).thenReturn(true);
when(addressLevelService.getAllRegistrationAddressIdsBySubjectType(any(), any())).thenReturn(catchment.getAddressLevels().stream().map(AddressLevel::getId).collect(Collectors.toList()));

userSubjectAssignmentService.assignSubjects(userSubjectAssignmentContract);
Expand All @@ -139,13 +136,11 @@ public void assigningVoidedGrpSubjectInsideCatchmentWithMemberSubjectOutsideUser
when(groupSubjectRepository.findAllByGroupSubjectAndIsVoidedFalse(group)).thenReturn(Collections.singletonList(new TestGroupSubjectBuilder().setId(1l).withGroup(group)
.withMember(new SubjectBuilder().setId(2).withLocation(addressLevelOutsideCatchment).withSubjectType(new SubjectTypeBuilder().setGroup(false).build()).setId(2).build()).build()));
when(groupPrivilegeService.getGroupPrivileges(any())).thenReturn(new GroupPrivileges(false));
when(avniMetaDataRuleService.isDirectAssignmentAllowedFor(any())).thenReturn(true);
when(addressLevelService.getAllRegistrationAddressIdsBySubjectType(any(), any())).thenReturn(catchment.getAddressLevels().stream().map(AddressLevel::getId).collect(Collectors.toList()));

userSubjectAssignmentService.assignSubjects(userSubjectAssignmentContract);
verify(userSubjectAssignmentRepository, times(2)).save(userSubjectAssignmentCaptor.capture());
verify(userSubjectAssignmentRepository, times(1)).save(userSubjectAssignmentCaptor.capture());
List<UserSubjectAssignment> usa = userSubjectAssignmentCaptor.getAllValues();
assertEquals(usa.get(0).getUser().getId().longValue(), 1l);
assertEquals(usa.get(1).getUser().getId().longValue(), 1l);
}
}

0 comments on commit f95af67

Please sign in to comment.