Fixed comment missing issue when user role is changed (#5898)

* -fixed comment missing issue when user role is changed

* WIP: add test for policy utils

* -added test for policy utils comment permission when users are added or removed

* -removed unused code

* -removed public access modifier for an internal function

* -add test to verify comment thread policy updated when user role changed in organization

* -add tests for add user and remove user from organization to test comment thread policies
This commit is contained in:
Nayan 2021-07-21 12:30:34 +06:00 committed by GitHub
parent dea9f26116
commit 5261f782df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 356 additions and 59 deletions

View File

@ -50,7 +50,13 @@ public class PolicyUtils {
// TODO: Investigate a solution without using deep-copy. // TODO: Investigate a solution without using deep-copy.
final Map<String, Policy> policyMap1 = new HashMap<>(); final Map<String, Policy> policyMap1 = new HashMap<>();
for (Map.Entry<String, Policy> entry : policyMap.entrySet()) { for (Map.Entry<String, Policy> 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. // Append the user to the existing permission policy if it already exists.
@ -221,7 +227,7 @@ public class PolicyUtils {
.saveAll(updatedPages)); .saveAll(updatedPages));
} }
public Flux<CommentThread> updateWithApplicationPermissionsToAllItsCommentThreads( public Flux<CommentThread> updateCommentThreadPermissions(
String applicationId, Map<String, Policy> commentThreadPolicyMap, String username, boolean addPolicyToObject) { String applicationId, Map<String, Policy> commentThreadPolicyMap, String username, boolean addPolicyToObject) {
return return

View File

@ -10,16 +10,12 @@ import java.util.List;
public interface UserOrganizationService { public interface UserOrganizationService {
Mono<User> addUserToOrganization(String orgId, User user); Mono<User> addUserToOrganization(String orgId, User user);
Mono<User> saveUser(User user);
Mono<Organization> addUserRoleToOrganization(String orgId, UserRole userRole); Mono<Organization> addUserRoleToOrganization(String orgId, UserRole userRole);
Mono<Organization> addUserToOrganizationGivenUserObject(Organization organization, User user, UserRole userRole); Mono<Organization> addUserToOrganizationGivenUserObject(Organization organization, User user, UserRole userRole);
Mono<User> leaveOrganization(String orgId); Mono<User> leaveOrganization(String orgId);
Mono<Organization> removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user);
Mono<UserRole> updateRoleForMember(String orgId, UserRole userRole, String originHeader); Mono<UserRole> updateRoleForMember(String orgId, UserRole userRole, String originHeader);
Mono<Organization> bulkAddUsersToOrganization(Organization organization, List<User> users, String roleName); Mono<Organization> bulkAddUsersToOrganization(Organization organization, List<User> users, String roleName);

View File

@ -120,11 +120,6 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
.flatMap(userRepository::save); .flatMap(userRepository::save);
} }
@Override
public Mono<User> saveUser(User user) {
return userRepository.save(user);
}
@Override @Override
public Mono<Organization> addUserRoleToOrganization(String orgId, UserRole userRole) { public Mono<Organization> addUserRoleToOrganization(String orgId, UserRole userRole) {
Mono<Organization> organizationMono = organizationRepository.findById(orgId, MANAGE_ORGANIZATIONS) Mono<Organization> organizationMono = organizationRepository.findById(orgId, MANAGE_ORGANIZATIONS)
@ -169,7 +164,9 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
Map<String, Policy> datasourcePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(orgPolicyMap, Organization.class, Datasource.class); Map<String, Policy> datasourcePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(orgPolicyMap, Organization.class, Datasource.class);
Map<String, Policy> pagePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(applicationPolicyMap, Application.class, Page.class); Map<String, Policy> pagePolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(applicationPolicyMap, Application.class, Page.class);
Map<String, Policy> actionPolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(pagePolicyMap, Page.class, Action.class); Map<String, Policy> actionPolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(pagePolicyMap, Page.class, Action.class);
Map<String, Policy> commentThreadPolicyMap = policyUtils.generateInheritedPoliciesFromSourcePolicies(
applicationPolicyMap, Application.class, CommentThread.class
);
//Now update the organization policies //Now update the organization policies
Organization updatedOrganization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization); Organization updatedOrganization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization);
updatedOrganization.setUserRoles(userRoles); updatedOrganization.setUserRoles(userRoles);
@ -182,13 +179,21 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsPages(application.getId(), pagePolicyMap, true)); .flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsPages(application.getId(), pagePolicyMap, true));
Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true)); .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true));
Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateCommentThreadPermissions(application.getId(), commentThreadPolicyMap, user.getUsername(), true));
return Mono.zip(updatedDatasourcesFlux.collectList(), updatedPagesFlux.collectList(), updatedActionsFlux.collectList(), Mono.just(updatedOrganization)) return Mono.zip(
.flatMap(tuple -> { updatedDatasourcesFlux.collectList(),
//By now all the datasources/applications/pages/actions have been updated. Just save the organization now updatedPagesFlux.collectList(),
Organization updatedOrgBeforeSave = tuple.getT4(); updatedActionsFlux.collectList(),
return organizationRepository.save(updatedOrgBeforeSave); 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 @Override
@ -212,8 +217,7 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
}); });
} }
@Override private Mono<Organization> removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user) {
public Mono<Organization> removeUserRoleFromOrganizationGivenUserObject(Organization organization, User user) {
List<UserRole> userRoles = organization.getUserRoles(); List<UserRole> userRoles = organization.getUserRoles();
if (userRoles == null) { if (userRoles == null) {
return Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER + " in organization", organization.getName())); 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<NewAction> updatedActionsFlux = updatedApplicationsFlux Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, false)); .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, false));
Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads( .flatMap(application -> policyUtils.updateCommentThreadPermissions(
application.getId(), commentThreadPolicyMap, user.getUsername(), false application.getId(), commentThreadPolicyMap, user.getUsername(), false
)); ));
@ -434,7 +438,7 @@ public class UserOrganizationServiceImpl implements UserOrganizationService {
Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux Flux<NewAction> updatedActionsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true)); .flatMap(application -> policyUtils.updateWithPagePermissionsToAllItsActions(application.getId(), actionPolicyMap, true));
Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux Flux<CommentThread> updatedThreadsFlux = updatedApplicationsFlux
.flatMap(application -> policyUtils.updateWithApplicationPermissionsToAllItsCommentThreads( .flatMap(application -> policyUtils.updateCommentThreadPermissions(
application.getId(), commentThreadPolicyMap, null, true application.getId(), commentThreadPolicyMap, null, true
)); ));

View File

@ -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<String, Policy> commentThreadPolicies = policyUtils.generatePolicyFromPermission(
Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), "api_user"
);
commentThread.setPolicies(Set.copyOf(commentThreadPolicies.values()));
Mono<CommentThread> saveThreadMono = commentThreadRepository.save(commentThread);
// add a new user and update the policies of the new user
String newUserName = "new_test_user";
Map<String, Policy> commentThreadPoliciesForNewUser = policyUtils.generatePolicyFromPermission(
Set.of(AclPermission.COMMENT_ON_THREAD), newUserName
);
Flux<CommentThread> updateCommentThreads = policyUtils.updateCommentThreadPermissions(
testApplicationId, commentThreadPoliciesForNewUser, newUserName, true
);
// check if new policies updated
Mono<List<CommentThread>> 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<Policy> 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<String, Policy> commentThreadPolicies = policyUtils.generatePolicyFromPermissionForMultipleUsers(
Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), List.of(user1, user2)
);
commentThread.setPolicies(Set.copyOf(commentThreadPolicies.values()));
Mono<CommentThread> saveThreadMono = commentThreadRepository.save(commentThread);
// remove an user and update the policies of the user
Map<String, Policy> commentThreadPoliciesForNewUser = policyUtils.generatePolicyFromPermission(
Set.of(AclPermission.MANAGE_THREAD, AclPermission.COMMENT_ON_THREAD), newUserName
);
Flux<CommentThread> updateCommentThreads = policyUtils.updateCommentThreadPermissions(
testApplicationId, commentThreadPoliciesForNewUser, newUserName, false
);
// check if new policies updated
Mono<List<CommentThread>> 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<Policy> 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();
}
}

View File

@ -1,11 +1,19 @@
package com.appsmith.server.services; 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.AppsmithRole;
import com.appsmith.server.acl.PolicyGenerator;
import com.appsmith.server.constants.FieldName; 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.Organization;
import com.appsmith.server.domains.User; import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserRole; import com.appsmith.server.domains.UserRole;
import com.appsmith.server.exceptions.AppsmithError; 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.OrganizationRepository;
import com.appsmith.server.repositories.UserRepository; import com.appsmith.server.repositories.UserRepository;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -22,13 +30,15 @@ import reactor.core.publisher.Mono;
import reactor.test.StepVerifier; import reactor.test.StepVerifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; 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.assertFalse;
import static org.junit.Assert.assertTrue; import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@Slf4j @Slf4j
@ -46,6 +56,21 @@ class UserOrganizationServiceTest {
@Autowired @Autowired
private UserRepository userRepository; 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 Organization organization;
private User user; private User user;
@ -53,27 +78,39 @@ class UserOrganizationServiceTest {
public void setup() { public void setup() {
Organization org = new Organization(); Organization org = new Organization();
org.setName("Test org"); org.setName("Test org");
org.setUserRoles(new ArrayList<>());
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<UserRole> userRoles = new ArrayList<>();
userRoles.add(userRole);
org.setUserRoles(userRoles);
this.organization = organizationRepository.save(org).block(); 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<UserRole> roles) {
this.organization.setUserRoles(roles);
for (UserRole userRole : roles) {
Set<AclPermission> rolePermissions = userRole.getRole().getPermissions();
Map<String, Policy> orgPolicyMap = policyUtils.generatePolicyFromPermission(
rolePermissions, userRole.getUsername()
);
this.organization = policyUtils.addPoliciesToExistingObject(orgPolicyMap, organization);
}
this.organization = organizationRepository.save(organization).block();
}
@AfterEach @AfterEach
public void clear() { public void clear() {
User currentUser = userRepository.findByEmail("api_user").block(); User currentUser = userRepository.findByEmail("api_user").block();
currentUser.getOrganizationIds().remove(organization.getId()); currentUser.getOrganizationIds().remove(organization.getId());
userRepository.save(currentUser); userRepository.save(currentUser);
organizationRepository.deleteById(organization.getId()).block(); organizationRepository.deleteById(organization.getId()).block();
} }
@ -88,11 +125,7 @@ class UserOrganizationServiceTest {
currentUser.getOrganizationIds().add(organization.getId()); currentUser.getOrganizationIds().add(organization.getId());
userRepository.save(currentUser).block(); userRepository.save(currentUser).block();
UserRole userRole = new UserRole(); UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_DEVELOPER);
userRole.setUsername(currentUser.getUsername());
userRole.setUserId(currentUser.getId());
userRole.setName(currentUser.getName());
userRole.setRoleName(AppsmithRole.ORGANIZATION_DEVELOPER.getName());
Organization updatedOrganization = userOrganizationService.addUserToOrganizationGivenUserObject( Organization updatedOrganization = userOrganizationService.addUserToOrganizationGivenUserObject(
this.organization, currentUser, userRole this.organization, currentUser, userRole
@ -130,10 +163,7 @@ class UserOrganizationServiceTest {
public void updateRoleForMember_WhenAdminRoleRemovedWithNoOtherAdmin_ThrowsExceptions() { public void updateRoleForMember_WhenAdminRoleRemovedWithNoOtherAdmin_ThrowsExceptions() {
// add the current user as an admin to the organization first // add the current user as an admin to the organization first
User currentUser = userRepository.findByEmail("api_user").block(); User currentUser = userRepository.findByEmail("api_user").block();
UserRole userRole = new UserRole(); UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN);
userRole.setUsername(currentUser.getUsername());
userRole.setRole(AppsmithRole.ORGANIZATION_DEVELOPER);
userRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName());
userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block(); userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block();
@ -151,23 +181,13 @@ class UserOrganizationServiceTest {
@WithUserDetails(value = "api_user") @WithUserDetails(value = "api_user")
public void updateRoleForMember_WhenAdminRoleRemovedButOtherAdminExists_MemberRemoved() { public void updateRoleForMember_WhenAdminRoleRemovedButOtherAdminExists_MemberRemoved() {
// add another admin role to the organization // add another admin role to the organization
UserRole adminRole = new UserRole(); UserRole adminRole = createUserRole("dummy_username2", "dummy_user_id2", ORGANIZATION_ADMIN);
adminRole.setUsername("dummy_username2");
adminRole.setUserId("dummy_user_id2");
adminRole.setName("dummy_username2");
adminRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName());
adminRole.setRole(AppsmithRole.ORGANIZATION_ADMIN);
this.organization.getUserRoles().add(adminRole); this.organization.getUserRoles().add(adminRole);
this.organization = organizationRepository.save(this.organization).block(); this.organization = organizationRepository.save(this.organization).block();
// add the current user as an admin to the organization // add the current user as an admin to the organization
User currentUser = userRepository.findByEmail("api_user").block(); User currentUser = userRepository.findByEmail("api_user").block();
UserRole userRole = new UserRole(); UserRole userRole = createUserRole(currentUser.getUsername(), currentUser.getId(), ORGANIZATION_ADMIN);
userRole.setUsername(currentUser.getUsername());
userRole.setRole(AppsmithRole.ORGANIZATION_ADMIN);
userRole.setRoleName(AppsmithRole.ORGANIZATION_ADMIN.getName());
userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block(); userOrganizationService.addUserToOrganizationGivenUserObject(organization, currentUser, userRole).block();
// try to remove the user from org // try to remove the user from org
@ -181,4 +201,137 @@ class UserOrganizationServiceTest {
} }
).verifyComplete(); ).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<UserRole> 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<Policy> 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<CommentThread> 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<Policy> 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<CommentThread> 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<Policy> 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<User> saveUserMono = userRepository.save(user);
Mono<CommentThread> 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<User> 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<Policy> 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();
}
} }