Merge branch 'feature/acl-org-user-role' into 'feature/acl-spring-object'

GET Organization Users & part base code to update permissions given an org level role.

See merge request theappsmith/internal-tools-server!339
This commit is contained in:
Trisha Anand 2020-05-21 15:05:43 +00:00
commit 10b07d5912
11 changed files with 308 additions and 53 deletions

View File

@ -6,19 +6,26 @@ import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_READ_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_ORGANIZATIONS;
@Getter
public enum AppsmithRole {
APPLICATION_ADMIN(Set.of(MANAGE_APPLICATIONS)),
APPLICATION_VIEWER(Set.of(READ_APPLICATIONS)),
ORGANIZATION_ADMIN(Set.of(MANAGE_ORGANIZATIONS)),
ORGANIZATION_VIEWER(Set.of(READ_ORGANIZATIONS));
APPLICATION_ADMIN("Application Administrator", "", Set.of(MANAGE_APPLICATIONS)),
APPLICATION_VIEWER("Application Viewer", "", Set.of(READ_APPLICATIONS)),
ORGANIZATION_ADMIN("Administrator", "", Set.of(MANAGE_ORGANIZATIONS)),
ORGANIZATION_DEVELOPER("Developer", "", Set.of(READ_ORGANIZATIONS, ORGANIZATION_MANAGE_APPLICATIONS)),
ORGANIZATION_VIEWER("App Viewer", "", Set.of(ORGANIZATION_READ_APPLICATIONS));
private Set<AclPermission> permissions;
private String name;
private String description;
AppsmithRole(Set<AclPermission> permissions) {
AppsmithRole(String name, String description, Set<AclPermission> permissions) {
this.name = name;
this.description = description;
this.permissions = permissions;
}
}

View File

@ -2,10 +2,19 @@ package com.appsmith.server.controllers;
import com.appsmith.server.constants.Url;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.UserRole;
import com.appsmith.server.dtos.ResponseDTO;
import com.appsmith.server.services.OrganizationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping(Url.ORGANIZATION_URL)
@ -17,4 +26,19 @@ public class OrganizationController extends BaseController<OrganizationService,
super(organizationService);
}
/**
* This function would be used to fetch all possible user roles at organization level.
* @return
*/
@GetMapping("/roles")
public Mono<ResponseDTO<Map<String, String>>> getUserRolesForOrganization() {
return service.getUserRolesForOrganization()
.map(permissions -> new ResponseDTO<>(HttpStatus.OK.value(), permissions, null));
}
@GetMapping("/{orgId}/members")
public Mono<ResponseDTO<List<UserRole>>> getUserMembersOfOrganization(@PathVariable String orgId) {
return service.getOrganizationMembers(orgId)
.map(users -> new ResponseDTO<>(HttpStatus.OK.value(), users, null));
}
}

View File

@ -1,6 +1,7 @@
package com.appsmith.server.domains;
import com.appsmith.external.models.BaseDomain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@ -31,6 +32,9 @@ public class Organization extends BaseDomain {
private String slug;
@JsonIgnore
private List<UserRole> userRoles;
public String makeSlug() {
return toSlug(name);
}
@ -38,5 +42,4 @@ public class Organization extends BaseDomain {
public static String toSlug(String text) {
return text == null ? null : text.replaceAll("[^\\w\\d]+", "-").toLowerCase();
}
}

View File

@ -0,0 +1,26 @@
package com.appsmith.server.domains;
import com.appsmith.server.acl.AppsmithRole;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@NoArgsConstructor
@ToString
public class UserRole {
@JsonIgnore
String userId;
String username;
String name;
String roleName;
@JsonIgnore
AppsmithRole role;
}

View File

@ -2,15 +2,27 @@ package com.appsmith.server.helpers;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.models.Policy;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.acl.PolicyGenerator;
import com.appsmith.server.domains.User;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class PolicyUtils<T extends BaseDomain> {
private final PolicyGenerator policyGenerator;
public PolicyUtils(PolicyGenerator policyGenerator) {
this.policyGenerator = policyGenerator;
}
public T setUserPermissionsInObject(T obj, User user) {
Set<String> permissions = new HashSet<>();
@ -38,4 +50,70 @@ public class PolicyUtils<T extends BaseDomain> {
return obj;
}
public T generateAndAddPoliciesFromPermissions(Set<AclPermission> permissions, T obj, User user) {
Map<String, Policy> policyMap = generatePolicyFromPermission(permissions, user);
// Append the user to the existing permission policy if it already exists.
for (Policy policy : obj.getPolicies()) {
String permission = policy.getPermission();
if (policyMap.containsKey(permission)) {
policy.getUsers().addAll(policyMap.get(permission).getUsers());
if (policy.getGroups() == null) {
policy.setGroups(new HashSet<>());
}
if (policyMap.get(permission).getGroups() != null) {
policy.getGroups().addAll(policyMap.get(permission).getGroups());
}
// Remove this permission from the policyMap as this has been accounted for in the above code
policyMap.remove(permission);
}
}
obj.getPolicies().addAll(policyMap.values());
return obj;
}
public T generateAndRemovePolicies(Set<AclPermission> permissions, T obj, User user) {
Map<String, Policy> policyMap = generatePolicyFromPermission(permissions, user);
// Remove the user from the existing permission policy if it exists.
for (Policy policy : obj.getPolicies()) {
String permission = policy.getPermission();
if (policyMap.containsKey(permission)) {
policy.getUsers().removeAll(policyMap.get(permission).getUsers());
if (policy.getGroups() == null) {
policy.setGroups(new HashSet<>());
}
if (policyMap.get(permission).getGroups() != null) {
policy.getGroups().removeAll(policyMap.get(permission).getGroups());
}
// Remove this permission from the policyMap as this has been accounted for in the above code
policyMap.remove(permission);
}
}
return obj;
}
/**
* Given a set of AclPermissions, generate all policies (including policies from lateral permissions) for the user.
* @param permissions
* @param user
* @return
*/
private Map<String, Policy> generatePolicyFromPermission(Set<AclPermission> permissions, User user) {
return permissions.stream()
.map(perm -> {
// Create a policy for the invited user using the permission as per the role
Policy policyWithCurrentPermission = Policy.builder().permission(perm.getValue())
.users(Set.of(user.getUsername())).build();
// Generate any and all lateral policies that might come with the current permission
Set<Policy> policiesForUser = policyGenerator.getLateralPoliciesForUser(perm, user);
policiesForUser.add(policyWithCurrentPermission);
return policiesForUser;
})
.flatMap(Collection::stream)
.collect(Collectors.toMap(Policy::getPermission, Function.identity()));
}
}

View File

@ -1,11 +1,15 @@
package com.appsmith.server.services;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.acl.AppsmithRole;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserRole;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
import java.util.Set;
public interface OrganizationService extends CrudService<Organization, String> {
@ -27,4 +31,12 @@ public interface OrganizationService extends CrudService<Organization, String> {
Mono<Organization> findByIdAndPluginsPluginId(String organizationId, String pluginId);
Flux<Organization> findByIdsIn(Set<String> ids,AclPermission permission);
Mono<Map<String, String>> getUserRolesForOrganization();
Mono<Organization> addUserRoleToOrganization(Organization organization, User user, AppsmithRole role);
Mono<Organization> removeUserRoleFromOrganization(Organization organization, User user);
Mono<List<UserRole>> getOrganizationMembers(String orgId);
}

View File

@ -2,6 +2,7 @@ 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.AnalyticsEvents;
import com.appsmith.server.constants.FieldName;
@ -10,9 +11,11 @@ import com.appsmith.server.domains.OrganizationPlugin;
import com.appsmith.server.domains.OrganizationSetting;
import com.appsmith.server.domains.Setting;
import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserRole;
import com.appsmith.server.dtos.OrganizationPluginStatus;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.PolicyUtils;
import com.appsmith.server.repositories.OrganizationRepository;
import com.appsmith.server.repositories.PluginRepository;
import lombok.extern.slf4j.Slf4j;
@ -27,12 +30,15 @@ import reactor.core.scheduler.Scheduler;
import javax.validation.Validator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
import static com.appsmith.server.acl.AclPermission.USER_MANAGE_ORGANIZATIONS;
import static java.util.stream.Collectors.toMap;
@Slf4j
@Service
@ -45,6 +51,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
private final SessionUserService sessionUserService;
private final UserOrganizationService userOrganizationService;
private final PolicyGenerator policyGenerator;
private final PolicyUtils policyUtils;
@Autowired
public OrganizationServiceImpl(Scheduler scheduler,
@ -58,7 +65,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
PluginRepository pluginRepository,
SessionUserService sessionUserService,
UserOrganizationService userOrganizationService,
PolicyGenerator policyGenerator) {
PolicyGenerator policyGenerator, PolicyUtils policyUtils) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
this.repository = repository;
this.settingService = settingService;
@ -67,6 +74,7 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
this.sessionUserService = sessionUserService;
this.userOrganizationService = userOrganizationService;
this.policyGenerator = policyGenerator;
this.policyUtils = policyUtils;
}
@Override
@ -129,9 +137,6 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
return Mono.error(new AppsmithException(AppsmithError.UNAUTHORIZED_ACCESS));
}
// Set the admin policies for this organization & user
organization.setPolicies(crudOrgPolicy(user));
Mono<Organization> setSlugMono;
if (organization.getName() == null) {
setSlugMono = Mono.just(organization);
@ -161,6 +166,9 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
}))
//Call the BaseService function to save the updated organization
.flatMap(super::create)
// Set the current user as admin for the organization
.flatMap(createdOrg -> addUserRoleToOrganization(createdOrg, user, AppsmithRole.ORGANIZATION_ADMIN))
// TODO : Remove the following code
.flatMap(savedOrganization -> userOrganizationService
.addUserToOrganization(savedOrganization.getId(), user)
.thenReturn(savedOrganization));
@ -251,5 +259,87 @@ public class OrganizationServiceImpl extends BaseService<OrganizationRepository,
return repository.findByIdsIn(ids, permission);
}
@Override
public Mono<Map<String, String>> getUserRolesForOrganization() {
// Get all the roles for Organization entity from the enum AppsmithRole
Map<String, String> appsmithRoles = Arrays.asList(AppsmithRole.values())
.stream()
.filter(role -> {
Set<AclPermission> permissions = role.getPermissions();
if (permissions != null && !permissions.isEmpty()) {
for (AclPermission permission : permissions) {
if (permission.getEntity().equals(Organization.class)) {
return true;
}
}
}
return false;
})
.collect(toMap(role -> role.getName(), AppsmithRole::getDescription));
return Mono.just(appsmithRoles);
}
@Override
public Mono<Organization> addUserRoleToOrganization(Organization organization, User user, AppsmithRole role) {
List<UserRole> userRoles = organization.getUserRoles();
if (userRoles == null) {
userRoles = new ArrayList<>();
}
UserRole userRole = new UserRole();
userRole.setUserId(user.getId());
userRole.setUsername(user.getUsername());
userRole.setName(user.getName());
userRole.setRole(role);
userRole.setRoleName(role.getName());
// Add the user and its role to the organization
userRoles.add(userRole);
Set<AclPermission> rolePermissions = role.getPermissions();
Organization updatedOrganization = (Organization) policyUtils.generateAndAddPoliciesFromPermissions(rolePermissions, organization, user);
updatedOrganization.setUserRoles(userRoles);
/**
* TODO : Update the underlying application/page/action
*/
return repository.save(updatedOrganization);
}
@Override
public Mono<Organization> removeUserRoleFromOrganization(Organization organization, User user) {
List<UserRole> userRoles = organization.getUserRoles();
if (userRoles == null) {
// The user doesnt exist in this organization. Nothing to do here. Return as is.
return Mono.just(organization);
}
for (UserRole role : userRoles) {
if (role.getUsername().equals(user.getUsername())) {
// Update the organization permissions
Set<AclPermission> rolePermissions = role.getRole().getPermissions();
Organization updatedPermissionsOrg = (Organization) policyUtils.generateAndRemovePolicies(rolePermissions, organization, user);
List<UserRole> finalUserRoles = updatedPermissionsOrg.getUserRoles();
// The user exists. Remove the user from the organization :
finalUserRoles.remove(role);
updatedPermissionsOrg.setUserRoles(finalUserRoles);
/**
* TODO : Update the underlying application/page/action
*/
return repository.save(updatedPermissionsOrg);
}
}
// The user was not found in the list of user roles in the organization. Throw the appropriate error.
return Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER, user.getId()));
}
@Override
public Mono<List<UserRole>> getOrganizationMembers(String orgId) {
return repository
.findById(orgId, MANAGE_ORGANIZATIONS)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ORGANIZATION, orgId)))
.map(organization -> organization.getUserRoles());
}
}

View File

@ -16,6 +16,7 @@ import com.appsmith.server.dtos.UserProfileDTO;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import com.appsmith.server.helpers.BeanCopyUtils;
import com.appsmith.server.helpers.PolicyUtils;
import com.appsmith.server.notifications.EmailSender;
import com.appsmith.server.repositories.ApplicationRepository;
import com.appsmith.server.repositories.InviteUserRepository;
@ -39,19 +40,15 @@ import javax.validation.Validator;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_USERS;
import static com.appsmith.server.acl.AclPermission.READ_USERS;
import static com.appsmith.server.acl.AclPermission.RESET_PASSWORD_USERS;
import static com.appsmith.server.acl.AclPermission.USER_MANAGE_ORGANIZATIONS;
@ -70,6 +67,7 @@ public class UserServiceImpl extends BaseService<UserRepository, User, String> i
private final UserOrganizationService userOrganizationService;
private final ApplicationRepository applicationRepository;
private final PolicyGenerator policyGenerator;
private final PolicyUtils policyUtils;
private static final String WELCOME_USER_EMAIL_TEMPLATE = "email/welcomeUserTemplate.html";
private static final String INVITE_USER_EMAIL_TEMPLATE = "email/inviteUserCreatorTemplate.html";
@ -94,7 +92,7 @@ public class UserServiceImpl extends BaseService<UserRepository, User, String> i
InviteUserRepository inviteUserRepository,
UserOrganizationService userOrganizationService,
ApplicationRepository applicationRepository,
PolicyGenerator policyGenerator) {
PolicyGenerator policyGenerator, PolicyUtils policyUtils) {
super(scheduler, validator, mongoConverter, reactiveMongoTemplate, repository, analyticsService);
this.repository = repository;
this.organizationService = organizationService;
@ -107,6 +105,7 @@ public class UserServiceImpl extends BaseService<UserRepository, User, String> i
this.userOrganizationService = userOrganizationService;
this.applicationRepository = applicationRepository;
this.policyGenerator = policyGenerator;
this.policyUtils = policyUtils;
}
@Override
@ -324,42 +323,8 @@ public class UserServiceImpl extends BaseService<UserRepository, User, String> i
}
Set<AclPermission> invitePermissions = inviteUser.getRole().getPermissions();
// Append the permissions to the application
Map<String, Policy> policyMap = invitePermissions.stream()
.map(perm -> {
// Create a policy for the invited user using the permission as per the role
Policy policyWithCurrentPermission = Policy.builder().permission(perm.getValue())
.users(Set.of(inviteUser.getUsername())).build();
// Generate any and all lateral policies that might come with the current permission
Set<Policy> policiesForUser = policyGenerator.getLateralPoliciesForUser(perm, inviteUser);
policiesForUser.add(policyWithCurrentPermission);
return policiesForUser;
})
.flatMap(Collection::stream)
.collect(Collectors.toMap(Policy::getPermission, Function.identity()));
// Append the user to the existing permission policy if it already exists.
for (Policy policy : application.getPolicies()) {
String permission = policy.getPermission();
if (policyMap.containsKey(permission)) {
policy.getUsers().addAll(policyMap.get(permission).getUsers());
if (policy.getGroups() == null) {
policy.setGroups(new HashSet<>());
}
if (policyMap.get(permission).getGroups() != null) {
policy.getGroups().addAll(policyMap.get(permission).getGroups());
}
// Remove this permission from the policyMap as this has been accounted for in the above code
policyMap.remove(permission);
}
}
// For all the remaining policies which exist in the policyMap but didnt exist in the application
// earlier, just add them to the set
application.getPolicies().addAll(policyMap.values());
return application;
// Append the permissions to the application and return
return (Application) policyUtils.generateAndAddPoliciesFromPermissions(invitePermissions, application, inviteUser);
// Append the required permissions to all the pages
/**
@ -632,7 +597,7 @@ public class UserServiceImpl extends BaseService<UserRepository, User, String> i
@Override
public Mono<User> update(String id, User userUpdate) {
Mono<User> userFromRepository = repository.findById(id, READ_USERS)
Mono<User> userFromRepository = repository.findById(id, MANAGE_USERS)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER, id)));
if (userUpdate.getPassword() != null) {

View File

@ -30,6 +30,7 @@ import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_PAGES;
import static com.appsmith.server.acl.AclPermission.MANAGE_USERS;
import static com.appsmith.server.acl.AclPermission.ORGANIZATION_MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_ORGANIZATIONS;
@ -86,13 +87,17 @@ public class SeedMongoData {
.users(Set.of(API_USER_EMAIL))
.build();
Policy manageApiUserPolicy = Policy.builder().permission(MANAGE_USERS.getValue())
.users(Set.of(API_USER_EMAIL))
.build();
Policy readTestUserPolicy = Policy.builder().permission(READ_USERS.getValue())
.users(Set.of(TEST_USER_EMAIL))
.build();
Object[][] userData = {
{"user test", TEST_USER_EMAIL, UserState.ACTIVATED, Set.of(readTestUserPolicy)},
{"api_user", API_USER_EMAIL, UserState.ACTIVATED, Set.of(userManageOrgPolicy, readApiUserPolicy)},
{"api_user", API_USER_EMAIL, UserState.ACTIVATED, Set.of(userManageOrgPolicy, readApiUserPolicy, manageApiUserPolicy)},
};
Object[][] orgData = {
{"Spring Test Organization", "appsmith-spring-test.com", "appsmith.com", "spring-test-organization",

View File

@ -1,10 +1,13 @@
package com.appsmith.server.services;
import com.appsmith.external.models.Policy;
import com.appsmith.server.acl.AppsmithRole;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Organization;
import com.appsmith.server.domains.UserRole;
import com.appsmith.server.exceptions.AppsmithError;
import com.appsmith.server.exceptions.AppsmithException;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -17,6 +20,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.appsmith.server.acl.AclPermission.MANAGE_ORGANIZATIONS;
@ -26,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@DirtiesContext
@Slf4j
public class OrganizationServiceTest {
@Autowired
@ -202,4 +208,40 @@ public class OrganizationServiceTest {
})
.verifyComplete();
}
@Test
public void getAllUserRolesForOrganizationDomain() {
Mono<Map<String, String>> userRolesForOrganization = organizationService.getUserRolesForOrganization();
StepVerifier.create(userRolesForOrganization)
.assertNext(roles -> {
assertThat(roles).isNotEmpty();
assertThat(roles).containsKeys("Administrator", "App Viewer", "Developer");
})
.verifyComplete();
}
@Test
@WithUserDetails(value = "api_user")
public void getAllMembersForOrganization() {
Organization testOrg = new Organization();
testOrg.setName("Get All Members For Organization Test");
testOrg.setDomain("test.com");
testOrg.setWebsite("https://test.com");
Mono<Organization> createOrganizationMono = organizationService.create(testOrg);
Mono<List<UserRole>> usersMono = createOrganizationMono
.flatMap(organization -> organizationService.getOrganizationMembers(organization.getId()));
StepVerifier
.create(usersMono)
.assertNext(users -> {
assertThat(users).isNotNull();
UserRole userRole = users.get(0);
assertThat(userRole.getName()).isEqualTo("api_user");
assertThat(userRole.getRole()).isEqualByComparingTo(AppsmithRole.ORGANIZATION_ADMIN);
assertThat(userRole.getRoleName()).isEqualTo(AppsmithRole.ORGANIZATION_ADMIN.getName());
})
.verifyComplete();
}
}

View File

@ -74,6 +74,9 @@ public class UserServiceTest {
.verify();
}
/**
* The following function tests for switch organization
*/
@Test
@WithUserDetails(value = "api_user")
public void updateUserWithValidOrganization() {