diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java index 5130eee5ca..aaff68c0b0 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/PolicyUtils.java @@ -50,7 +50,13 @@ public class PolicyUtils { // TODO: Investigate a solution without using deep-copy. final Map policyMap1 = new HashMap<>(); for (Map.Entry entry : policyMap.entrySet()) { - policyMap1.put(entry.getKey(), entry.getValue()); + Policy entryValue = entry.getValue(); + Policy policy = Policy.builder() + .users(new HashSet<>(entryValue.getUsers())) + .permission(entryValue.getPermission()) + .groups(new HashSet<>(entryValue.getGroups())) + .build(); + policyMap1.put(entry.getKey(), policy); } // Append the user to the existing permission policy if it already exists. @@ -221,7 +227,7 @@ public class PolicyUtils { .saveAll(updatedPages)); } - public Flux updateWithApplicationPermissionsToAllItsCommentThreads( + public Flux updateCommentThreadPermissions( String applicationId, Map commentThreadPolicyMap, String username, boolean addPolicyToObject) { return diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationService.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationService.java index 8a8533bd8c..0d12f43318 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationService.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationService.java @@ -10,16 +10,12 @@ import java.util.List; public interface UserOrganizationService { Mono addUserToOrganization(String orgId, User user); - Mono saveUser(User user); - Mono addUserRoleToOrganization(String orgId, UserRole userRole); Mono addUserToOrganizationGivenUserObject(Organization organization, User user, UserRole userRole); Mono leaveOrganization(String orgId); - Mono removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user); - Mono updateRoleForMember(String orgId, UserRole userRole, String originHeader); Mono bulkAddUsersToOrganization(Organization organization, List users, String roleName); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java index aa1e6b14c8..ac4aee2103 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserOrganizationServiceImpl.java @@ -120,11 +120,6 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { .flatMap(userRepository::save); } - @Override - public Mono saveUser(User user) { - return userRepository.save(user); - } - @Override public Mono addUserRoleToOrganization(String orgId, UserRole userRole) { Mono organizationMono = organizationRepository.findById(orgId, MANAGE_ORGANIZATIONS) @@ -169,7 +164,9 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { Map datasourcePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(orgPolicyMap, Organization.class, Datasource.class); Map pagePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(applicationPolicyMap, Application.class, Page.class); Map actionPolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(pagePolicyMap, Page.class, Action.class); - + Map commentThreadPolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies( + applicationPolicyMap, Application.class, CommentThread.class + ); //Now update the organization policies Organization updatedOrganization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization); updatedOrganization.setUserRoles(userRoles); @@ -182,13 +179,21 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { .flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsPages(application.getId(), pagePolicyMap, true)); Flux updatedActionsFlux = updatedApplicationsFlux .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true)); + Flux updatedThreadsFlux = updatedApplicationsFlux + .flatMap(application -> policyUtils.updateCommentThreadPermissions(application.getId(), commentThreadPolicyMap, user.getUsername(), true)); - return Mono.zip(updatedDatasourcesFlux.collectList(), updatedPagesFlux.collectList(), updatedActionsFlux.collectList(), Mono.just(updatedOrganization)) - .flatMap(tuple -> { - //By now all the datasources/applications/pages/actions have been updated. Just save the organization now - Organization updatedOrgBeforeSave = tuple.getT4(); - return organizationRepository.save(updatedOrgBeforeSave); - }); + return Mono.zip( + updatedDatasourcesFlux.collectList(), + updatedPagesFlux.collectList(), + updatedActionsFlux.collectList(), + Mono.just(updatedOrganization), + updatedThreadsFlux.collectList() + ) + .flatMap(tuple -> { + //By now all the datasources/applications/pages/actions have been updated. Just save the organization now + Organization updatedOrgBeforeSave = tuple.getT4(); + return organizationRepository.save(updatedOrgBeforeSave); + }); } @Override @@ -212,8 +217,7 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { }); } - @Override - public Mono removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user) { + private Mono removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user) { List userRoles = organization.getUserRoles(); if (userRoles == null) { return Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER + " in organization", organization.getName())); @@ -258,7 +262,7 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { Flux updatedActionsFlux = updatedApplicationsFlux .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, false)); Flux updatedThreadsFlux = updatedApplicationsFlux - .flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads( + .flatMap(application -> policyUtils.updateCommentThreadPermissions( application.getId(), commentThreadPolicyMap, user.getUsername(), false )); @@ -434,7 +438,7 @@ public class UserOrganizationServiceImpl implements UserOrganizationService { Flux updatedActionsFlux = updatedApplicationsFlux .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true)); Flux updatedThreadsFlux = updatedApplicationsFlux - .flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads( + .flatMap(application -> policyUtils.updateCommentThreadPermissions( application.getId(), commentThreadPolicyMap, null, true )); diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/PolicyUtilsTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/PolicyUtilsTest.java new file mode 100644 index 0000000000..bb6aec84bb --- /dev/null +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/helpers/PolicyUtilsTest.java @@ -0,0 +1,138 @@ +package com.appsmith.server.helpers; + +import com.appsmith.external.models.Policy; +import com.appsmith.server.acl.AclPermission; +import com.appsmith.server.domains.CommentThread; +import com.appsmith.server.domains.User; +import com.appsmith.server.repositories.CommentThreadRepository; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.security.test.context.support.WithUserDetails; +import org.springframework.test.context.junit4.SpringRunner; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@RunWith(SpringRunner.class) +public class PolicyUtilsTest { + + @Autowired + private PolicyUtils policyUtils; + + @Autowired + private CommentThreadRepository commentThreadRepository; + + @Before + public void cleanUp() { + commentThreadRepository.deleteAll().block(); + } + + @Test + @WithUserDetails("api_user") + public void updateWithApplicationPermissionsToAllItsCommentThreads_AddPermissions_PermissionsAdded() { + // create a thread + String testApplicationId = "test-application-id"; + CommentThread commentThread = new CommentThread(); + commentThread.setApplicationId(testApplicationId); + Map commentThreadPolicies = policyUtils.generatePolicyFromPermission( + Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), "api_user" + ); + commentThread.setPolicies(Set.copyOf(commentThreadPolicies.values())); + Mono saveThreadMono = commentThreadRepository.save(commentThread); + + // add a new user and update the policies of the new user + String newUserName = "new_test_user"; + Map commentThreadPoliciesForNewUser = policyUtils.generatePolicyFromPermission( + Set.of(AclPermission.COMMENT_ON_THREAD), newUserName + ); + Flux updateCommentThreads = policyUtils.updateCommentThreadPermissions( + testApplicationId, commentThreadPoliciesForNewUser, newUserName, true + ); + + // check if new policies updated + Mono> applicationCommentList = saveThreadMono + .thenMany(updateCommentThreads) + .collectList() + .thenMany(commentThreadRepository.findByApplicationId(testApplicationId, AclPermission.READ_THREAD)) + .collectList(); + + StepVerifier.create(applicationCommentList) + .assertNext(commentThreads -> { + assertThat(commentThreads.size()).isEqualTo(1); + CommentThread commentThread1 = commentThreads.get(0); + Set policies = commentThread1.getPolicies(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.MANAGE_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.MANAGE_THREAD.getValue(), newUserName)).isFalse(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.READ_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.READ_THREAD.getValue(), newUserName)).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.COMMENT_ON_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.COMMENT_ON_THREAD.getValue(), newUserName)).isTrue(); + }) + .verifyComplete(); + } + + @Test + @WithUserDetails("api_user") + public void updateWithApplicationPermissionsToAllItsCommentThreads_RemovePermissions_PermissionsRemoved() { + String newUserName = "new_test_user"; + + // create a thread with two users having permission on it + String testApplicationId = "test-application-id"; + CommentThread commentThread = new CommentThread(); + commentThread.setApplicationId(testApplicationId); + commentThread.setPolicies(new HashSet<>()); + + User user1 = new User(); + user1.setEmail("api_user"); + + User user2 = new User(); + user2.setEmail(newUserName); + + Map commentThreadPolicies = policyUtils.generatePolicyFromPermissionForMultipleUsers( + Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), List.of(user1, user2) + ); + + commentThread.setPolicies(Set.copyOf(commentThreadPolicies.values())); + Mono saveThreadMono = commentThreadRepository.save(commentThread); + + // remove an user and update the policies of the user + Map commentThreadPoliciesForNewUser = policyUtils.generatePolicyFromPermission( + Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), newUserName + ); + Flux updateCommentThreads = policyUtils.updateCommentThreadPermissions( + testApplicationId, commentThreadPoliciesForNewUser, newUserName, false + ); + + // check if new policies updated + Mono> applicationCommentList = saveThreadMono + .thenMany(updateCommentThreads) + .collectList() + .thenMany(commentThreadRepository.findByApplicationId(testApplicationId, AclPermission.READ_THREAD)) + .collectList(); + + StepVerifier.create(applicationCommentList) + .assertNext(commentThreads -> { + assertThat(commentThreads.size()).isEqualTo(1); + CommentThread commentThread1 = commentThreads.get(0); + Set policies = commentThread1.getPolicies(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.MANAGE_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.MANAGE_THREAD.getValue(), newUserName)).isFalse(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.READ_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.READ_THREAD.getValue(), newUserName)).isFalse(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.COMMENT_ON_THREAD.getValue(), "api_user")).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser(policies, AclPermission.COMMENT_ON_THREAD.getValue(), newUserName)).isFalse(); + }) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserOrganizationServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserOrganizationServiceTest.java index 7d0066df46..425e70ef3b 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserOrganizationServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserOrganizationServiceTest.java @@ -1,11 +1,19 @@ package com.appsmith.server.services; +import com.appsmith.external.models.Policy; +import com.appsmith.server.acl.AclPermission; import com.appsmith.server.acl.AppsmithRole; +import com.appsmith.server.acl.PolicyGenerator; import com.appsmith.server.constants.FieldName; +import com.appsmith.server.domains.Application; +import com.appsmith.server.domains.CommentThread; import com.appsmith.server.domains.Organization; import com.appsmith.server.domains.User; import com.appsmith.server.domains.UserRole; import com.appsmith.server.exceptions.AppsmithError; +import com.appsmith.server.helpers.PolicyUtils; +import com.appsmith.server.repositories.ApplicationRepository; +import com.appsmith.server.repositories.CommentThreadRepository; import com.appsmith.server.repositories.OrganizationRepository; import com.appsmith.server.repositories.UserRepository; import lombok.extern.slf4j.Slf4j; @@ -22,13 +30,15 @@ import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Set; +import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_ADMIN; +import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_DEVELOPER; +import static com.appsmith.server.acl.AppsmithRole.ORGANIZATION_VIEWER; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @Slf4j @@ -46,6 +56,21 @@ class UserOrganizationServiceTest { @Autowired private UserRepository userRepository; + @Autowired + private PolicyUtils policyUtils; + + @Autowired + private ApplicationRepository applicationRepository; + + @Autowired + private CommentService commentService; + + @Autowired + private CommentThreadRepository commentThreadRepository; + + @Autowired + private PolicyGenerator policyGenerator; + private Organization organization; private User user; @@ -53,27 +78,39 @@ class UserOrganizationServiceTest { public void setup() { Organization org = new Organization(); org.setName("Test org"); - - UserRole userRole = new UserRole(); - userRole.setUsername("dummy_username"); - userRole.setUserId("dummy_user_id"); - userRole.setName("dummy_username"); - userRole.setRoleName(AppsmithRole.ORGANIZATION_DEVELOPER.getName()); - userRole.setRole(AppsmithRole.ORGANIZATION_DEVELOPER); - - List userRoles = new ArrayList<>(); - userRoles.add(userRole); - org.setUserRoles(userRoles); - + org.setUserRoles(new ArrayList<>()); this.organization = organizationRepository.save(org).block(); } + private UserRole createUserRole(String username, String userId, AppsmithRole role) { + UserRole userRole = new UserRole(); + userRole.setUsername(username); + userRole.setUserId(userId); + userRole.setName(username); + if(role != null) { + userRole.setRoleName(role.getName()); + userRole.setRole(role); + } + return userRole; + } + + private void addRolesToOrg(List roles) { + this.organization.setUserRoles(roles); + for (UserRole userRole : roles) { + Set rolePermissions = userRole.getRole().getPermissions(); + Map orgPolicyMap = policyUtils.generatePolicyFromPermission( + rolePermissions, userRole.getUsername() + ); + this.organization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization); + } + this.organization = organizationRepository.save(organization).block(); + } + @AfterEach public void clear() { User currentUser = userRepository.findByEmail("api_user").block(); currentUser.getOrganizationIds().remove(organization.getId()); userRepository.save(currentUser); - organizationRepository.deleteById(organization.getId()).block(); } @@ -88,11 +125,7 @@ class UserOrganizationServiceTest { currentUser.getOrganizationIds().add(organization.getId()); userRepository.save(currentUser).block(); - UserRole userRole = new UserRole(); - userRole.setUsername(currentUser.getUsername()); - userRole.setUserId(currentUser.getId()); - userRole.setName(currentUser.getName()); - userRole.setRoleName(AppsmithRole.ORGANIZATION_DEVELOPER.getName()); + UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_DEVELOPER); Organization updatedOrganization = userOrganizationService.addUserToOrganizationGivenUserObject( this.organization, currentUser, userRole @@ -130,10 +163,7 @@ class UserOrganizationServiceTest { public void updateRoleForMember_WhenAdminRoleRemovedWithNoOtherAdmin_ThrowsExceptions() { // add the current user as an admin to the organization first User currentUser = userRepository.findByEmail("api_user").block(); - UserRole userRole = new UserRole(); - userRole.setUsername(currentUser.getUsername()); - userRole.setRole(AppsmithRole.ORGANIZATION_DEVELOPER); - userRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName()); + UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN); userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block(); @@ -151,23 +181,13 @@ class UserOrganizationServiceTest { @WithUserDetails(value = "api_user") public void updateRoleForMember_WhenAdminRoleRemovedButOtherAdminExists_MemberRemoved() { // add another admin role to the organization - UserRole adminRole = new UserRole(); - adminRole.setUsername("dummy_username2"); - adminRole.setUserId("dummy_user_id2"); - adminRole.setName("dummy_username2"); - adminRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName()); - adminRole.setRole(AppsmithRole.ORGANIZATION_ADMIN); + UserRole adminRole = createUserRole("dummy_username2", "dummy_user_id2", ORGANIZATION_ADMIN); this.organization.getUserRoles().add(adminRole); - this.organization = organizationRepository.save(this.organization).block(); // add the current user as an admin to the organization User currentUser = userRepository.findByEmail("api_user").block(); - UserRole userRole = new UserRole(); - userRole.setUsername(currentUser.getUsername()); - userRole.setRole(AppsmithRole.ORGANIZATION_ADMIN); - userRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName()); - + UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN); userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block(); // try to remove the user from org @@ -181,4 +201,137 @@ class UserOrganizationServiceTest { } ).verifyComplete(); } + + private Application createTestApplicationForCommentThreadTests() { + // add a two roles to the organization + User devUser = new User(); + devUser.setEmail("test_developer"); + userRepository.findByEmail("test_developer") + .switchIfEmpty(userRepository.save(devUser)) + .block(); + + UserRole adminRole = createUserRole("api_user", "api_user", ORGANIZATION_ADMIN); + UserRole devRole = createUserRole("test_developer", "test_developer", ORGANIZATION_DEVELOPER); + + List userRoles = new ArrayList<>(2); + userRoles.add(adminRole); + userRoles.add(devRole); + + addRolesToOrg(userRoles); + + // create a test application + Application application = new Application(); + application.setOrganizationId(this.organization.getId()); + application.setName("Test application"); + Set documentPolicies = policyGenerator.getAllChildPolicies( + organization.getPolicies(), Organization.class, Application.class + ); + application.setPolicies(documentPolicies); + return application; + } + + @Test + @WithUserDetails("api_user") + public void updateRoleForMember_WhenCommentThreadExists_ThreadPoliciesUnchanged() { + // create a test application + Mono commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests()) + .flatMap(savedApplication -> { + CommentThread commentThread = new CommentThread(); + commentThread.setApplicationId(savedApplication.getId()); + commentThread.setPolicies(policyGenerator.getAllChildPolicies( + savedApplication.getPolicies(), Application.class, CommentThread.class + )); + return commentThreadRepository.save(commentThread); + }).flatMap(commentThread -> { + // update an user's role + UserRole updatedRole = createUserRole("test_developer", "test_developer", ORGANIZATION_VIEWER); + return userOrganizationService.updateRoleForMember( + organization.getId(), updatedRole, null + ).thenReturn(commentThread); + }).flatMap(commentThread -> + commentThreadRepository.findById(commentThread.getId()) + ); + + StepVerifier.create(commentThreadMono).assertNext(commentThread -> { + Set policies = commentThread.getPolicies(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "test_developer" + )).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "api_user" + )).isTrue(); + }).verifyComplete(); + } + + @Test + @WithUserDetails("api_user") + public void updateRoleForMember_WhenCommentThreadExistsAndUserRemoved_UserRemovedFromThreadPolicies() { + Mono commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests()) + .flatMap(savedApplication -> { + CommentThread commentThread = new CommentThread(); + commentThread.setApplicationId(savedApplication.getId()); + commentThread.setPolicies(policyGenerator.getAllChildPolicies( + savedApplication.getPolicies(), Application.class, CommentThread.class + )); + return commentThreadRepository.save(commentThread); + }).flatMap(commentThread -> { + // remove the test_developer user from the organization + UserRole updatedRole = createUserRole("test_developer", "test_developer", null); + return userOrganizationService.updateRoleForMember(organization.getId(), updatedRole, null) + .thenReturn(commentThread); + }).flatMap(commentThread -> + commentThreadRepository.findById(commentThread.getId()) + ); + + StepVerifier.create(commentThreadMono).assertNext(commentThread -> { + Set policies = commentThread.getPolicies(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "test_developer" + )).isFalse(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "api_user" + )).isTrue(); + }).verifyComplete(); + } + + @Test + @WithUserDetails("api_user") + public void bulkAddUsersToOrganization_WhenNewUserAdded_ThreadPolicyUpdated() { + // create a new user + User user = new User(); + user.setEmail("new_test_user"); + Mono saveUserMono = userRepository.save(user); + + Mono commentThreadMono = applicationRepository.save(createTestApplicationForCommentThreadTests()) + .flatMap(savedApplication -> { + CommentThread commentThread = new CommentThread(); + commentThread.setApplicationId(savedApplication.getId()); + commentThread.setPolicies(policyGenerator.getAllChildPolicies( + savedApplication.getPolicies(), Application.class, CommentThread.class + )); + return commentThreadRepository.save(commentThread); + }).flatMap(commentThread -> { + // add the new user to the organization + List users = new ArrayList<>(1); + users.add(user); + return userOrganizationService + .bulkAddUsersToOrganization(organization, users, ORGANIZATION_DEVELOPER.getName()) + .thenReturn(commentThread); + }).flatMap(commentThread -> + commentThreadRepository.findById(commentThread.getId()) + ); + + StepVerifier.create(saveUserMono.then(commentThreadMono)).assertNext(commentThread -> { + Set policies = commentThread.getPolicies(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "test_developer" + )).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "new_test_user" + )).isTrue(); + assertThat(policyUtils.isPermissionPresentForUser( + policies, AclPermission.READ_THREAD.getValue(), "api_user" + )).isTrue(); + }).verifyComplete(); + } } \ No newline at end of file