Merge pull request #433 from rasika/IoTS-1.0.0

Update device grouping UIs to work with new sharing model
4.x.x
Charitha Goonetilleke 8 years ago committed by GitHub
commit 42f7233065

@ -356,6 +356,70 @@ public interface RoleManagementService {
value = "The properties required to add a new role.", value = "The properties required to add a new role.",
required = true) RoleInfo role); required = true) RoleInfo role);
@POST
@Path("/create-combined-role/{roleName}")
@ApiOperation(
consumes = MediaType.APPLICATION_JSON,
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Adding a combined Role",
notes = "WSO2 EMM supports role-based access control (RBAC) and role management. Add a new combined role to WSO2 EMM using this REST API.",
tags = "Role Management",
authorizations = {
@Authorization(
value="permission",
scopes = { @AuthorizationScope(scope = "/device-mgt/roles/manage",
description = "Manage Roles") }
)
}
)
@ApiResponses(value = {
@ApiResponse(
code = 201,
message = "Created. \n Successfully created the role.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The URL to the newly added role."),
@ResponseHeader(
name = "Content-Type",
description = "The content type of the body"),
@ResponseHeader(
name = "ETag",
description = "Entity Tag of the response resource.\n" +
"Used by caches, or in conditional requests."),
@ResponseHeader(
name = "Last-Modified",
description = "Date and time the resource has been modified the last time.\n" +
"Used by caches, or in conditional requests.")}),
@ApiResponse(
code = 303,
message = "See Other. \n The source can be retrieved from the URL specified in the location header.",
responseHeaders = {
@ResponseHeader(
name = "Content-Location",
description = "The Source URL of the document.")}),
@ApiResponse(
code = 400,
message = "Bad Request. \n Invalid request or validation error.",
response = ErrorResponse.class),
@ApiResponse(
code = 415,
message = "Unsupported media type. \n The format of the requested entity was not supported.",
response = ErrorResponse.class),
@ApiResponse(
code = 500,
message = "Internal Server Error. \n Server error occurred while adding a new role.",
response = ErrorResponse.class)
})
Response addCombinedRole(
@ApiParam(
name = "roles",
value = "List of roles names required to add a new combined role.",
required = true) List<String> roles,
@PathParam("roleName") String roleName,
@QueryParam("user-store") String userStoreName);
@PUT @PUT
@Path("/{roleName}") @Path("/{roleName}")
@ApiOperation( @ApiOperation(

@ -30,13 +30,26 @@ import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.FilteringUtil;
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
import org.wso2.carbon.device.mgt.jaxrs.util.SetReferenceTransformer; import org.wso2.carbon.device.mgt.jaxrs.util.SetReferenceTransformer;
import org.wso2.carbon.user.api.*; import org.wso2.carbon.user.api.AuthorizationManager;
import org.wso2.carbon.user.api.Permission;
import org.wso2.carbon.user.api.UserRealm;
import org.wso2.carbon.user.api.UserStoreException;
import org.wso2.carbon.user.api.UserStoreManager;
import org.wso2.carbon.user.core.common.AbstractUserStoreManager; import org.wso2.carbon.user.core.common.AbstractUserStoreManager;
import org.wso2.carbon.user.mgt.UserRealmProxy; import org.wso2.carbon.user.mgt.UserRealmProxy;
import org.wso2.carbon.user.mgt.common.UIPermissionNode; import org.wso2.carbon.user.mgt.common.UIPermissionNode;
import org.wso2.carbon.user.mgt.common.UserAdminException; import org.wso2.carbon.user.mgt.common.UserAdminException;
import javax.ws.rs.*; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -45,7 +58,9 @@ import java.net.URISyntaxException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import static org.wso2.carbon.device.mgt.jaxrs.util.Constants.PRIMARY_USER_STORE; import static org.wso2.carbon.device.mgt.jaxrs.util.Constants.PRIMARY_USER_STORE;
@ -69,7 +84,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
RoleList targetRoles = new RoleList(); RoleList targetRoles = new RoleList();
//if user store is null set it to primary //if user store is null set it to primary
if(userStore == null || "".equals(userStore)){ if (userStore == null || "".equals(userStore)) {
userStore = PRIMARY_USER_STORE; userStore = PRIMARY_USER_STORE;
} }
@ -94,7 +109,8 @@ public class RoleManagementServiceImpl implements RoleManagementService {
@Path("/{roleName}/permissions") @Path("/{roleName}/permissions")
@Override @Override
public Response getPermissionsOfRole(@PathParam("roleName") String roleName, public Response getPermissionsOfRole(@PathParam("roleName") String roleName,
@QueryParam("user-store") String userStoreName, @HeaderParam("If-Modified-Since") String ifModifiedSince) { @QueryParam("user-store") String userStoreName,
@HeaderParam("If-Modified-Since") String ifModifiedSince) {
if (userStoreName != null && !userStoreName.isEmpty()) { if (userStoreName != null && !userStoreName.isEmpty()) {
roleName = userStoreName + "/" + roleName; roleName = userStoreName + "/" + roleName;
} }
@ -166,7 +182,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
@Path("/{roleName}") @Path("/{roleName}")
@Override @Override
public Response getRole(@PathParam("roleName") String roleName, @QueryParam("user-store") String userStoreName, public Response getRole(@PathParam("roleName") String roleName, @QueryParam("user-store") String userStoreName,
@HeaderParam("If-Modified-Since") String ifModifiedSince) { @HeaderParam("If-Modified-Since") String ifModifiedSince) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Getting the list of user roles"); log.debug("Getting the list of user roles");
} }
@ -181,7 +197,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
if (!userStoreManager.isExistingRole(roleName)) { if (!userStoreManager.isExistingRole(roleName)) {
return Response.status(404).entity( return Response.status(404).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" + new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" +
roleName + "'").build()).build(); roleName + "'").build()).build();
} }
roleInfo.setRoleName(roleName); roleInfo.setRoleName(roleName);
roleInfo.setUsers(userStoreManager.getUserListOfRole(roleName)); roleInfo.setUsers(userStoreManager.getUserListOfRole(roleName));
@ -235,7 +251,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
//TODO fix what's returned in the entity //TODO fix what's returned in the entity
return Response.created(new URI(API_BASE_PATH + "/" + URLEncoder.encode(roleInfo.getRoleName(), "UTF-8"))). return Response.created(new URI(API_BASE_PATH + "/" + URLEncoder.encode(roleInfo.getRoleName(), "UTF-8"))).
entity("Role '" + roleInfo.getRoleName() + "' has " + "successfully been" entity("Role '" + roleInfo.getRoleName() + "' has " + "successfully been"
+ " added").build(); + " added").build();
} catch (UserStoreException e) { } catch (UserStoreException e) {
String msg = "Error occurred while adding role '" + roleInfo.getRoleName() + "'"; String msg = "Error occurred while adding role '" + roleInfo.getRoleName() + "'";
log.error(msg, e); log.error(msg, e);
@ -255,11 +271,76 @@ public class RoleManagementServiceImpl implements RoleManagementService {
} }
} }
@POST
@Path("/create-combined-role/{roleName}")
@Override
public Response addCombinedRole(List<String> roles, @PathParam("roleName") String roleName,
@QueryParam("user-store") String userStoreName) {
if (userStoreName != null && !userStoreName.isEmpty()) {
roleName = userStoreName + "/" + roleName;
}
if (roles.size() < 2) {
return Response.status(400).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage("Combining Roles requires at least two roles.")
.build()
).build();
}
for (String role : roles) {
RequestValidationUtil.validateRoleName(role);
}
try {
UserStoreManager userStoreManager = DeviceMgtAPIUtils.getUserStoreManager();
if (log.isDebugEnabled()) {
log.debug("Persisting the role in the underlying user store");
}
HashSet<Permission> permsSet = new HashSet<>();
try {
for (String role : roles) {
mergePermissions(new UIPermissionNode[]{getRolePermissions(role)}, permsSet);
}
} catch (IllegalArgumentException e) {
return Response.status(404).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(e.getMessage()).build()
).build();
}
Permission[] permissions = permsSet.toArray(new Permission[permsSet.size()]);
userStoreManager.addRole(roleName, new String[0], permissions);
//TODO fix what's returned in the entity
return Response.created(new URI(API_BASE_PATH + "/" + URLEncoder.encode(roleName, "UTF-8"))).
entity("Role '" + roleName + "' has " + "successfully been"
+ " added").build();
} catch (UserAdminException e) {
String msg = "Error occurred while retrieving the permissions of role '" + roleName + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (UserStoreException e) {
String msg = "Error occurred while adding role '" + roleName + "'";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (URISyntaxException e) {
String msg = "Error occurred while composing the URI at which the information of the newly created role " +
"can be retrieved";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
} catch (UnsupportedEncodingException e) {
String msg = "Error occurred while encoding role name";
log.error(msg, e);
return Response.serverError().entity(
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
}
}
@PUT @PUT
@Path("/{roleName}") @Path("/{roleName}")
@Override @Override
public Response updateRole(@PathParam("roleName") String roleName, RoleInfo roleInfo, public Response updateRole(@PathParam("roleName") String roleName, RoleInfo roleInfo,
@QueryParam("user-store") String userStoreName) { @QueryParam("user-store") String userStoreName) {
if (userStoreName != null && !userStoreName.isEmpty()) { if (userStoreName != null && !userStoreName.isEmpty()) {
roleName = userStoreName + "/" + roleName; roleName = userStoreName + "/" + roleName;
} }
@ -271,7 +352,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
if (!userStoreManager.isExistingRole(roleName)) { if (!userStoreManager.isExistingRole(roleName)) {
return Response.status(404).entity( return Response.status(404).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" + new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" +
roleName + "'").build()).build(); roleName + "'").build()).build();
} }
final AuthorizationManager authorizationManager = userRealm.getAuthorizationManager(); final AuthorizationManager authorizationManager = userRealm.getAuthorizationManager();
@ -287,7 +368,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
if (roleInfo.getUsers() != null) { if (roleInfo.getUsers() != null) {
SetReferenceTransformer<String> transformer = new SetReferenceTransformer<>(); SetReferenceTransformer<String> transformer = new SetReferenceTransformer<>();
transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(newRoleName)), transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(newRoleName)),
Arrays.asList(roleInfo.getUsers())); Arrays.asList(roleInfo.getUsers()));
final String[] usersToAdd = transformer.getObjectsToAdd().toArray(new String[transformer final String[] usersToAdd = transformer.getObjectsToAdd().toArray(new String[transformer
.getObjectsToAdd().size()]); .getObjectsToAdd().size()]);
final String[] usersToDelete = transformer.getObjectsToRemove().toArray(new String[transformer final String[] usersToDelete = transformer.getObjectsToRemove().toArray(new String[transformer
@ -307,7 +388,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
} }
//TODO: Need to send the updated role information in the entity back to the client //TODO: Need to send the updated role information in the entity back to the client
return Response.status(Response.Status.OK).entity("Role '" + roleInfo.getRoleName() + "' has " + return Response.status(Response.Status.OK).entity("Role '" + roleInfo.getRoleName() + "' has " +
"successfully been updated").build(); "successfully been updated").build();
} catch (UserStoreException e) { } catch (UserStoreException e) {
String msg = "Error occurred while updating role '" + roleName + "'"; String msg = "Error occurred while updating role '" + roleName + "'";
log.error(msg, e); log.error(msg, e);
@ -330,7 +411,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
if (!userStoreManager.isExistingRole(roleName)) { if (!userStoreManager.isExistingRole(roleName)) {
return Response.status(404).entity( return Response.status(404).entity(
new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" + new ErrorResponse.ErrorResponseBuilder().setMessage("No role exists with the name '" +
roleName + "'").build()).build(); roleName + "'").build()).build();
} }
final AuthorizationManager authorizationManager = userRealm.getAuthorizationManager(); final AuthorizationManager authorizationManager = userRealm.getAuthorizationManager();
@ -354,7 +435,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
@Path("/{roleName}/users") @Path("/{roleName}/users")
@Override @Override
public Response updateUsersOfRole(@PathParam("roleName") String roleName, public Response updateUsersOfRole(@PathParam("roleName") String roleName,
@QueryParam("user-store") String userStoreName, List<String> users) { @QueryParam("user-store") String userStoreName, List<String> users) {
if (userStoreName != null && !userStoreName.isEmpty()) { if (userStoreName != null && !userStoreName.isEmpty()) {
roleName = userStoreName + "/" + roleName; roleName = userStoreName + "/" + roleName;
} }
@ -367,7 +448,7 @@ public class RoleManagementServiceImpl implements RoleManagementService {
} }
SetReferenceTransformer<String> transformer = new SetReferenceTransformer<>(); SetReferenceTransformer<String> transformer = new SetReferenceTransformer<>();
transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(roleName)), transformer.transform(Arrays.asList(userStoreManager.getUserListOfRole(roleName)),
users); users);
final String[] usersToAdd = transformer.getObjectsToAdd().toArray(new String[transformer final String[] usersToAdd = transformer.getObjectsToAdd().toArray(new String[transformer
.getObjectsToAdd().size()]); .getObjectsToAdd().size()]);
final String[] usersToDelete = transformer.getObjectsToRemove().toArray(new String[transformer final String[] usersToDelete = transformer.getObjectsToRemove().toArray(new String[transformer
@ -376,7 +457,8 @@ public class RoleManagementServiceImpl implements RoleManagementService {
userStoreManager.updateUserListOfRole(roleName, usersToDelete, usersToAdd); userStoreManager.updateUserListOfRole(roleName, usersToDelete, usersToAdd);
return Response.status(Response.Status.OK).entity("Role '" + roleName + "' has " + return Response.status(Response.Status.OK).entity("Role '" + roleName + "' has " +
"successfully been updated with the user list").build(); "successfully been updated with the user list")
.build();
} catch (UserStoreException e) { } catch (UserStoreException e) {
String msg = "Error occurred while updating the users of the role '" + roleName + "'"; String msg = "Error occurred while updating the users of the role '" + roleName + "'";
log.error(msg, e); log.error(msg, e);
@ -400,7 +482,8 @@ public class RoleManagementServiceImpl implements RoleManagementService {
// removing all internal roles, roles created for Service-providers and application related roles. // removing all internal roles, roles created for Service-providers and application related roles.
List<String> filteredRoles = new ArrayList<>(); List<String> filteredRoles = new ArrayList<>();
for (String role : roles) { for (String role : roles) {
if (!(role.startsWith("Internal/") || role.startsWith("Authentication/") || role.startsWith("Application/"))) { if (!(role.startsWith("Internal/") || role.startsWith("Authentication/") || role.startsWith(
"Application/"))) {
if (!filterRolesByName) { if (!filterRolesByName) {
filteredRoles.add(role); filteredRoles.add(role);
} else { } else {
@ -413,4 +496,31 @@ public class RoleManagementServiceImpl implements RoleManagementService {
return filteredRoles; return filteredRoles;
} }
private Set<Permission> mergePermissions(UIPermissionNode[] permissionNodes, Set<Permission> permissions)
throws UserStoreException, UserAdminException {
for (UIPermissionNode permissionNode : permissionNodes) {
if (permissionNode.getNodeList().length > 0) {
mergePermissions(permissionNode.getNodeList(), permissions);
}
if (permissionNode.isSelected()) {
permissions.add(new Permission(permissionNode.getResourcePath(), CarbonConstants.UI_PERMISSION_ACTION));
}
}
return permissions;
}
private UIPermissionNode getRolePermissions(String roleName) throws UserStoreException, UserAdminException {
final UserRealm userRealm = DeviceMgtAPIUtils.getUserRealm();
if (!userRealm.getUserStoreManager().isExistingRole(roleName)) {
throw new IllegalArgumentException("No role exists with the name '" + roleName + "'");
}
final UIPermissionNode rolePermissions = this.getUIPermissionNode(roleName, userRealm);
if (rolePermissions == null) {
if (log.isDebugEnabled()) {
log.debug("No permissions found for the role '" + roleName + "'");
}
}
return rolePermissions;
}
} }

@ -608,10 +608,10 @@ public class GroupDAOImpl implements GroupDAO {
"(SELECT GROUP_ID FROM DM_ROLE_GROUP_MAP WHERE ROLE IN ("; "(SELECT GROUP_ID FROM DM_ROLE_GROUP_MAP WHERE ROLE IN (";
int index = 0; int index = 0;
while (index++ < rolesCount) { while (index++ < rolesCount - 1) {
sql += (rolesCount - 1 != index) ? "?," : "?"; sql += "?,";
} }
sql += ")) gr WHERE g.ID = gr.GROUP_ID AND TENANT_ID = ? GROUP BY g.ID"; sql += "?)) gr WHERE g.ID = gr.GROUP_ID AND TENANT_ID = ? GROUP BY g.ID";
stmt = conn.prepareStatement(sql); stmt = conn.prepareStatement(sql);
index = 0; index = 0;

@ -31,6 +31,7 @@ import org.wso2.carbon.device.mgt.core.common.BaseDeviceManagementTest;
import org.wso2.carbon.device.mgt.core.common.TestDataHolder; import org.wso2.carbon.device.mgt.core.common.TestDataHolder;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class GroupPersistTests extends BaseDeviceManagementTest { public class GroupPersistTests extends BaseDeviceManagementTest {
@ -47,7 +48,7 @@ public class GroupPersistTests extends BaseDeviceManagementTest {
} }
@Test @Test
public void testAddGroupTest() { public void addGroupTest() {
DeviceGroup deviceGroup = TestDataHolder.generateDummyGroupData(); DeviceGroup deviceGroup = TestDataHolder.generateDummyGroupData();
try { try {
GroupManagementDAOFactory.beginTransaction(); GroupManagementDAOFactory.beginTransaction();
@ -72,7 +73,7 @@ public class GroupPersistTests extends BaseDeviceManagementTest {
log.debug("Group name: " + group.getName()); log.debug("Group name: " + group.getName());
} }
@Test(dependsOnMethods = {"testAddGroupTest"}) @Test(dependsOnMethods = {"addGroupTest"})
public void getGroupTest() { public void getGroupTest() {
try { try {
GroupManagementDAOFactory.openConnection(); GroupManagementDAOFactory.openConnection();
@ -96,7 +97,82 @@ public class GroupPersistTests extends BaseDeviceManagementTest {
} }
} }
@Test(dependsOnMethods = {"testAddGroupTest"}) @Test(dependsOnMethods = {"addGroupTest"})
public void shareGroupTest() {
try {
GroupManagementDAOFactory.beginTransaction();
List<String> addedRoles = new ArrayList<>();
for (int i = 0; i < 3; i++) {
String role = "role-" + i;
groupDAO.addRole(groupId, role, TestDataHolder.SUPER_TENANT_ID);
addedRoles.add(role);
}
GroupManagementDAOFactory.commitTransaction();
List<String> roles = groupDAO.getRoles(groupId, TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(roles, addedRoles, "Added roles are not equal to returned roles.");
log.debug("Group shared with roles.");
} catch (GroupManagementDAOException e) {
String msg = "Error occurred while find group by name.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
GroupManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = {"shareGroupTest"})
public void getShareGroupTest() {
try {
GroupManagementDAOFactory.openConnection();
List<String> roles = groupDAO.getRoles(groupId, TestDataHolder.SUPER_TENANT_ID);
roles.remove(0);
List<DeviceGroup> deviceGroups = groupDAO.getGroups(roles.toArray(new String[roles.size()]), TestDataHolder.SUPER_TENANT_ID);
Assert.assertEquals(deviceGroups.size(), 1, "Unexpected number of device groups found with role.");
Assert.assertEquals(deviceGroups.get(0).getGroupId(), groupId, "Unexpected groupId found with role.");
log.debug("Group found for given roles.");
} catch (GroupManagementDAOException e) {
String msg = "Error occurred while getting groups shared with roles.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (SQLException e) {
String msg = "Error occurred while opening a connection to the data source.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
GroupManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = {"getShareGroupTest"})
public void unshareGroupTest() {
try {
GroupManagementDAOFactory.beginTransaction();
List<String> rolesToRemove = groupDAO.getRoles(groupId, TestDataHolder.SUPER_TENANT_ID);
for (String role : rolesToRemove) {
groupDAO.removeRole(groupId, role, TestDataHolder.SUPER_TENANT_ID);
}
GroupManagementDAOFactory.commitTransaction();
List<String> roles = groupDAO.getRoles(groupId, TestDataHolder.SUPER_TENANT_ID);
Assert.assertNotEquals(roles, rolesToRemove, "Roles not removed.");
log.debug("Group unshared with given roles.");
} catch (GroupManagementDAOException e) {
String msg = "Error occurred while find group by name.";
log.error(msg, e);
Assert.fail(msg, e);
} catch (TransactionManagementException e) {
String msg = "Error occurred while opening a connection to the data source.";
log.error(msg, e);
Assert.fail(msg, e);
} finally {
GroupManagementDAOFactory.closeConnection();
}
}
@Test(dependsOnMethods = {"addGroupTest"})
public void addDeviceToGroupTest() { public void addDeviceToGroupTest() {
Device initialTestDevice = TestDataHolder.initialTestDevice; Device initialTestDevice = TestDataHolder.initialTestDevice;
DeviceGroup deviceGroup = getGroupById(groupId); DeviceGroup deviceGroup = getGroupById(groupId);
@ -162,7 +238,7 @@ public class GroupPersistTests extends BaseDeviceManagementTest {
} }
} }
@Test(dependsOnMethods = {"removeDeviceFromGroupTest"}) @Test(dependsOnMethods = {"removeDeviceFromGroupTest", "unshareGroupTest"})
public void updateGroupTest() { public void updateGroupTest() {
String name = "Test Updated"; String name = "Test Updated";
String desc = "Desc updated"; String desc = "Desc updated";

@ -80,7 +80,7 @@
<div id="ast-container" class="ast-container list-view"> <div id="ast-container" class="ast-container list-view">
<div class="ctrl-info-panel col-centered text-center wr-login"> <div class="ctrl-info-panel col-centered text-center wr-login">
<h2>You don't have any group registered at the moment.</h2> <h2>You don't have any group registered at the moment.</h2>
<br/> <br />
{{#if permissions.ADD_GROUP}} {{#if permissions.ADD_GROUP}}
<p class="text-center"> <p class="text-center">
<a href="{{@app.context}}/group/add" class="wr-btn"> <a href="{{@app.context}}/group/add" class="wr-btn">
@ -115,67 +115,37 @@
</div> </div>
<div id="user-names"> <div id="user-names">
<h4> <h4>
Enter user name to manage group sharing Select user roles to manage group sharing
<br><br> <br><br>
<input type="text" id="share-user-selector" class="form-control modal-input operationDataKeys"> <div style="max-height: 200px; overflow: scroll">
</input> <br />
{{#each userRoles}}
<div class="wr-input-control">
<label class="wr-input-control checkbox">
<input class="roleCheckBoxes" type="checkbox"
data-role-name="{{this}}" />
<span class="helper"
title="{{this}}">{{this}}</span>
</label>
</div>
{{/each}}
</div>
</h4> </h4>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="buttons"> <div class="buttons">
{{#if permissions.CREATE_GROUP_ROLES}}
<a href="{{@app.context}}/role/add" class="btn-operations">
New Role
</a>
<a href="#" id="share-group-new-role-from-selection" class="btn-operations">
New Role from Selection
</a>
{{/if}}
<a href="#" id="share-group-next-link" class="btn-operations"> <a href="#" id="share-group-next-link" class="btn-operations">
Next Next
</a> </a>
<a href="#" id="share-group-w1-cancel-link" class="btn-operations btn-default">
Cancel
</a>
</div>
</div>
</div>
<div id="share-group-w2-modal-content" class="hide">
<div class="modal-header">
<h3 class="pull-left modal-title">
<span>
<span class="fw-stack">
<i class="fw fw-ring fw-stack-2x"></i>
<i class="fw fw-share fw-stack-1x"></i>
</span> Group Sharing
</span>
</h3>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i
class="fw fw-cancel"></i></button>
</div>
<div class="modal-body add-margin-top-2x add-margin-bottom-2x">
<div id="notification-error-msg" class="alert alert-danger hidden" role="alert">
<i class="icon fw fw-error"></i><span></span>
</div>
<div id="user-roles">
<h4>
Select sharing roles
<br><br>
</h4>
</div>
{{#if permissions.CREATE_GROUP_ROLES}}
<div class="buttons">
<a href="#" id="share-group-w2-add-new-role-link" class="btn-operations">
<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-add fw-stack-1x"></i></span> Add New Role
</a>
</div>
{{/if}}
</div>
<div class="modal-footer">
<div class="buttons">
<a href="#" id="share-group-yes-link" class="btn-operations">
OK
</a>
<a href="#" id="share-group-w2-cancel-link" class="btn-operations btn-default">
Cancel
</a>
</div> </div>
</div> </div>
</div> </div>
@ -201,25 +171,10 @@
<h4> <h4>
Enter Group Sharing Role Name Enter Group Sharing Role Name
<br><br> <br><br>
<input type="text" id="group-sharing-role-name" class="form-control modal-input operationDataKeys"/> <input type="text" id="group-sharing-role-name"
<br><br> class="form-control modal-input operationDataKeys" />
Role Permissions
<br><br> <br><br>
</h4> </h4>
<table class="table">
<tbody id="permission-table-container">
{{#each groupPermissions}}
<tr>
<td>{{this}}</td>
<td>
<a href="#" class="btn-operations btn-default" onclick="togglePermissionAction(this)" data-value="unchecked">
<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-add fw-stack-1x"></i></span>
</a>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
@ -239,7 +194,43 @@
<div class="content"> <div class="content">
<div class="row"> <div class="row">
<div class="col-lg-5 col-md-6 col-centered"> <div class="col-lg-5 col-md-6 col-centered">
<h3>Group sharing updated successfully.</h3> <h3>Group was successfully updated.</h3>
<br />
Do you need to Add / Remove users to the chosen roles?
<div class="buttons">
<a href="{{@app.context}}/users" id="share-group-add-users-yes-link"
class="btn-operations">
Yes
</a>
<a href="#" class="btn-operations btn-default" data-dismiss="modal">
No
</a>
</div>
<br />
</div>
</div>
</div>
</div>
<div id="create-combined-role-200-content" class="hide">
<div class="content">
<div class="row">
<div class="col-lg-5 col-md-6 col-centered">
<h3>New Role was successfully created.</h3>
<br />
Do you need to Add / Remove users to the chosen roles?
<div class="buttons">
<a href="{{@app.context}}/users" id="share-group-add-users-yes-link"
class="btn-operations">
Yes
</a>
<a href="#" class="btn-operations btn-default" data-dismiss="modal">
No
</a>
</div>
<br />
</div> </div>
</div> </div>
</div> </div>
@ -256,7 +247,8 @@
Yes Yes
</a> </a>
<a href="#" id="remove-group-cancel-link" class="btn-operations btn-default"> <a href="#" id="remove-group-cancel-link" class="btn-operations btn-default"
data-dismiss="modal">
Cancel Cancel
</a> </a>
</div> </div>

@ -23,6 +23,10 @@ function onRequest(context) {
var groupPermissions = require("/app/pages/cdmf.page.groups/public/group-permissions.json"); var groupPermissions = require("/app/pages/cdmf.page.groups/public/group-permissions.json");
var currentUser = session.get(constants.USER_SESSION_KEY); var currentUser = session.get(constants.USER_SESSION_KEY);
var page = {}; var page = {};
var rolesResult = userModule.getRoles();
if (rolesResult.status == "success") {
page.userRoles = rolesResult.content;
}
if (currentUser) { if (currentUser) {
page.permissions = userModule.getUIPermissions(); page.permissions = userModule.getUIPermissions();
page.permissions.list = stringify(page.permissions); page.permissions.list = stringify(page.permissions);

@ -110,12 +110,12 @@ function loadGroups() {
var objects = []; var objects = [];
$(data.deviceGroups).each(function (index) { $(data.deviceGroups).each(function (index) {
objects.push({ objects.push({
groupId: data.deviceGroups[index].id, groupId: data.deviceGroups[index].id,
name: data.deviceGroups[index].name, name: data.deviceGroups[index].name,
description: data.deviceGroups[index].description, description: data.deviceGroups[index].description,
owner: data.deviceGroups[index].owner, owner: data.deviceGroups[index].owner,
dateOfCreation: data.deviceGroups[index].dateOfCreation dateOfCreation: data.deviceGroups[index].dateOfCreation
}) })
}); });
var json = { var json = {
"recordsTotal": data.count, "recordsTotal": data.count,
@ -154,34 +154,50 @@ function loadGroups() {
class: 'text-right content-fill text-left-on-grid-view no-wrap', class: 'text-right content-fill text-left-on-grid-view no-wrap',
render: function (id, type, row, meta) { render: function (id, type, row, meta) {
var html; var html;
if ($.hasPermission("VIEW_GROUP_DEVICES")){ if ($.hasPermission("VIEW_GROUP_DEVICES")) {
html = '<a href="devices?groupId=' + row.groupId + '&groupName=' + row.name + '" data-click-event="remove-form" class="btn padding-reduce-on-grid-view">' + html = '<a href="devices?groupId=' + row.groupId + '&groupName=' + row.name
'<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-view fw-stack-1x"></i></span>' + + '" data-click-event="remove-form" class="btn padding-reduce-on-grid-view">' +
'<span class="hidden-xs hidden-on-grid-view">View Devices</span></a>'; '<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-view fw-stack-1x"></i></span>'
+
html += '<a href="group/' + row.name + '/' + row.groupId + '/analytics" data-click-event="remove-form" class="btn padding-reduce-on-grid-view">' + '<span class="hidden-xs hidden-on-grid-view">View Devices</span></a>';
'<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-statistics fw-stack-1x"></i></span>' +
'<span class="hidden-xs hidden-on-grid-view">Analytics</span></a>'; html += '<a href="group/' + row.name + '/' + row.groupId
+ '/analytics" data-click-event="remove-form" class="btn padding-reduce-on-grid-view">' +
'<span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-statistics fw-stack-1x"></i></span>'
+
'<span class="hidden-xs hidden-on-grid-view">Analytics</span></a>';
} else { } else {
html = ''; html = '';
} }
if($.hasPermission("SHARE_GROUP")) { if ($.hasPermission("SHARE_GROUP")) {
html += '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view share-group-link" data-group-id="' + row.groupId + '" ' + html +=
'data-group-owner="' + row.owner + '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-share fw-stack-1x"></i></span>' + '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view share-group-link" data-group-id="'
+ row.groupId + '" ' +
'data-group-owner="' + row.owner
+ '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-share fw-stack-1x"></i></span>'
+
'<span class="hidden-xs hidden-on-grid-view">Share</span></a>'; '<span class="hidden-xs hidden-on-grid-view">Share</span></a>';
} else { } else {
html += ''; html += '';
} }
if($.hasPermission("UPDATE_GROUP")) { if ($.hasPermission("UPDATE_GROUP")) {
html += '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view edit-group-link" data-group-name="' + row.name + '" ' + html +=
'data-group-owner="' + row.owner + '" data-group-description="' + row.description + '" data-group-id="' + row.groupId + '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i>' + '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view edit-group-link" data-group-name="'
+ row.name + '" ' +
'data-group-owner="' + row.owner + '" data-group-description="' + row.description
+ '" data-group-id="' + row.groupId
+ '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i>' +
'<i class="fw fw-edit fw-stack-1x"></i></span><span class="hidden-xs hidden-on-grid-view">Edit</span></a>'; '<i class="fw fw-edit fw-stack-1x"></i></span><span class="hidden-xs hidden-on-grid-view">Edit</span></a>';
} else { } else {
html += ''; html += '';
} }
if ($.hasPermission("REMOVE_GROUP")) { if ($.hasPermission("REMOVE_GROUP")) {
html += '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view remove-group-link" data-group-id="' + row.groupId + '" ' + html +=
'data-group-owner="' + row.owner + '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-delete fw-stack-1x"></i>' + '<a href="#" data-click-event="remove-form" class="btn padding-reduce-on-grid-view remove-group-link" data-group-id="'
+ row.groupId + '" ' +
'data-group-owner="' + row.owner
+ '"><span class="fw-stack"><i class="fw fw-ring fw-stack-2x"></i><i class="fw fw-delete fw-stack-1x"></i>'
+
'</span><span class="hidden-xs hidden-on-grid-view">Delete</span></a>'; '</span><span class="hidden-xs hidden-on-grid-view">Delete</span></a>';
} else { } else {
html += ''; html += '';
@ -336,7 +352,7 @@ function hidePopup() {
$(modalPopupContent).html(""); $(modalPopupContent).html("");
$(modalPopupContent).removeClass("operation-data"); $(modalPopupContent).removeClass("operation-data");
$(modalPopup).modal('hide'); $(modalPopup).modal('hide');
$('body').removeClass('modal-open').css('padding-right','0px'); $('body').removeClass('modal-open').css('padding-right', '0px');
$('.modal-backdrop').remove(); $('.modal-backdrop').remove();
} }
@ -352,33 +368,37 @@ function attachEvents() {
$("a.share-group-link").click(function () { $("a.share-group-link").click(function () {
var groupId = $(this).data("group-id"); var groupId = $(this).data("group-id");
var groupOwner = $(this).data("group-owner"); var groupOwner = $(this).data("group-owner");
$(modalPopupContent).html($('#share-group-w1-modal-content').html()); $(modalPopupContent).html($('#share-group-w1-modal-content').html());
$("a#share-group-next-link").show();
showPopup(); showPopup();
$("a#share-group-next-link").click(function () {
var successCallback = function (data) { markAlreadySavedUsersRoles(groupId);
if(data === 'true') { var shareGroupNextLink = $("a#share-group-next-link");
getAllRoles(groupId, selectedUser); shareGroupNextLink.click(function () {
} else { var roles = [];
var errorMsgWrapper = "#notification-error-msg"; $('.modal .roleCheckBoxes').each(
var errorMsg = "#notification-error-msg span"; function () {
$(errorMsg).text("User does not exist."); if ($(this).is(':checked')) {
$(errorMsgWrapper).removeClass("hidden"); roles.push($(this).data('role-name'));
}
} }
} );
var selectedUser = $('#share-user-selector').val(); updateGroupShare(groupId, roles);
if (selectedUser == $("#group-listing").data("current-user")) {
$("#user-names").html("Please specify a user other than current user.");
$("a#share-group-next-link").hide();
} else {
invokerUtil.get("/api/device-mgt/v1.0/users/checkUser?username=" + selectedUser,
successCallback, function (message) {
displayErrors(message);
});
}
}); });
$("a#share-group-w1-cancel-link").click(function () {
hidePopup(); var shareGroupNewRoleFromSelectionLink = $("a#share-group-new-role-from-selection");
shareGroupNewRoleFromSelectionLink.click(function () {
var roles = [];
$('.modal .roleCheckBoxes').each(
function () {
if ($(this).is(':checked')) {
roles.push($(this).data('role-name'));
}
}
);
addNewRole(roles);
// $(modalPopupContent).html($('#share-group-w3-modal-content').html());
// createNewRole(roles);
}); });
}); });
@ -408,8 +428,8 @@ function attachEvents() {
}; };
invokerUtil.delete("/api/device-mgt/v1.0/groups/id/" + groupId, invokerUtil.delete("/api/device-mgt/v1.0/groups/id/" + groupId,
successCallback, function (message) { successCallback, function (message) {
displayErrors(message); displayErrors(message);
}); });
}); });
@ -453,8 +473,8 @@ function attachEvents() {
}; };
invokerUtil.put("/api/device-mgt/v1.0/groups/id/" + groupId, group, invokerUtil.put("/api/device-mgt/v1.0/groups/id/" + groupId, group,
successCallback, function (message) { successCallback, function (message) {
displayErrors(message); displayErrors(message);
}); });
}); });
@ -464,16 +484,22 @@ function attachEvents() {
}); });
} }
function getAllRoles(groupId, selectedUser) { function markAlreadySavedUsersRoles(groupId) {
$(modalPopupContent).html($('#share-group-w2-modal-content').html());
$("a#share-group-yes-link").hide();
var successCallback = function (data, textStatus, xhr) { var successCallback = function (data, textStatus, xhr) {
data = JSON.parse(data); data = JSON.parse(data);
if (xhr.status == 200) { if (xhr.status == 200) {
if (data.roles.length > 0) { if (data.roles.length > 0) {
generateRoleMap(groupId, selectedUser, data.roles); for (var i = 0; i < data.roles.length; i++) {
$('.roleCheckBoxes').each(
function () {
if (data.roles[i] == $(this).data('role-name')) {
$(this).attr('checked', true);
}
}
);
}
} else { } else {
$('#user-roles').html("There is no any roles for this group."); return;
} }
} else { } else {
displayErrors(xhr); displayErrors(xhr);
@ -481,98 +507,17 @@ function getAllRoles(groupId, selectedUser) {
}; };
invokerUtil.get("/api/device-mgt/v1.0/groups/id/" + groupId + "/roles", invokerUtil.get("/api/device-mgt/v1.0/groups/id/" + groupId + "/roles",
successCallback, function (message) { successCallback, function (message) {
displayErrors(message);
});
$("a#share-group-w2-cancel-link").click(function () {
hidePopup();
});
}
function generateRoleMap(groupId, selectedUser, allRoles) {
var successCallback = function (data, textStatus, xhr) {
data = JSON.parse(data);
if (xhr.status == 200) {
var userRoles = [];
if(data != "EMPTY") {
userRoles = data.roles;
}
var str = $('#user-roles').html();
for (var i = 0; i < allRoles.length; i++) {
var isChecked = '';
for (var j = 0; j < userRoles.length; j++) {
if (allRoles[i] == userRoles[j]) {
isChecked = 'checked';
break;
}
}
str += '<label class="wr-input-control checkbox"><input type="checkbox" class="form-control modal-input operationDataKeys" id="user-role-' + allRoles[i] + '" value="' + allRoles[i]
+ '" ' + isChecked + '/>' +'<span class="helper" title="Check to share this group role with user."> &nbsp;&nbsp;&nbsp;'+ allRoles[i] + '</span></label><br><br>';
}
$('#user-roles').html(str);
$("a#share-group-yes-link").show();
$("a#share-group-yes-link").show();
$("a#share-group-yes-link").click(function () {
var roles = [];
for (var i = 0; i < allRoles.length; i++) {
if ($('#user-role-' + allRoles[i]).is(':checked')) {
roles.push(allRoles[i]);
}
}
updateGroupShare(groupId, selectedUser, roles);
});
$("a#share-group-w2-add-new-role-link").click(function () {
addNewRole(groupId, selectedUser, allRoles);
});
} else {
displayErrors(xhr);
}
};
invokerUtil.get("/api/device-mgt/v1.0/groups/id/" + groupId + "/roles?userName=" + selectedUser,
successCallback, function (message) {
displayErrors(message); displayErrors(message);
}); });
$("a#share-group-w2-cancel-link").click(function () {
hidePopup();
});
} }
function addNewRole(groupId, selectedUser, allRoles) { function addNewRole(roles) {
$(modalPopupContent).html($('#share-group-w3-modal-content').html()); $(modalPopupContent).html($('#share-group-w3-modal-content').html());
function getPermissions() {
var PERMISSION_PREFIX = '/permission/admin/';
var permissions = [];
$('#permission-table-container').find('tr').each(function () {
var row = $(this).closest('tr');
var permission = $(row).find('td:nth-child(1)').text();
var check = $(row).find('td:nth-child(2) a').data('value');
if(check === 'checked') {
permission = PERMISSION_PREFIX + permission;
permissions.push(permission);
}
});
return permissions;
};
$("a#share-group-w3-yes-link").click(function () { $("a#share-group-w3-yes-link").click(function () {
var successCallback = function (data, status, jqXHR) {
if(status == "success") {
getAllRoles(groupId, selectedUser);
}
}
var roleName = $('#group-sharing-role-name').val(); var roleName = $('#group-sharing-role-name').val();
var users = []; if (roleName) {
if(roleName) { createNewCombinedRole(roleName, roles);
var groupRoleInfo = {"roleName": roleName, "permissions": getPermissions(), "users": users};
var currentUser = $("#group-listing").data("current-user");
invokerUtil.post("/api/device-mgt/v1.0/groups/id/" + groupId + "/roles/create?userName=" + currentUser,
groupRoleInfo, successCallback, function (message) {
displayErrors(message);
});
} else { } else {
var errorMsgWrapper = "#notification-error-msg"; var errorMsgWrapper = "#notification-error-msg";
var errorMsg = "#notification-error-msg span"; var errorMsg = "#notification-error-msg span";
@ -588,7 +533,7 @@ function addNewRole(groupId, selectedUser, allRoles) {
function togglePermissionAction(element) { function togglePermissionAction(element) {
$(element).data('value', 'checked'); $(element).data('value', 'checked');
var icon = $(element).find("i")[1]; var icon = $(element).find("i")[1];
if($(icon).hasClass('fw-minus')) { if ($(icon).hasClass('fw-minus')) {
$(icon).removeClass('fw-minus'); $(icon).removeClass('fw-minus');
$(icon).addClass('fw-add'); $(icon).addClass('fw-add');
$(element).data('value', 'unchecked'); $(element).data('value', 'unchecked');
@ -599,7 +544,7 @@ function togglePermissionAction(element) {
} }
} }
function updateGroupShare(groupId, selectedUser, roles) { function updateGroupShare(groupId, roles) {
var successCallback = function (data) { var successCallback = function (data) {
$(modalPopupContent).html($('#share-group-200-content').html()); $(modalPopupContent).html($('#share-group-200-content').html());
setTimeout(function () { setTimeout(function () {
@ -608,11 +553,21 @@ function updateGroupShare(groupId, selectedUser, roles) {
}, 2000); }, 2000);
}; };
var deviceGroupShare = {"username": selectedUser, "groupRoles": roles };
invokerUtil.post("/api/device-mgt/v1.0/groups/id/" + groupId + "/share", invokerUtil.post("/api/device-mgt/v1.0/groups/id/" + groupId + "/share",
deviceGroupShare, successCallback, function (message) { roles, successCallback, function (message) {
displayErrors(message); displayErrors(message);
}); });
}
function createNewCombinedRole(roleName, roleList) {
var successCallback = function (data, status, jqXHR, isLast) {
$(modalPopupContent).html($('#create-combined-role-200-content').html());
showPopup();
};
invokerUtil.post("/api/device-mgt/v1.0/roles/create-combined-role/" + roleName, roleList,
successCallback, function (message) {
displayErrors(message);
});
} }
function displayErrors(jqXHR) { function displayErrors(jqXHR) {

@ -131,7 +131,7 @@ function loadRoles() {
class: "fade-edge", class: "fade-edge",
data: "name", data: "name",
render: function (name, type, row, meta) { render: function (name, type, row, meta) {
return '<h4>' + name + 'role</h4>'; return '<h4>' + name + '</h4>';
} }
}, },
{ {

Loading…
Cancel
Save