diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscribingDeviceIdHolder.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscribingDeviceIdHolder.java index eb92f07bc06..0dd283b3fe8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscribingDeviceIdHolder.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/SubscribingDeviceIdHolder.java @@ -26,6 +26,7 @@ public class SubscribingDeviceIdHolder { private Map appInstalledDevices = new HashMap<>(); private Map appInstallableDevices = new HashMap<>(); private Map appReInstallableDevices = new HashMap<>(); + private Map appReUnInstallableDevices = new HashMap<>(); private Map skippedDevices = new HashMap<>(); public Map getAppInstalledDevices() { @@ -57,4 +58,12 @@ public class SubscribingDeviceIdHolder { public void setSkippedDevices(Map skippedDevices) { this.skippedDevices = skippedDevices; } + + public Map getAppReUnInstallableDevices() { + return appReUnInstallableDevices; + } + + public void setAppReUnInstallableDevices(Map appReUnInstallableDevices) { + this.appReUnInstallableDevices = appReUnInstallableDevices; + } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java index b4b55e6edb3..3c8a1d844ee 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.common/src/main/java/org/wso2/carbon/device/application/mgt/common/services/SubscriptionManager.java @@ -83,6 +83,23 @@ public interface SubscriptionManager { */ void updateScheduledSubscriptionStatus(int id, ExecutionStatus status) throws SubscriptionManagementException; + /** + * Perform google enterprise app install + * @param applicationUUID UUID of the application to subscribe/unsubscribe + * @param params list of subscribers. This list can be of either + * {@link org.wso2.carbon.device.mgt.common.DeviceIdentifier} if {@param subType} is equal + * to DEVICE or {@link String} if {@param subType} is USER, ROLE or GROUP + * @param subType subscription type. E.g. DEVICE, USER, ROLE, GROUP {@see { + * @param action subscription action. E.g. INSTALL/UNINSTALL {@see { + * @param generic type of the method. + * @return {@link ApplicationInstallResponse} + * @throws ApplicationManagementException ApplicationManagementException if error occurs when subscribing to the + * given application + * @link org.wso2.carbon.device.application.mgt.common.SubscriptionType}} + */ + void performEntAppSubscription(String applicationUUID, List params, String subType, String action) + throws ApplicationManagementException; + /*** * This method used to get the app id ,device ids and pass them to DM service method. * @@ -106,7 +123,7 @@ public interface SubscriptionManager { * @return {@link PaginationResult} pagination result of the category details. * @throws {@link ApplicationManagementException} Exception of the application management */ - PaginationResult getAppInstalledCategories(int offsetValue, int limitValue, String appUUID, + PaginationResult getAppInstalledSubscribers(int offsetValue, int limitValue, String appUUID, String subType) throws ApplicationManagementException; /** diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java index 33fafe57dbe..5b7f9a00cbb 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/SubscriptionDAO.java @@ -33,7 +33,7 @@ import java.util.Map; */ public interface SubscriptionDAO { - List addDeviceSubscription(String subscribedBy, List deviceIds, String subscribedFrom, + void addDeviceSubscription(String subscribedBy, List deviceIds, String subscribedFrom, String installStatus, int releaseId, int tenantId ) throws ApplicationManagementDAOException; void updateDeviceSubscription(String updateBy, List deviceIds, String action, String actionTriggeredFrom, @@ -66,13 +66,13 @@ public interface SubscriptionDAO { Map getDeviceSubscriptions(List deviceIds, int appReleaseId, int tenantId) throws ApplicationManagementDAOException; - List getSubscribedUserNames(List users, int tenantId) throws + List getAppSubscribedUserNames(List users, int appReleaseId, int tenantId) throws ApplicationManagementDAOException; - List getSubscribedRoleNames(List roles, int tenantId) throws + List getAppSubscribedRoleNames(List roles, int appReleaseId, int tenantId) throws ApplicationManagementDAOException; - List getSubscribedGroupNames(List groups, int tenantId) throws + List getAppSubscribedGroupNames(List groups, int appReleaseId, int tenantId) throws ApplicationManagementDAOException; void updateSubscriptions(int tenantId, String updateBy, List paramList, @@ -81,7 +81,8 @@ public interface SubscriptionDAO { List getDeviceSubIds(List deviceIds, int applicationReleaseId, int tenantId) throws ApplicationManagementDAOException; - List getDeviceSubIdsForOperation (int operationId, int tenantId) throws ApplicationManagementDAOException; + List getDeviceSubIdsForOperation(int operationId, int deviceID, int tenantId) + throws ApplicationManagementDAOException; boolean updateDeviceSubStatus(int deviceId, List deviceSubIds, String status, int tenantcId) throws ApplicationManagementDAOException; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java index 444445a2884..46621cb9d4f 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/GenericSubscriptionDAOImpl.java @@ -49,7 +49,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc private static Log log = LogFactory.getLog(GenericSubscriptionDAOImpl.class); @Override - public List addDeviceSubscription(String subscribedBy, List deviceIds, + public void addDeviceSubscription(String subscribedBy, List deviceIds, String subscribedFrom, String installStatus, int releaseId, int tenantId) throws ApplicationManagementDAOException { String sql = "INSERT INTO " @@ -82,13 +82,6 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc } } stmt.executeBatch(); - try (ResultSet rs = stmt.getGeneratedKeys()) { - List deviceSubIds = new ArrayList<>(); - while (rs.next()) { - deviceSubIds.add(rs.getInt(1)); - } - return deviceSubIds; - } } } catch (DBConnectionException e) { String msg = "Error occured while obtaining database connection to add device subscription for application " @@ -425,8 +418,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc } } - @Override - public List getSubscribedUserNames(List users, int tenantId) + public List getAppSubscribedUserNames(List users, int appReleaseId, int tenantId) throws ApplicationManagementDAOException { if (log.isDebugEnabled()) { log.debug("Request received in DAO Layer to get already subscribed users for given list of user names."); @@ -438,13 +430,14 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc StringJoiner joiner = new StringJoiner(",", "SELECT US.USER_NAME AS USER_NAME " + "FROM AP_USER_SUBSCRIPTION US " - + "WHERE US.USER_NAME IN (", ") AND TENANT_ID = ?"); + + "WHERE US.USER_NAME IN (", ") AND AP_APP_RELEASE_ID = ? AND TENANT_ID = ?"); users.stream().map(ignored -> "?").forEach(joiner::add); String query = joiner.toString(); try (PreparedStatement ps = conn.prepareStatement(query)) { for (String username : users) { ps.setObject(index++, username); } + ps.setInt(index++, appReleaseId); ps.setInt(index, tenantId); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { @@ -465,8 +458,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc } } - @Override - public List getSubscribedRoleNames(List roles, int tenantId) + public List getAppSubscribedRoleNames(List roles, int appReleaseId, int tenantId) throws ApplicationManagementDAOException { if (log.isDebugEnabled()) { log.debug("Request received in DAO Layer to get already subscribed role names for given list of roles."); @@ -478,13 +470,14 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc StringJoiner joiner = new StringJoiner(",", "SELECT RS.ROLE_NAME AS ROLE " + "FROM AP_ROLE_SUBSCRIPTION RS " - + "WHERE RS.ROLE_NAME IN (", ") AND TENANT_ID = ?"); + + "WHERE RS.ROLE_NAME IN (", ") AND AP_APP_RELEASE_ID = ? AND TENANT_ID = ?"); roles.stream().map(ignored -> "?").forEach(joiner::add); String query = joiner.toString(); try (PreparedStatement ps = conn.prepareStatement(query)) { for (String roleName : roles) { ps.setObject(index++, roleName); } + ps.setInt(index++, appReleaseId); ps.setInt(index, tenantId); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { @@ -506,7 +499,7 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc } @Override - public List getSubscribedGroupNames(List groups, int tenantId) + public List getAppSubscribedGroupNames(List groups, int appReleaseId, int tenantId) throws ApplicationManagementDAOException { if (log.isDebugEnabled()) { log.debug("Request received in DAO Layer to get already subscribed groups for given list of groups."); @@ -518,13 +511,14 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc StringJoiner joiner = new StringJoiner(",", "SELECT GS.GROUP_NAME AS GROUP_NAME " + "FROM AP_GROUP_SUBSCRIPTION GS " - + "WHERE GS.GROUP_NAME IN (", ") AND TENANT_ID = ?"); + + "WHERE GS.GROUP_NAME IN (", ") AND AP_APP_RELEASE_ID = ? AND TENANT_ID = ?"); groups.stream().map(ignored -> "?").forEach(joiner::add); String query = joiner.toString(); try (PreparedStatement ps = conn.prepareStatement(query)) { for (String groupName : groups) { ps.setObject(index++, groupName); } + ps.setInt(index++, appReleaseId); ps.setInt(index, tenantId); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { @@ -647,20 +641,22 @@ public class GenericSubscriptionDAOImpl extends AbstractDAOImpl implements Subsc } @Override - public List getDeviceSubIdsForOperation(int operationId, int tenantId) + public List getDeviceSubIdsForOperation(int operationId, int deviceId, int tenantId) throws ApplicationManagementDAOException { try { Connection conn = this.getDBConnection(); List deviceSubIds = new ArrayList<>(); - String sql = "SELECT " - + "AP_DEVICE_SUBSCRIPTION_ID " - + "FROM AP_APP_SUB_OP_MAPPING " - + "WHERE " - + "OPERATION_ID = ? AND " - + "TENANT_ID = ?"; + String sql = "SELECT AP_APP_SUB_OP_MAPPING.AP_DEVICE_SUBSCRIPTION_ID " + + "FROM " + + "AP_APP_SUB_OP_MAPPING INNER JOIN AP_DEVICE_SUBSCRIPTION " + + "ON AP_APP_SUB_OP_MAPPING.AP_DEVICE_SUBSCRIPTION_ID = AP_DEVICE_SUBSCRIPTION.ID " + + "WHERE AP_APP_SUB_OP_MAPPING.OPERATION_ID = ? AND " + + "AP_DEVICE_SUBSCRIPTION.DM_DEVICE_ID = ? AND " + + "AP_APP_SUB_OP_MAPPING.TENANT_ID = ?"; try (PreparedStatement stmt = conn.prepareStatement(sql)) { stmt.setInt(1, operationId); - stmt.setInt(2, tenantId); + stmt.setInt(2, deviceId); + stmt.setInt(3, tenantId); try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) { deviceSubIds.add(rs.getInt("AP_DEVICE_SUBSCRIPTION_ID")); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/SQLServerSubscriptionDAOImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/SQLServerSubscriptionDAOImpl.java index 2c725dde077..26a498af1b5 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/SQLServerSubscriptionDAOImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/dao/impl/subscription/SQLServerSubscriptionDAOImpl.java @@ -159,58 +159,4 @@ public class SQLServerSubscriptionDAOImpl extends GenericSubscriptionDAOImpl { throw new ApplicationManagementDAOException(msg, e); } } - - @Override - public List addDeviceSubscription(String subscribedBy, List deviceIds, - String subscribedFrom, String installStatus, int releaseId, int tenantId) - throws ApplicationManagementDAOException { - String sql = "INSERT INTO " - + "AP_DEVICE_SUBSCRIPTION(" - + "SUBSCRIBED_BY, " - + "SUBSCRIBED_TIMESTAMP, " - + "ACTION_TRIGGERED_FROM, " - + "STATUS, " - + "DM_DEVICE_ID, " - + "AP_APP_RELEASE_ID," - + "TENANT_ID) " - + "VALUES (?, ?, ?, ?, ?, ?, ?)"; - try { - Connection conn = this.getDBConnection(); - try (PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { - Calendar calendar = Calendar.getInstance(); - Timestamp timestamp = new Timestamp(calendar.getTime().getTime()); - List deviceSubIds = new ArrayList<>(); - for (Integer deviceId : deviceIds) { - stmt.setString(1, subscribedBy); - stmt.setTimestamp(2, timestamp); - stmt.setString(3, subscribedFrom); - stmt.setString(4, installStatus); - stmt.setInt(5, deviceId); - stmt.setInt(6, releaseId); - stmt.setInt(7, tenantId); - if (log.isDebugEnabled()) { - log.debug("Adding a device subscription for device id " + deviceId + " and application " - + "release which has release id" + releaseId); - } - stmt.executeUpdate(); - try (ResultSet rs = stmt.getGeneratedKeys()) { - if (rs.next()) { - deviceSubIds.add(rs.getInt(1)); - } - } - } - return deviceSubIds; - } - } catch (DBConnectionException e) { - String msg = "Error occured while obtaining database connection to add device subscription for application " - + "release which has release Id" + releaseId; - log.error(msg, e); - throw new ApplicationManagementDAOException(msg, e); - } catch (SQLException e) { - String msg = "Error occured when processing SQL to add device subscription for application release which" - + " has release Id " + releaseId; - log.error(msg, e); - throw new ApplicationManagementDAOException(msg, e); - } - } } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java index b7f63a1f791..a937169b837 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/ApplicationManagerImpl.java @@ -3163,7 +3163,7 @@ public class ApplicationManagerImpl implements ApplicationManager { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); try { ConnectionManagerUtil.beginDBTransaction(); - List deviceSubIds = subscriptionDAO.getDeviceSubIdsForOperation(operationId, tenantId); + List deviceSubIds = subscriptionDAO.getDeviceSubIdsForOperation(operationId, deviceId, tenantId); if (deviceSubIds.isEmpty()){ ConnectionManagerUtil.rollbackDBTransaction(); String msg = "Couldn't find device subscription for operation id " + operationId; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java index 9dc7a152db4..51409bef708 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.core/src/main/java/org/wso2/carbon/device/application/mgt/core/impl/SubscriptionManagerImpl.java @@ -38,6 +38,7 @@ import org.wso2.carbon.device.application.mgt.common.SubscriptionType; import org.wso2.carbon.device.application.mgt.common.SubscribingDeviceIdHolder; import org.wso2.carbon.device.application.mgt.common.dto.ApplicationDTO; import org.wso2.carbon.device.application.mgt.common.dto.ApplicationPolicyDTO; +import org.wso2.carbon.device.application.mgt.common.dto.ApplicationReleaseDTO; import org.wso2.carbon.device.application.mgt.common.dto.DeviceSubscriptionDTO; import org.wso2.carbon.device.application.mgt.common.dto.ScheduledSubscriptionDTO; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; @@ -174,7 +175,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } - if (!ApplicationType.WEB_CLIP.toString().equals(applicationDTO.getType())) { + if (!ApplicationType.WEB_CLIP.toString().equals(applicationDTO.getType()) && !SubscriptionType.DEVICE + .toString().equals(subType)) { DeviceType deviceType = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId()); deviceTypeName = deviceType.getName(); //filter devices by device type @@ -316,6 +318,207 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } } + @Override + public void performEntAppSubscription(String applicationUUID, List params, String subType, String action) + throws ApplicationManagementException { + if (log.isDebugEnabled()) { + log.debug("Google Ent app Install operation is received to application which has UUID " + + applicationUUID + " to perform on " + params.size() + " params."); + } + try { + if (params.isEmpty()) { + String msg = "In order to subscribe/unsubscribe application release, you should provide list of " + + "subscribers. But found an empty list of subscribers."; + log.error(msg); + throw new BadRequestException(msg); + } + + ApplicationDTO applicationDTO = getApplicationDTO(applicationUUID); + ApplicationReleaseDTO applicationReleaseDTO = applicationDTO.getApplicationReleaseDTOs().get(0); + //todo need to check application release status if it is not in installable state send forbidden exception + int applicationReleaseId = applicationReleaseDTO.getId(); + if (!ApplicationType.PUBLIC.toString().equals(applicationDTO.getType())) { + String msg = "Application type is not public. Hence you can't perform google ent.install operation on " + + "this application. Application name " + applicationDTO.getName() + " Application Type " + + applicationDTO.getType(); + log.error(msg); + throw new BadRequestException(msg); + } + + List categories = getApplicationCategories(applicationDTO.getId()); + if (!categories.contains("GooglePlaySyncedApp")) { + String msg = "This is not google play store synced application. Hence can't perform enteprise app " + + "installation."; + log.error(msg); + throw new BadRequestException(msg); + } + + DeviceManagementProviderService deviceManagementProviderService = HelperUtil + .getDeviceManagementProviderService(); + + List devices = new ArrayList<>(); + List subscribers = new ArrayList<>(); + List appSubscribingDeviceIds; + List appReSubscribingDeviceIds = new ArrayList<>(); + List deviceIdentifiers = new ArrayList<>(); + + //todo validate users, groups and roles + if (SubscriptionType.DEVICE.toString().equals(subType)) { + DeviceType deviceType = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId()); + for (T param : params) { + DeviceIdentifier deviceIdentifier = (DeviceIdentifier) param; + if (StringUtils.isEmpty(deviceIdentifier.getId()) || StringUtils + .isEmpty(deviceIdentifier.getType())) { + log.warn("Found a device identifier which has either empty identity of the device or empty" + + " device type. Hence ignoring the device identifier. "); + continue; + } + if (!deviceType.getName().equals(deviceIdentifier.getType())) { + log.warn("Found a device identifier which is not matched with the supported device type " + + "of the application release which has UUID " + applicationUUID + " Application " + + "supported device type is " + deviceType.getName() + " and the " + + "identifier of which has a different device type is " + deviceIdentifier.getId()); + continue; + } + deviceIdentifiers.add(deviceIdentifier); + devices.add(deviceManagementProviderService.getDevice(deviceIdentifier, false)); + } + } else if (SubscriptionType.USER.toString().equalsIgnoreCase(subType)) { + for (T param : params) { + String username = (String) param; + subscribers.add(username); + devices.addAll(deviceManagementProviderService.getDevicesOfUser(username)); + } + } else if (SubscriptionType.ROLE.toString().equalsIgnoreCase(subType)) { + for (T param : params) { + String roleName = (String) param; + subscribers.add(roleName); + devices.addAll(deviceManagementProviderService.getAllDevicesOfRole(roleName)); + } + } else if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) { + GroupManagementProviderService groupManagementProviderService = HelperUtil + .getGroupManagementProviderService(); + for (T param : params) { + String groupName = (String) param; + subscribers.add(groupName); + devices.addAll(groupManagementProviderService.getAllDevicesOfGroup(groupName)); + } + } else { + String msg = "Found invalid subscription type " + subType+ " to install application release" ; + log.error(msg); + throw new BadRequestException(msg); + } + + /*If subscription type is not device we need to crete device identifiers object list by referring retrieved + list of devices.*/ + if (!SubscriptionType.DEVICE.toString().equalsIgnoreCase(subType)) { + DeviceType deviceType = APIUtil.getDeviceTypeData(applicationDTO.getDeviceTypeId()); + String deviceTypeName = deviceType.getName(); + //filter devices by device type + devices.removeIf(device -> !deviceTypeName.equals(device.getType())); + devices.forEach(device -> { + DeviceIdentifier deviceIdentifier = new DeviceIdentifier(); + deviceIdentifier.setId(device.getDeviceIdentifier()); + deviceIdentifier.setType(device.getType()); + deviceIdentifiers.add(deviceIdentifier); + }); + } + + //Installing the application + ApplicationPolicyDTO applicationPolicyDTO = new ApplicationPolicyDTO(); + applicationPolicyDTO.setApplicationDTO(applicationDTO); + applicationPolicyDTO.setDeviceIdentifierList(deviceIdentifiers); + applicationPolicyDTO.setAction(action); + installEnrollmentApplications(applicationPolicyDTO); + + appSubscribingDeviceIds = devices.stream().map(Device::getId).collect(Collectors.toList()); + Map deviceSubscriptions = getDeviceSubscriptions(appSubscribingDeviceIds, + applicationReleaseId); + for (Map.Entry deviceSubscription: deviceSubscriptions.entrySet()){ + appReSubscribingDeviceIds.add(deviceSubscription.getKey()); + appSubscribingDeviceIds.remove(deviceSubscription.getKey()); + } + + updateSubscriptionsForEntInstall(applicationReleaseId, appSubscribingDeviceIds, appReSubscribingDeviceIds, + subscribers, subType, action); + } catch (DeviceManagementException e) { + String msg = "Error occurred while getting devices of given users or given roles."; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } catch (GroupManagementException e) { + String msg = "Error occurred while getting devices of given groups"; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } + } + + /** + * This method is responsible to update subscription data for google enterprise install. + * + * @param applicationReleaseId Application release Id + * @param params subscribers. If subscription is performed via user, group or role, params is a list of + * {@link String} + * @param subType Subscription type. i.e USER, GROUP, ROLE or DEVICE + * @param action Performing action. (i.e INSTALL or UNINSTALL) + * @throws ApplicationManagementException if error occurred while getting or updating subscription data. + */ + private void updateSubscriptionsForEntInstall(int applicationReleaseId, List appSubscribingDeviceIds, + List appReSubscribingDeviceIds, List params, String subType, String action) + throws ApplicationManagementException { + int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); + String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); + try { + ConnectionManagerUtil.beginDBTransaction(); + List subscribedEntities = new ArrayList<>(); + if (SubscriptionType.USER.toString().equalsIgnoreCase(subType)) { + subscribedEntities = subscriptionDAO.getAppSubscribedUserNames(params, applicationReleaseId, tenantId); + } else if (SubscriptionType.ROLE.toString().equalsIgnoreCase(subType)) { + subscribedEntities = subscriptionDAO.getAppSubscribedRoleNames(params, applicationReleaseId, tenantId); + } else if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) { + subscribedEntities = subscriptionDAO.getAppSubscribedGroupNames(params, applicationReleaseId, tenantId); + } + + params.removeAll(subscribedEntities); + if (!params.isEmpty()) { + subscriptionDAO.addUserSubscriptions(tenantId, username, params, applicationReleaseId); + } + if (!subscribedEntities.isEmpty()) { + subscriptionDAO + .updateSubscriptions(tenantId, username, subscribedEntities, applicationReleaseId, subType, + action); + } + + if (SubAction.INSTALL.toString().equalsIgnoreCase(action) && !appSubscribingDeviceIds.isEmpty()) { + subscriptionDAO.addDeviceSubscription(username, appSubscribingDeviceIds, subType, + Operation.Status.COMPLETED.toString(), applicationReleaseId, tenantId); + } + if (!appReSubscribingDeviceIds.isEmpty()) { + subscriptionDAO.updateDeviceSubscription(username, appReSubscribingDeviceIds, action, subType, + Operation.Status.COMPLETED.toString(), applicationReleaseId, tenantId); + } + ConnectionManagerUtil.commitDBTransaction(); + } catch (ApplicationManagementDAOException e) { + ConnectionManagerUtil.rollbackDBTransaction(); + String msg = + "Error occurred when adding subscription data for application release ID: " + applicationReleaseId; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } catch (DBConnectionException e) { + String msg = "Error occurred when getting database connection to add new device subscriptions to application."; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } catch (TransactionManagementException e) { + String msg = "SQL Error occurred when adding new device subscription to application release which has ID: " + + applicationReleaseId; + log.error(msg, e); + throw new ApplicationManagementException(msg, e); + } finally { + ConnectionManagerUtil.closeDBConnection(); + } + } + + + /** * THis method is responsible to validate application install or uninstall request. * @@ -327,8 +530,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager { */ private void validateRequest(List params, String subType, String action) throws BadRequestException { if (params.isEmpty()) { - String msg = "In order to install application release, you should provide list of subscribers. " - + "But found an empty list of users."; + String msg = "In order to subscribe/unsubscribe application release, you should provide list of " + + "subscribers. But found an empty list of subscribers."; log.error(msg); throw new BadRequestException(msg); } @@ -375,10 +578,11 @@ public class SubscriptionManagerImpl implements SubscriptionManager { if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet())); deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReInstallableDevices().keySet())); - ignoredDeviceIdentifiers - .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet())); + deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet())); } else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) { deviceIdentifiers.addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstalledDevices().keySet())); + deviceIdentifiers + .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppReUnInstallableDevices().keySet())); ignoredDeviceIdentifiers .addAll(new ArrayList<>(subscribingDeviceIdHolder.getAppInstallableDevices().keySet())); } @@ -408,18 +612,6 @@ public class SubscriptionManagerImpl implements SubscriptionManager { entry.getKey(), action); activityList.add(activity); } - } else if (applicationDTO.getType().equals(ApplicationType.PUBLIC.toString())) { - List categories = getApplicationCategories(applicationDTO.getId()); - if (categories.contains("GooglePlaySyncedApp")) { - ApplicationPolicyDTO applicationPolicyDTO = new ApplicationPolicyDTO(); - applicationPolicyDTO.setApplicationDTO(applicationDTO); - applicationPolicyDTO.setDeviceIdentifierList(deviceIdentifiers); - applicationPolicyDTO.setAction(action); - installEnrollmentApplications(applicationPolicyDTO); - } else { - Activity activity = addAppOperationOnDevices(applicationDTO, deviceIdentifiers, deviceType, action); - activityList.add(activity); - } } else { Activity activity = addAppOperationOnDevices(applicationDTO, deviceIdentifiers, deviceType, action); activityList.add(activity); @@ -445,10 +637,13 @@ public class SubscriptionManagerImpl implements SubscriptionManager { */ private SubscribingDeviceIdHolder getSubscribingDeviceIdHolder(List devices, int appReleaseId) throws ApplicationManagementException { - Map appInstalledDevices = new HashMap<>(); - Map appInstallableDevices = new HashMap<>(); - Map appReInstallableDevices = new HashMap<>(); - Map skippedDevices = new HashMap<>(); + + SubscribingDeviceIdHolder subscribingDeviceIdHolder = new SubscribingDeviceIdHolder(); + subscribingDeviceIdHolder.setAppInstallableDevices(new HashMap<>()); + subscribingDeviceIdHolder.setAppInstalledDevices(new HashMap<>()); + subscribingDeviceIdHolder.setAppReInstallableDevices(new HashMap<>()); + subscribingDeviceIdHolder.setAppReUnInstallableDevices(new HashMap<>()); + subscribingDeviceIdHolder.setSkippedDevices(new HashMap<>()); List deviceIds = devices.stream().map(Device::getId).collect(Collectors.toList()); //get device subscriptions for given device id list. @@ -459,23 +654,20 @@ public class SubscriptionManagerImpl implements SubscriptionManager { if (deviceSubscriptionDTO != null) { if (!deviceSubscriptionDTO.isUnsubscribed() && Operation.Status.COMPLETED.toString() .equals(deviceSubscriptionDTO.getStatus())) { - appInstalledDevices.put(deviceIdentifier, device.getId()); + subscribingDeviceIdHolder.getAppInstalledDevices().put(deviceIdentifier, device.getId()); + } else if (deviceSubscriptionDTO.isUnsubscribed() && !Operation.Status.COMPLETED.toString() + .equals(deviceSubscriptionDTO.getStatus())) { + subscribingDeviceIdHolder.getAppReUnInstallableDevices().put(deviceIdentifier, device.getId()); } else if (Operation.Status.PENDING.toString().equals(deviceSubscriptionDTO.getStatus()) || Operation.Status.IN_PROGRESS.toString().equals(deviceSubscriptionDTO.getStatus())) { - skippedDevices.put(deviceIdentifier, device.getId()); + subscribingDeviceIdHolder.getSkippedDevices().put(deviceIdentifier, device.getId()); } else { - appReInstallableDevices.put(deviceIdentifier, device.getId()); + subscribingDeviceIdHolder.getAppReInstallableDevices().put(deviceIdentifier, device.getId()); } } else { - appInstallableDevices.put(deviceIdentifier, device.getId()); + subscribingDeviceIdHolder.getAppInstallableDevices().put(deviceIdentifier, device.getId()); } } - - SubscribingDeviceIdHolder subscribingDeviceIdHolder = new SubscribingDeviceIdHolder(); - subscribingDeviceIdHolder.setAppInstallableDevices(appInstallableDevices); - subscribingDeviceIdHolder.setAppInstalledDevices(appInstalledDevices); - subscribingDeviceIdHolder.setAppReInstallableDevices(appReInstallableDevices); - subscribingDeviceIdHolder.setSkippedDevices(skippedDevices); return subscribingDeviceIdHolder; } @@ -565,7 +757,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager { try { ConnectionManagerUtil.beginDBTransaction(); if (SubscriptionType.USER.toString().equalsIgnoreCase(subType)) { - List subscribedEntities = subscriptionDAO.getSubscribedUserNames(params, tenantId); + List subscribedEntities = subscriptionDAO + .getAppSubscribedUserNames(params, applicationReleaseId, tenantId); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { params.removeAll(subscribedEntities); subscriptionDAO.addUserSubscriptions(tenantId, username, params, applicationReleaseId); @@ -573,7 +766,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager { subscriptionDAO.updateSubscriptions(tenantId, username, subscribedEntities, applicationReleaseId, subType, action); } else if (SubscriptionType.ROLE.toString().equalsIgnoreCase(subType)) { - List subscribedEntities = subscriptionDAO.getSubscribedRoleNames(params, tenantId); + List subscribedEntities = subscriptionDAO + .getAppSubscribedRoleNames(params, applicationReleaseId, tenantId); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { params.removeAll(subscribedEntities); subscriptionDAO.addRoleSubscriptions(tenantId, username, params, applicationReleaseId); @@ -581,7 +775,8 @@ public class SubscriptionManagerImpl implements SubscriptionManager { subscriptionDAO.updateSubscriptions(tenantId, username, subscribedEntities, applicationReleaseId, subType, action); } else if (SubscriptionType.GROUP.toString().equalsIgnoreCase(subType)) { - List subscribedEntities = subscriptionDAO.getSubscribedGroupNames(params, tenantId); + List subscribedEntities = subscriptionDAO + .getAppSubscribedGroupNames(params, applicationReleaseId, tenantId); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { params.removeAll(subscribedEntities); subscriptionDAO.addGroupSubscriptions(tenantId, username, params, applicationReleaseId); @@ -594,32 +789,31 @@ public class SubscriptionManagerImpl implements SubscriptionManager { int operationId = Integer.parseInt(activity.getActivityId().split("ACTIVITY_")[1]); List subUpdatingDeviceIds = new ArrayList<>(); List subInsertingDeviceIds = new ArrayList<>(); - List deviceSubIds = new ArrayList<>(); if (SubAction.INSTALL.toString().equalsIgnoreCase(action)) { subUpdatingDeviceIds.addAll(getOperationAddedDeviceIds(activity, subscribingDeviceIdHolder.getAppReInstallableDevices())); + subUpdatingDeviceIds.addAll(getOperationAddedDeviceIds(activity, + subscribingDeviceIdHolder.getAppInstalledDevices())); subInsertingDeviceIds.addAll(getOperationAddedDeviceIds(activity, subscribingDeviceIdHolder.getAppInstallableDevices())); - } else if (SubAction.UNINSTALL.toString().equalsIgnoreCase(action)) { subUpdatingDeviceIds.addAll(getOperationAddedDeviceIds(activity, subscribingDeviceIdHolder.getAppInstalledDevices())); } - List subscribingDevices = subscriptionDAO - .addDeviceSubscription(username, subInsertingDeviceIds, subType, + subscriptionDAO.addDeviceSubscription(username, subInsertingDeviceIds, subType, Operation.Status.PENDING.toString(), applicationReleaseId, tenantId); - subscriptionDAO.updateDeviceSubscription(username, subUpdatingDeviceIds, action, subType, - Operation.Status.PENDING.toString(), applicationReleaseId, tenantId); - if (!subUpdatingDeviceIds.isEmpty()) { - deviceSubIds.addAll(subscriptionDAO - .getDeviceSubIds(subUpdatingDeviceIds, applicationReleaseId, tenantId)); + subscriptionDAO.updateDeviceSubscription(username, subUpdatingDeviceIds, action, subType, + Operation.Status.PENDING.toString(), applicationReleaseId, tenantId); + } + subUpdatingDeviceIds.addAll(subInsertingDeviceIds); + if (!subUpdatingDeviceIds.isEmpty()) { + List deviceSubIds = new ArrayList<>( + subscriptionDAO.getDeviceSubIds(subUpdatingDeviceIds, applicationReleaseId, tenantId)); + subscriptionDAO.addOperationMapping(operationId, deviceSubIds, tenantId); } - deviceSubIds.addAll(subscribingDevices); - - subscriptionDAO.addOperationMapping(operationId, deviceSubIds, tenantId); } ConnectionManagerUtil.commitDBTransaction(); } catch (ApplicationManagementDAOException e) { @@ -822,7 +1016,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { String payload = gson.toJson(applicationPolicyDTO); StringRequestEntity requestEntity = new StringRequestEntity(payload, MediaType.APPLICATION_JSON - , Constants.ApplicationInstall.ENCODING);; + , Constants.ApplicationInstall.ENCODING); httpClient = new HttpClient(); request = new PostMethod(requestUrl); request.addRequestHeader(Constants.ApplicationInstall.AUTHORIZATION @@ -869,14 +1063,21 @@ public class SubscriptionManagerImpl implements SubscriptionManager { List deviceSubscriptionDTOS = subscriptionDAO .getDeviceSubscriptions(applicationReleaseId, tenantId); if (deviceSubscriptionDTOS.isEmpty()) { - String msg = "Couldn't found an subscribed devices for application release id: " - + applicationReleaseId; - log.info(msg); + PaginationResult paginationResult = new PaginationResult(); + paginationResult.setData(new ArrayList<>()); + paginationResult.setRecordsFiltered(0); + paginationResult.setRecordsTotal(0); + return paginationResult; } List deviceIdList = new ArrayList<>(); - for (DeviceSubscriptionDTO deviceIds : deviceSubscriptionDTOS) { - deviceIdList.add(deviceIds.getDeviceId()); - } + deviceSubscriptionDTOS.forEach(deviceSubscriptionDTO -> { + if ((!deviceSubscriptionDTO.isUnsubscribed() && Operation.Status.COMPLETED.toString() + .equalsIgnoreCase(deviceSubscriptionDTO.getStatus())) || (deviceSubscriptionDTO.isUnsubscribed() + && !Operation.Status.COMPLETED.toString() + .equalsIgnoreCase(deviceSubscriptionDTO.getStatus()))) { + deviceIdList.add(deviceSubscriptionDTO.getDeviceId()); + } + }); if (deviceIdList.isEmpty()){ PaginationResult paginationResult = new PaginationResult(); @@ -919,7 +1120,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager { } @Override - public PaginationResult getAppInstalledCategories(int offsetValue, int limitValue, String appUUID, String subType) + public PaginationResult getAppInstalledSubscribers(int offsetValue, int limitValue, String appUUID, String subType) throws ApplicationManagementException { int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(true); @@ -988,18 +1189,14 @@ public class SubscriptionManagerImpl implements SubscriptionManager { List deviceSubscriptionDTOS = subscriptionDAO .getDeviceSubscriptions(applicationReleaseId, tenantId); if (deviceSubscriptionDTOS.isEmpty()) { - String msg = "Couldn't found an subscribed devices for application release id: " + applicationReleaseId; - log.info(msg); - } - List deviceIdList = deviceSubscriptionDTOS.stream().map(DeviceSubscriptionDTO::getDeviceId) - .collect(Collectors.toList()); - if (deviceIdList.isEmpty()) { PaginationResult paginationResult = new PaginationResult(); - paginationResult.setData(deviceIdList); + paginationResult.setData(new ArrayList<>()); paginationResult.setRecordsFiltered(0); paginationResult.setRecordsTotal(0); return paginationResult; } + List deviceIdList = deviceSubscriptionDTOS.stream().map(DeviceSubscriptionDTO::getDeviceId) + .collect(Collectors.toList()); try { //pass the device id list to device manager service method PaginationResult paginationResult = deviceManagementProviderService diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java index 5e0e7652391..ae864cb52e8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.api/src/main/java/org/wso2/carbon/device/application/mgt/publisher/api/services/impl/ApplicationManagementPublisherAPIImpl.java @@ -954,7 +954,7 @@ public class ApplicationManagementPublisherAPIImpl implements ApplicationManagem log.error(msg); throw new BadRequestException(msg); } - applicationArtifact.setInstallerName(installerFileName); + applicationArtifact.setInstallerName(installerFileName.replaceAll("\\s", "")); applicationArtifact.setInstallerStream(installerStream); } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java index 95edf144200..897154efc3e 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/SubscriptionManagementAPI.java @@ -185,6 +185,106 @@ public interface SubscriptionManagementAPI { @QueryParam("timestamp") String timestamp ); + @POST + @Path("/{uuid}/devices/ent-app-install/{action}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Install an application for devices via google enterprise app installing service", + notes = "This will install an application to a given list of devices", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:app:subscription:install") + }) + } + ) + @ApiResponses( + value = { + + }) + Response performEntAppSubscriptionOnDevices( + @ApiParam( + name = "UUID", + value = "The application UUID", + required = true + ) + @PathParam("uuid") String uuid, + @ApiParam( + name = "action", + value = "Performing action.", + required = true + ) + @PathParam("action") String action, + @ApiParam( + name = "installationDetails", + value = "The list of device identifiers", + required = true + ) + @Valid List deviceIdentifiers, + @ApiParam( + name = "timestamp", + value = "Timestamp of scheduled ent. install operation" + ) + @QueryParam("timestamp") String timestamp + ); + + @POST + @Path("/{uuid}/{subType}/ent-app-install/{action}") + @Produces(MediaType.APPLICATION_JSON) + @Consumes(MediaType.APPLICATION_JSON) + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + produces = MediaType.APPLICATION_JSON, + httpMethod = "POST", + value = "Install an application for subscription type via google enterprise install.", + notes = "This will install an application to a given subscription type and this is bulk app installation.", + tags = "Subscription Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = SCOPE, value = "perm:app:subscription:install") + }) + } + ) + @ApiResponses( + value = { + + }) + Response performBulkEntAppSubscription( + @ApiParam( + name = "uuid", + value = "The application release UUID", + required = true + ) + @PathParam("uuid") String uuid, + @ApiParam( + name = "subType", + value = "Subscription type of the app installing operation.", + required = true + ) + @PathParam("subType") String subType, + @ApiParam( + name = "action", + value = "Performing action.", + required = true + ) + @PathParam("action") String action, + @ApiParam( + name = "subscribers", + value = "Subscriber list of the application release.", + required = true + ) + @Valid List subscribers, + @ApiParam( + name = "timestamp", + value = "Timestamp of scheduled ent app install operation" + ) + @QueryParam("timestamp") String timestamp + ); + @GET @Path("/{uuid}/devices") @Produces(MediaType.APPLICATION_JSON) diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/admin/SubscriptionManagementAdminAPI.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/admin/SubscriptionManagementAdminAPI.java index 904e6acdd6c..7fb357e4fe8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/admin/SubscriptionManagementAdminAPI.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/admin/SubscriptionManagementAdminAPI.java @@ -92,7 +92,7 @@ public interface SubscriptionManagementAdminAPI { tags = "Subscription Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = SCOPE, value = "perm:app:subscription:view") + @ExtensionProperty(name = SCOPE, value = "perm:admin:app:subscription:view") }) } ) diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java index 62af127d182..ba83ba655fa 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.store.api/src/main/java/org/wso2/carbon/device/application/mgt/store/api/services/impl/SubscriptionManagementAPIImpl.java @@ -89,13 +89,13 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ log.error(msg, e); return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); } catch (BadRequestException e) { - String msg = "Found invalid payload for installing application which has UUID: " + uuid - + ". Hence verify the payload"; + String msg = "Found invalid payload for installing application which has UUID: " + uuid + ". Hence verify " + + "the payload"; log.error(msg, e); return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); } catch (ForbiddenException e) { - String msg = "Application release is not in the installable state. Hence you are not permitted to install " - + "the application."; + String msg = "Application release is not in the installable state. Hence you are not permitted to perform " + + "the action on the application."; log.error(msg, e); return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); } catch (ApplicationManagementException e) { @@ -106,7 +106,6 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ } } - @Override @POST @Path("/{uuid}/{subType}/{action}") @@ -132,13 +131,13 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ log.error(msg, e); return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); } catch (BadRequestException e) { - String msg = "Found invalid payload for installing application which has UUID: " + uuid - + ". Hence verify the payload"; + String msg = "Found invalid payload for installing application which has UUID: " + uuid + ". Hence verify " + + "the payload"; log.error(msg, e); return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); } catch (ForbiddenException e) { - String msg = "Application release is not in the installable state. Hence you are not permitted to install " - + "the application."; + String msg = "Application release is not in the installable state. Hence you are not permitted to perform " + + "the action on the application."; log.error(msg, e); return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); } catch (ApplicationManagementException e) { @@ -149,6 +148,93 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ } } + @Override + @POST + @Path("/{uuid}/devices/ent-app-install/{action}") + public Response performEntAppSubscriptionOnDevices( + @PathParam("uuid") String uuid, + @PathParam("action") String action, + @Valid List deviceIdentifiers, + @QueryParam("timestamp") String timestamp) { + try { + if (StringUtils.isEmpty(timestamp)) { + SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); + subscriptionManager + .performEntAppSubscription(uuid, deviceIdentifiers, SubscriptionType.DEVICE.toString(), action); + String msg = "Application release which has UUID " + uuid + " is installed to given valid device " + + "identifiers."; + return Response.status(Response.Status.OK).entity(msg).build(); + } else { + return scheduleApplicationOperationTask(uuid, deviceIdentifiers, SubscriptionType.DEVICE, + SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp); + } + } catch (NotFoundException e) { + String msg = "Couldn't found an application release for UUI: " + uuid + " to perform ent app installation " + + "on subscriber's devices"; + log.error(msg, e); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } catch (BadRequestException e) { + String msg = "Found invalid payload when performing ent app installation on application which has UUID: " + + uuid + ". Hence verify the payload of the request."; + log.error(msg, e); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } catch (ForbiddenException e) { + String msg = "Application release is not in the installable state. Hence you are not permitted to install " + + "the application."; + log.error(msg, e); + return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); + } catch (ApplicationManagementException e) { + String msg = + "Error occurred while performing ent app installation on the application release which has UUID: " + + uuid + " for devices"; + log.error(msg, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } + } + + @Override + @POST + @Path("/{uuid}/{subType}/ent-app-install/{action}") + public Response performBulkEntAppSubscription( + @PathParam("uuid") String uuid, + @PathParam("subType") String subType, + @PathParam("action") String action, + @Valid List subscribers, + @QueryParam("timestamp") String timestamp) { + try { + if (StringUtils.isEmpty(timestamp)) { + SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); + subscriptionManager.performEntAppSubscription(uuid, subscribers, subType, action); + String msg = "Application release which has UUID " + uuid + " is installed to subscriber's valid device" + + " identifiers."; + return Response.status(Response.Status.OK).entity(msg).build(); + } else { + return scheduleApplicationOperationTask(uuid, subscribers, + SubscriptionType.valueOf(subType.toUpperCase()), + SubAction.valueOf(SubAction.INSTALL.toString().toUpperCase()), timestamp); + } + } catch (NotFoundException e) { + String msg = "Couldn't found an application release for UUID: " + uuid + ". Hence, verify the payload"; + log.error(msg, e); + return Response.status(Response.Status.NOT_FOUND).entity(msg).build(); + } catch (BadRequestException e) { + String msg = "Found invalid payload when performing ent app installation on application which has UUID: " + + uuid + ". Hence verify the payload of the request."; + log.error(msg, e); + return Response.status(Response.Status.BAD_REQUEST).entity(msg).build(); + } catch (ForbiddenException e) { + String msg = "Application release is not in the installable state. Hence you are not permitted to install " + + "the application."; + log.error(msg, e); + return Response.status(Response.Status.FORBIDDEN).entity(msg).build(); + } catch (ApplicationManagementException e) { + String msg = "Error occurred while performing ent app installation on the application release which has " + + "UUID: " + uuid + " for user devices"; + log.error(msg, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } + } + /** * Schedule the application subscription for the given timestamp * @@ -183,24 +269,20 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ @Consumes("application/json") @Produces("application/json") @Path("/{uuid}/devices") - public Response getAppInstalledDevices(@PathParam("uuid") String uuid, - @DefaultValue("0") - @QueryParam("offset") int offset, - @DefaultValue("5") - @QueryParam("limit") int limit, - @QueryParam("status") String status) { - + public Response getAppInstalledDevices( + @PathParam("uuid") String uuid, + @DefaultValue("0") + @QueryParam("offset") int offset, + @DefaultValue("5") + @QueryParam("limit") int limit, + @QueryParam("status") String status) { try { SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); - PaginationResult subscribedDeviceDetails = subscriptionManager .getAppInstalledDevices(offset, limit, uuid, status); - DeviceList devices = new DeviceList(); - devices.setList((List) subscribedDeviceDetails.getData()); devices.setCount(subscribedDeviceDetails.getRecordsTotal()); - return Response.status(Response.Status.OK).entity(devices).build(); } catch (NotFoundException e) { String msg = "Application with application release UUID: " + uuid + " is not found"; @@ -228,18 +310,18 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{ @Consumes("application/json") @Produces("application/json") @Path("/{uuid}/{subType}") - public Response getAppInstalledCategories(@PathParam("uuid") String uuid, - @PathParam("subType") String subType, - @DefaultValue("0") - @QueryParam("offset") int offset, - @DefaultValue("5") - @QueryParam("limit") int limit) { - + public Response getAppInstalledCategories( + @PathParam("uuid") String uuid, + @PathParam("subType") String subType, + @DefaultValue("0") + @QueryParam("offset") int offset, + @DefaultValue("5") + @QueryParam("limit") int limit) { try { SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); PaginationResult subscribedCategoryDetails = subscriptionManager - .getAppInstalledCategories(offset, limit, uuid, subType); + .getAppInstalledSubscribers(offset, limit, uuid, subType); if (SubscriptionType.USER.toString().equalsIgnoreCase(subType)) { BasicUserInfoList users = new BasicUserInfoList(); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js index 42af8271b76..19a7b3f1b65 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/DeviceTypes/DeviceTypesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {message, notification, Typography, Icon, Card, Col, Row} from "antd"; +import {Card, Col, Icon, message, notification, Row, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js index 38e5444aebb..d129d6a6013 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/DevicesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, Modal, Select} from "antd"; +import {Icon, message, Modal, notification, Select, Table, Tag, Tooltip, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js index 604d540e001..61a8635564b 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/ReportDevicesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd"; +import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js new file mode 100644 index 00000000000..d828d20a88c --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/AddGroup.js @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import {Button, Form, Input, message, Modal, notification, Typography} from "antd"; +import axios from "axios"; +import {withConfigContext} from "../../context/ConfigContext"; + +const {Text} = Typography; +let config = null; + +class AddGroup extends React.Component { + + constructor(props) { + super(props); + config = this.props.context; + this.state = { + addModalVisible: false, + name:'', + description:'', + } + } + + onConfirmAdGroup = () => { + const config = this.props.context; + + const groupData = { + name: this.state.name, + description: this.state.description + } + + //send request to the invoker + axios.post( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/groups", + groupData, + {headers: {'Content-Type': 'application/json'}} + ).then(res => { + if (res.status === 201) { + this.props.fetchGroups(); + notification["success"]({ + message: "Done", + duration: 4, + description: + "Successfully added the group.", + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to add group.", + }); + } + }); + }; + + openAddModal = () => { + this.setState({ + addModalVisible:true + }) + }; + + handleAddOk = e => { + this.props.form.validateFields(err => { + if (!err) { + this.onConfirmAdGroup(); + this.setState({ + addModalVisible: false, + }); + } + }); + }; + + handleAddCancel = e => { + this.setState({ + addModalVisible: false, + }); + }; + + onChangeName = (e) => { + this.setState({ + name:e.currentTarget.value + }) + }; + + onChangeDescription = (e) => { + this.setState({ + description:e.currentTarget.value + }) + }; + + render() { + const { getFieldDecorator } = this.props.form; + return( +
+
+ +
+
+ + Cancel + , + , + ]} + > +
+

Create new device group on IoT Server.

+
+ + {getFieldDecorator('name', { + rules: [ + { + required: true, + message: 'Please input group name', + }, + ], + })()} + + + {getFieldDecorator('description', { + rules: [ + { + required: true, + message: 'Please input group description', + }, + ], + })()} + +
+
+
+
+
+ ) + } +} + +export default withConfigContext(Form.create({name: 'add-group'})(AddGroup)); \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js new file mode 100644 index 00000000000..b82489a14ae --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupActions.js @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved. + * + * Entgra (pvt) Ltd. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from "react"; +import { + Button, + Divider, + Form, + Icon, + Input, + message, + Modal, + notification, + Popconfirm, + Select, + Tooltip, + Typography +} from "antd"; +import axios from "axios"; +import {withConfigContext} from "../../context/ConfigContext"; + +const {Text} = Typography; +let config = null; + +class GroupActions extends React.Component { + + constructor(props) { + super(props); + config = this.props.context; + this.state = { + editModalVisible: false, + shareModalVisible: false, + name:this.props.data.name, + description:this.props.data.description, + groupDataObject:{}, + rolesData:[], + shareRolesData:[] + } + } + + onConfirmDeleteGroup = () => { + const config = this.props.context; + + //send request to the invoker + axios.delete( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/groups/id/" + this.props.data.id, + {headers: {'Content-Type': 'application/json'}} + + ).then(res => { + if (res.status === 200) { + this.props.fetchGroups(); + notification["success"]({ + message: "Done", + duration: 4, + description: + "Successfully deleted the group.", + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to delete group.", + }); + } + }); + }; + + onConfirmUpdateGroup = (data) => { + const config = this.props.context; + + //send request to the invoker + axios.put( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/groups/id/" + this.props.data.id, + data + ).then(res => { + if (res.status === 200) { + this.props.fetchGroups(); + notification["success"]({ + message: "Done", + duration: 4, + description: + "Successfully updated the group.", + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to update group.", + }); + } + }); + }; + + fetchUserRoles = (params = {}) => { + const config = this.props.context; + + const apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/roles"; + + //send request to the invokerss + axios.get(apiUrl).then(res => { + if (res.status === 200) { + this.setState({ + rolesData: res.data.data.roles, + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description:"Error occurred while trying to load roles.", + }); + } + }); + }; + + onConfirmShareGroup = (data) => { + const config = this.props.context; + + //send request to the invoker + axios.post( + window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/groups/id/" + this.props.data.id + "/share", + data + ).then(res => { + if (res.status === 200) { + this.props.fetchGroups(); + notification["success"]({ + message: "Done", + duration: 4, + description: + "Successfully shared the group.", + }); + } + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popop with error + message.error('You are not logged in'); + window.location.href = window.location.origin + '/entgra/login'; + } else { + notification["error"]({ + message: "There was a problem", + duration: 0, + description: + "Error occurred while trying to share group.", + }); + } + }); + } + + openEditModal = () => { + this.setState({ + editModalVisible:true + }) + }; + + openShareModal = () => { + this.fetchUserRoles(); + this.setState({ + shareModalVisible:true + }) + } + + handleEditOk = e => { + this.state.groupDataObject = { + name:this.state.name, + description:this.state.description, + id:this.props.data.id, + owner:this.props.data.owner, + groupProperties:this.props.data.groupProperties + }; + this.props.form.validateFields(err => { + if (!err) { + this.onConfirmUpdateGroup(this.state.groupDataObject); + this.setState({ + editModalVisible: false, + }); + } + }); + }; + + handleEditCancel = e => { + this.setState({ + editModalVisible: false, + }); + }; + + handleShareOk = e => { + this.setState({ + shareModalVisible: false, + }); + this.onConfirmShareGroup(this.state.shareRolesData); + }; + + handleShareCancel = e => { + this.setState({ + shareModalVisible: false, + }); + }; + + onChangeName = (e) => { + this.setState({ + name:e.currentTarget.value + }) + }; + + onChangeDescription = (e) => { + this.setState({ + description:e.currentTarget.value + }) + }; + + handleRolesDropdownChange = (value) => { + this.setState({ + shareRolesData:value + }) + }; + + render() { + const isAdminGroups = this.props.data.id==1 || this.props.data.id==2; + const { Option } = Select; + const { getFieldDecorator } = this.props.form; + let item = this.state.rolesData.map((data) => + + {data} + ); + return( +
+
+ + + + + + + + + + + + + +
+
+ + Cancel + , + , + ]} + > +
+

Enter new name and description for the group

+
+ + {getFieldDecorator( + 'name', + { + initialValue: this.props.data.name, + rules: [ + { + required: true, + message: 'Please input group name', + }, + ], + })()} + + + {getFieldDecorator( + 'description', + { + initialValue: this.props.data.description, + rules: [ + { + required: true, + message: 'Please input group description', + }, + ], + })()} + +
+
+
+
+
+ + New Role + , + , + , + ]} + > +

Select user role(s)

+ , +
+
+
+ ) + } +} + +export default withConfigContext(Form.create({name: 'group-actions'})(GroupActions)); \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js index 1fdaedec499..cf782973b37 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Groups/GroupsTable.js @@ -18,40 +18,19 @@ import React from "react"; import axios from "axios"; -import { message, notification, Table, Typography} from "antd"; +import {message, notification, Table, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; +import GroupActions from "./GroupActions"; +import AddGroup from "./AddGroup"; const {Text} = Typography; let config = null; let apiUrl; -const columns = [ - { - title: 'Group Name', - dataIndex: 'name', - width: 100, - }, - { - title: 'Owner', - dataIndex: 'owner', - key: 'owner', - // render: enrolmentInfo => enrolmentInfo.owner - // todo add filtering options - }, - { - title: 'Description', - dataIndex: 'description', - key: 'description', - // render: enrolmentInfo => enrolmentInfo.ownership - // todo add filtering options - } -]; - const getTimeAgo = (time) => { const timeAgo = new TimeAgo('en-US'); return timeAgo.format(time); @@ -70,6 +49,38 @@ class GroupsTable extends React.Component { }; } + columns = [ + { + title: 'Group Name', + dataIndex: 'name', + width: 100, + }, + { + title: 'Owner', + dataIndex: 'owner', + key: 'owner', + // render: enrolmentInfo => enrolmentInfo.owner + // todo add filtering options + }, + { + title: 'Description', + dataIndex: 'description', + key: 'description', + // render: enrolmentInfo => enrolmentInfo.ownership + // todo add filtering options + }, + { + title: 'Action', + dataIndex: 'id', + key: 'action', + render: (id, row) => ( + + + + ), + }, + ]; + rowSelection = { onChange: (selectedRowKeys, selectedRows) => { this.setState({ @@ -130,6 +141,8 @@ class GroupsTable extends React.Component { }); }; + + handleTableChange = (pagination, filters, sorter) => { const pager = {...this.state.pagination}; pager.current = pagination.current; @@ -148,23 +161,29 @@ class GroupsTable extends React.Component { render() { const {data, pagination, loading, selectedRows} = this.state; + return (
- (record.id)} - dataSource={data} - pagination={{ - ...pagination, - size: "small", - // position: "top", - showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups` - // showQuickJumper: true - }} - loading={loading} - onChange={this.handleTableChange} - rowSelection={this.rowSelection} - /> +
+ +
+
+
(record.id)} + dataSource={data} + pagination={{ + ...pagination, + size: "small", + // position: "top", + showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} groups` + // showQuickJumper: true + }} + loading={loading} + onChange={this.handleTableChange} + rowSelection={this.rowSelection} + /> + ); } diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js index 1080cddddbf..3d85bbe344c 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Roles/RolesTable.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Card, Col, Row, Select} from "antd"; +import {Card, Col, Icon, message, notification, Row, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; @@ -124,7 +123,6 @@ class RolesTable extends React.Component { }; render() { - const {data, pagination, loading, selectedRows} = this.state; const { Meta } = Card; const itemCard = data.map((data) => diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js index 75529becc12..eca727ac9a9 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersDevices.js @@ -18,9 +18,8 @@ import React from "react"; import axios from "axios"; -import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider} from "antd"; +import {Icon, message, notification, Table, Tag, Tooltip, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js index a1651111ffa..6684329e674 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Users/UsersTable.js @@ -18,13 +18,11 @@ import React from "react"; import axios from "axios"; -import {message, notification, Table, Typography, Panel, Collapse, Button, List, Modal, Icon, Tabs} from "antd"; +import {Button, Collapse, Icon, List, message, Modal, notification, Table, Tabs, Typography} from "antd"; import TimeAgo from 'javascript-time-ago' - // Load locale-specific relative date/time formatting rules. import en from 'javascript-time-ago/locale/en' import {withConfigContext} from "../../context/ConfigContext"; -import DeviceTable from "../Devices/DevicesTable"; import UsersDevices from "./UsersDevices"; const {Text} = Typography; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js index b96f869872b..b259c3256ac 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Groups/Groups.js @@ -25,6 +25,7 @@ import { } from "antd"; import {Link} from "react-router-dom"; import GroupsTable from "../../../components/Groups/GroupsTable"; +import AddGroup from "../../../components/Groups/AddGroup"; const {Paragraph} = Typography; diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js index 7c32b7a0a23..66286a20143 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Policies/Policies.js @@ -55,7 +55,7 @@ class Policies extends React.Component {
- +
); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Login.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Login.js index 19bbf40a27e..3ac1408ba0b 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Login.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Login.js @@ -157,7 +157,7 @@ class NormalLoginForm extends React.Component { )}
Forgot password - diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java index 3531154a6ea..f80d3326fe2 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/DeviceManagementService.java @@ -1713,16 +1713,16 @@ public interface DeviceManagementService { @Valid OperationRequest operationRequest); @GET - @Path("/status/count/{tenantDomain}/{type}/{status}") + @Path("/type/{type}/status/{status}/count") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", value = "Get Device Count with status", - notes = "Get specified device count with status.", + notes = "Get specified device count with type and status.", tags = "Device Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details") + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view") }) } ) @@ -1730,7 +1730,7 @@ public interface DeviceManagementService { value = { @ApiResponse( code = 200, - message = "OK. \n Successfully fetched the details of the device.", + message = "OK. \n Successfully fetched the count of matching devices.", response = int.class, responseHeaders = { @ResponseHeader( @@ -1764,13 +1764,6 @@ public interface DeviceManagementService { response = ErrorResponse.class) }) Response getDeviceCountByStatus( - @ApiParam( - name = "tenantDomain", - value = "The tenant doamin.", - required = true) - @PathParam("tenantDomain") - @Size(max = 45) - String tenantDomain, @ApiParam( name = "type", value = "The device type name, such as ios, android, windows or fire-alarm.", @@ -1788,17 +1781,16 @@ public interface DeviceManagementService { @GET - @Path("/status/ids/{tenantDomain}/{type}/{status}") + @Path("/type/{type}/status/{status}/ids") @ApiOperation( produces = MediaType.APPLICATION_JSON, httpMethod = "GET", - value = "Getting Details of a Device", - notes = "Get the details of a device by specifying the device type and device identifier and optionally " + - "the owner.", + value = "Getting ids of devices with specified type and status", + notes = "Get the ids of a device by specifying the device type and status.", tags = "Device Management", extensions = { @Extension(properties = { - @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:details") + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view") }) } ) @@ -1840,13 +1832,6 @@ public interface DeviceManagementService { response = ErrorResponse.class) }) Response getDeviceIdentifiersByStatus( - @ApiParam( - name = "tenantDomain", - value = "The tenant domain.", - required = true) - @PathParam("tenantDomain") - @Size(max = 45) - String tenantDomain, @ApiParam( name = "type", value = "The device type name, such as ios, android, windows or fire-alarm.", @@ -1863,7 +1848,7 @@ public interface DeviceManagementService { String status); @PUT - @Path("/status/update/{tenantDomain}/{type}/{status}") + @Path("/type/{type}/status/{status}") @ApiOperation( produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON, @@ -1915,8 +1900,6 @@ public interface DeviceManagementService { response = ErrorResponse.class) }) Response bulkUpdateDeviceStatus( - @ApiParam(name = "tenantDomain", value = "The tenant domain.", required = true) - @PathParam("tenantDomain") String tenantDomain, @ApiParam(name = "type", value = "The device type, such as ios, android or windows.", required = true) @PathParam("type") String type, @ApiParam(name = "status", value = "The device type, such as ios, android or windows.", required = true) diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java index 0e5673dd299..9ea2e4b2bba 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/GroupManagementService.java @@ -458,8 +458,10 @@ public interface GroupManagementService { @Path("/id/{groupId}") @DELETE + @Consumes(MediaType.WILDCARD) @ApiOperation( produces = MediaType.APPLICATION_JSON, + consumes = MediaType.WILDCARD, httpMethod = HTTPConstants.HEADER_DELETE, value = "Deleting a Group", notes = "If you wish to remove an existing group, that can be done by updating the group using this API.", diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java index 1ac3169189a..29d8a2cb437 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/DeviceManagementAdminService.java @@ -45,9 +45,11 @@ import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import io.swagger.annotations.ResponseHeader; +import org.apache.axis2.transport.http.HTTPConstants; import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scopes; import org.wso2.carbon.device.mgt.common.Device; +import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.util.Constants; @@ -198,6 +200,59 @@ public interface DeviceManagementAdminService { defaultValue = "5") @QueryParam("limit") int limit); + @Path("/count") + @GET + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = HTTPConstants.HEADER_GET, + value = "Get the count of devices.", + notes = "Returns count of all devices enrolled with the system.", + tags = "Device Management Administrative Service", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin:devices:view") + }) + } + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device count.", + response = Integer.class, + responseHeaders = { + @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 = 304, + message = "Not Modified. \n Empty body because the client has already the latest version of " + + "the requested resource."), + @ApiResponse( + code = 404, + message = "No groups found.", + response = ErrorResponse.class), + @ApiResponse( + code = 406, + message = "Not Acceptable.\n The requested media type is not supported."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n Server error occurred while fetching the device count.", + response = ErrorResponse.class) + }) + Response getDeviceCount(@ApiParam( + name = "status", + value = "status of group of which count should be retrieved") + @QueryParam("status") + String status); + + @PUT @Path("/device-owner") @ApiOperation( diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/GroupManagementAdminService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/GroupManagementAdminService.java index c42739f2960..304a00d380c 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/GroupManagementAdminService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/admin/GroupManagementAdminService.java @@ -33,10 +33,12 @@ import io.swagger.annotations.ResponseHeader; import org.apache.axis2.transport.http.HTTPConstants; import org.wso2.carbon.apimgt.annotations.api.Scope; import org.wso2.carbon.apimgt.annotations.api.Scopes; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; import org.wso2.carbon.device.mgt.jaxrs.util.Constants; +import javax.validation.Valid; import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -75,6 +77,12 @@ import javax.ws.rs.core.Response; description = "", key = "perm:admin-groups:count", permissions = {"/device-mgt/admin/groups/view"} + ), + @Scope( + name = "Add groups", + description = "", + key = "perm:admin-groups:add", + permissions = {"/device-mgt/admin/groups/add"} ) } ) @@ -166,7 +174,7 @@ public interface GroupManagementAdminService { ) @ApiResponses(value = { @ApiResponse(code = 200, message = "OK. \n Successfully fetched the device group count.", - response = DeviceGroupList.class, + response = Integer.class, responseHeaders = { @ResponseHeader( name = "Content-Type", @@ -202,4 +210,71 @@ public interface GroupManagementAdminService { @QueryParam("status") String status); + @POST + @ApiOperation( + consumes = MediaType.APPLICATION_JSON, + httpMethod = HTTPConstants.HEADER_POST, + value = "Adding a New Device Group", + notes = "Add device group with the current user as the owner.", + tags = "Device Group Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:admin-groups:add") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 201, + message = "Created. \n Device group has successfully been created", + responseHeaders = { + @ResponseHeader( + name = "Content-Location", + description = "The URL of the added group."), + @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 Source can be retrieved from the URL specified at 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 = 401, + message = "Unauthorized. \n Current logged in user is not authorized to add device groups.", + response = ErrorResponse.class), + @ApiResponse( + code = 415, + message = "Unsupported media type. \n The entity of the request was in a not supported " + + "format."), + @ApiResponse( + code = 500, + message = "Internal Server Error. \n " + + "Server error occurred while adding a new device group.", + response = ErrorResponse.class) + }) + Response createGroup(@ApiParam( + name = "group", + value = "Define the group object with data.", + required = true) + @Valid DeviceGroup group); + } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java index ef89eb6ef84..c058b1ac699 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/DeviceManagementServiceImpl.java @@ -973,66 +973,48 @@ public class DeviceManagementServiceImpl implements DeviceManagementService { @GET @Override - @Path("/status/count/{tenantDomain}/{type}/{status}") - public Response getDeviceCountByStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type, @PathParam("status") String status) { + @Path("/type/{type}/status/{status}/count") + public Response getDeviceCountByStatus(@PathParam("type") String type, @PathParam("status") String status) { int deviceCount; try { - int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain); - deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCountOfTypeByStatus(tenantId, type, status); + deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCountOfTypeByStatus(type, status); return Response.status(Response.Status.OK).entity(deviceCount).build(); } catch (DeviceManagementException e) { String errorMessage = "Error while retrieving device count."; log.error(errorMessage, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); - } catch (UserStoreException e) { - String errorMessage = "Error resolving tenant Domain"; - log.error(errorMessage, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( - new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); } } @GET @Override - @Path("/status/ids/{tenantDomain}/{type}/{status}") - public Response getDeviceIdentifiersByStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type, @PathParam("status") String status) { + @Path("/type/{type}/status/{status}/ids") + public Response getDeviceIdentifiersByStatus(@PathParam("type") String type, @PathParam("status") String status) { List deviceIds; try { - int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain); - deviceIds = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceIdentifiersByStatus(tenantId, type, status); + deviceIds = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceIdentifiersByStatus(type, status); return Response.status(Response.Status.OK).entity(deviceIds.toArray(new String[0])).build(); } catch (DeviceManagementException e) { String errorMessage = "Error while obtaining list of devices"; log.error(errorMessage, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); - } catch (UserStoreException e) { - String errorMessage = "Error resolving tenant Domain"; - log.error(errorMessage, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( - new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); } } @PUT @Override - @Path("/status/update/{tenantDomain}/{type}/{status}") - public Response bulkUpdateDeviceStatus(@PathParam("tenantDomain") String tenantDomain, @PathParam("type") String type, - @PathParam("status") String status, @Valid List deviceList) { + @Path("/type/{type}/status/{status}") + public Response bulkUpdateDeviceStatus(@PathParam("type") String type, @PathParam("status") String status, + @Valid List deviceList) { try { - int tenantId = DeviceMgtAPIUtils.getRealmService().getTenantManager().getTenantId(tenantDomain); - DeviceMgtAPIUtils.getDeviceManagementService().bulkUpdateDeviceStatus(tenantId, type, deviceList, status); + DeviceMgtAPIUtils.getDeviceManagementService().bulkUpdateDeviceStatus(type, deviceList, status); } catch (DeviceManagementException e) { String errorMessage = "Error while updating device status in bulk."; log.error(errorMessage, e); return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); - } catch (UserStoreException e) { - String errorMessage = "Error resolving tenant Domain"; - log.error(errorMessage, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity( - new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build(); } return Response.status(Response.Status.OK).build(); } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java index 4b30cb4112b..9533c43a42a 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/DeviceManagementAdminServiceImpl.java @@ -40,10 +40,10 @@ import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.CarbonContext; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.device.mgt.common.Device; -import org.wso2.carbon.device.mgt.common.DeviceIdentifier; +import org.wso2.carbon.device.mgt.common.EnrolmentInfo; +import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException; -import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.exceptions.UserNotFoundException; import org.wso2.carbon.device.mgt.core.service.DeviceManagementProviderService; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; @@ -53,7 +53,13 @@ import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil; import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils; import javax.validation.constraints.Size; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.util.List; @@ -107,6 +113,26 @@ public class DeviceManagementAdminServiceImpl implements DeviceManagementAdminSe } } + @Override + @Path("/count") + @GET + public Response getDeviceCount(@QueryParam("status") String status) { + int deviceCount; + try { + if (status == null) { + deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCount(); + } else { + deviceCount = DeviceMgtAPIUtils.getDeviceManagementService().getDeviceCount(EnrolmentInfo.Status.valueOf(status)); + } + } catch (DeviceManagementException e) { + String msg = "Error occurred while fetching device count."; + log.error(msg, e); + return Response.serverError().entity( + new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); + } + return Response.status(Response.Status.OK).entity(deviceCount).build(); + } + @PUT @Override @Path("/device-owner") diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/GroupManagementAdminServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/GroupManagementAdminServiceImpl.java index dcb02382041..1971890b43d 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/GroupManagementAdminServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/admin/GroupManagementAdminServiceImpl.java @@ -20,9 +20,11 @@ package org.wso2.carbon.device.mgt.jaxrs.service.impl.admin; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.solr.common.StringUtils; import org.wso2.carbon.device.mgt.common.GroupPaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroup; +import org.wso2.carbon.device.mgt.common.group.mgt.DeviceGroupConstants; +import org.wso2.carbon.device.mgt.common.group.mgt.GroupAlreadyExistException; import org.wso2.carbon.device.mgt.common.group.mgt.GroupManagementException; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceGroupList; import org.wso2.carbon.device.mgt.jaxrs.service.api.admin.GroupManagementAdminService; @@ -36,6 +38,10 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ private static final Log log = LogFactory.getLog(GroupManagementAdminServiceImpl.class); + private static final String DEFAULT_ADMIN_ROLE = "admin"; + private static final String[] DEFAULT_ADMIN_PERMISSIONS = {"/permission/device-mgt/admin/groups", + "/permission/device-mgt/user/groups"}; + @Override public Response getGroups(String name, String owner, int offset, int limit, String status) { try { @@ -84,4 +90,24 @@ public class GroupManagementAdminServiceImpl implements GroupManagementAdminServ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); } } + + @Override + public Response createGroup(DeviceGroup group) { + if (group == null) { + return Response.status(Response.Status.BAD_REQUEST).build(); + } + group.setStatus(DeviceGroupConstants.GroupStatus.ACTIVE); + try { + DeviceMgtAPIUtils.getGroupManagementProviderService().createGroup(group, DEFAULT_ADMIN_ROLE, DEFAULT_ADMIN_PERMISSIONS); + return Response.status(Response.Status.CREATED).build(); + } catch (GroupManagementException e) { + String msg = "Error occurred while adding new group."; + log.error(msg, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build(); + } catch (GroupAlreadyExistException e) { + String msg = "Group already exists with name " + group.getName() + "."; + log.warn(msg); + return Response.status(Response.Status.CONFLICT).entity(msg).build(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java index 43bb5ba7132..8765ed22e54 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderService.java @@ -752,11 +752,11 @@ public interface DeviceManagementProviderService { List findGeoClusters(String deviceType, GeoCoordinate southWest, GeoCoordinate northEast, int geohashLength) throws DeviceManagementException; - int getDeviceCountOfTypeByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException; + int getDeviceCountOfTypeByStatus(String deviceType, String deviceStatus) throws DeviceManagementException; - List getDeviceIdentifiersByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException; + List getDeviceIdentifiersByStatus(String deviceType, String deviceStatus) throws DeviceManagementException; - boolean bulkUpdateDeviceStatus(int tenantId, String deviceType, List deviceList, String status) throws DeviceManagementException; + boolean bulkUpdateDeviceStatus(String deviceType, List deviceList, String status) throws DeviceManagementException; boolean updateEnrollment(String owner, List deviceIdentifiers) throws DeviceManagementException, UserNotFoundException, InvalidDeviceException; diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java index a012fff0c80..a2f9a9769e7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/service/DeviceManagementProviderServiceImpl.java @@ -3125,10 +3125,10 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public int getDeviceCountOfTypeByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException { + public int getDeviceCountOfTypeByStatus(String deviceType, String deviceStatus) throws DeviceManagementException { try { DeviceManagementDAOFactory.openConnection(); - return deviceDAO.getDeviceCount(deviceType, deviceStatus, tenantId); + return deviceDAO.getDeviceCount(deviceType, deviceStatus, getTenantId()); } catch (DeviceManagementDAOException e) { String msg = "Error occurred in while retrieving device count by status for deviceType :" +deviceType + " status : " + deviceStatus; log.error(msg, e); @@ -3143,11 +3143,11 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public List getDeviceIdentifiersByStatus(int tenantId, String deviceType, String deviceStatus) throws DeviceManagementException { + public List getDeviceIdentifiersByStatus(String deviceType, String deviceStatus) throws DeviceManagementException { List deviceIds; try { DeviceManagementDAOFactory.openConnection(); - deviceIds = deviceDAO.getDeviceIdentifiers(deviceType, deviceStatus, tenantId); + deviceIds = deviceDAO.getDeviceIdentifiers(deviceType, deviceStatus, getTenantId()); } catch (DeviceManagementDAOException e) { String msg = "Error occurred in while retrieving devices by status for deviceType :" +deviceType + " status : " + deviceStatus; log.error(msg, e); @@ -3163,20 +3163,19 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv } @Override - public boolean bulkUpdateDeviceStatus(int tenantId, String deviceType, - List deviceList, String status) + public boolean bulkUpdateDeviceStatus(String deviceType, List deviceList, String status) throws DeviceManagementException { boolean success; try { - DeviceManagementDAOFactory.openConnection(); - success = deviceDAO.setEnrolmentStatusInBulk(deviceType, status, tenantId, deviceList); + DeviceManagementDAOFactory.beginTransaction(); + success = deviceDAO.setEnrolmentStatusInBulk(deviceType, status, getTenantId(), deviceList); DeviceManagementDAOFactory.commitTransaction(); } catch (DeviceManagementDAOException e) { - String msg = "Error occurred in while updating status of devices :" + deviceType + " status : " + deviceList - .toString(); + DeviceManagementDAOFactory.rollbackTransaction(); + String msg = "Error occurred in while updating status of devices :" + deviceType + " status : " + status; log.error(msg, e); throw new DeviceManagementException(msg, e); - } catch (SQLException e) { + } catch (TransactionManagementException e) { String msg = "Error occurred while opening a connection to the data source"; log.error(msg, e); throw new DeviceManagementException(msg, e); diff --git a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/util/PolicyManagerUtil.java b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/util/PolicyManagerUtil.java index 0d31dc2e07c..714421c431f 100644 --- a/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/util/PolicyManagerUtil.java +++ b/components/policy-mgt/org.wso2.carbon.policy.mgt.core/src/main/java/org/wso2/carbon/policy/mgt/core/util/PolicyManagerUtil.java @@ -155,8 +155,8 @@ public class PolicyManagerUtil { PolicyAdministratorPoint pap = new PolicyAdministratorPointImpl(); try { Policy correctivePolicy = pap.getPolicy(correctiveAction.getPolicyId()); - if (correctivePolicy == null || PolicyManagementConstants.CORRECTIVE_POLICY_TYPE - .equalsIgnoreCase(correctivePolicy.getPolicyType())) { + if (correctivePolicy == null || !PolicyManagementConstants.CORRECTIVE_POLICY_TYPE + .equalsIgnoreCase(correctivePolicy.getPolicyType() )) { String msg = "No corrective policy was found for the policy " + policy.getPolicyName() + " and policy ID " + policy.getId(); log.error(msg); diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/UserHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/UserHandler.java index 81041d9e9cc..6f59f28fe81 100644 --- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/UserHandler.java +++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/UserHandler.java @@ -103,7 +103,8 @@ public class UserHandler extends HttpServlet { } ProxyResponse proxyResponse = new ProxyResponse(); proxyResponse.setCode(HttpStatus.SC_OK); - proxyResponse.setData(jTokenResultAsJsonObject.get("username").getAsString()); + proxyResponse.setData( + jTokenResultAsJsonObject.get("username").getAsString().replaceAll("@carbon.super", "")); HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse); } } catch (IOException e) { diff --git a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql index 383210ef9fe..3ca9a0c9852 100644 --- a/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql +++ b/features/application-mgt/org.wso2.carbon.device.application.mgt.server.feature/src/main/resources/dbscripts/cdm/application-mgt/mysql.sql @@ -4,7 +4,7 @@ CREATE TABLE IF NOT EXISTS AP_APP( ID INTEGER NOT NULL AUTO_INCREMENT, NAME VARCHAR(45) NOT NULL, - DESCRIPTION CLOB NULL, + DESCRIPTION VARCHAR(200) NOT NULL, TYPE VARCHAR(200) NOT NULL, TENANT_ID INTEGER NOT NULL, STATUS VARCHAR(45) NOT NULL DEFAULT 'ACTIVE', @@ -20,7 +20,7 @@ CREATE TABLE IF NOT EXISTS AP_APP( -- ----------------------------------------------------- CREATE TABLE IF NOT EXISTS AP_APP_RELEASE( ID INTEGER NOT NULL AUTO_INCREMENT, - DESCRIPTION CLOB NOT NULL, + DESCRIPTION VARCHAR(200) NOT NULL, VERSION VARCHAR(70) NOT NULL, TENANT_ID INTEGER NOT NULL, UUID VARCHAR(200) NOT NULL, @@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS AP_APP_RELEASE( SC_3_LOCATION VARCHAR(100) NULL DEFAULT NULL, APP_HASH_VALUE VARCHAR(1000) NOT NULL, SHARED_WITH_ALL_TENANTS BOOLEAN NOT NULL DEFAULT FALSE, - APP_META_INFO CLOB NULL DEFAULT NULL, + APP_META_INFO VARCHAR(150) NULL DEFAULT NULL, SUPPORTED_OS_VERSIONS VARCHAR(45) NOT NULL, RATING DOUBLE NULL DEFAULT NULL, CURRENT_STATE VARCHAR(45) NOT NULL, @@ -57,8 +57,8 @@ CREATE TABLE IF NOT EXISTS AP_APP_REVIEW( COMMENT TEXT NOT NULL, ROOT_PARENT_ID INTEGER NOT NULL, IMMEDIATE_PARENT_ID INTEGER NOT NULL, - CREATED_AT TIMESTAMP NOT NULL, - MODIFIED_AT TIMESTAMP NOT NULL, + CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + MODIFIED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, RATING INTEGER NULL, USERNAME VARCHAR(45) NOT NULL, ACTIVE_REVIEW BOOLEAN NOT NULL DEFAULT TRUE, @@ -267,14 +267,11 @@ CREATE TABLE IF NOT EXISTS AP_SCHEDULED_SUBSCRIPTION( ID INTEGER NOT NULL AUTO_INCREMENT, TASK_NAME VARCHAR(100) NOT NULL, APPLICATION_UUID VARCHAR(36) NOT NULL, - SUBSCRIBER_LIST LONGVARCHAR NOT NULL, + SUBSCRIBER_LIST TEXT NOT NULL, STATUS VARCHAR(15) NOT NULL, - SCHEDULED_AT TIMESTAMP NOT NULL, + SCHEDULED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, SCHEDULED_BY VARCHAR(100) NOT NULL, - SCHEDULED_TIMESTAMP TIMESTAMP NOT NULL, + SCHEDULED_TIMESTAMP TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, DELETED BOOLEAN, - PRIMARY KEY (ID), - CONSTRAINT fk_AP_SCHEDULED_SUBSCRIPTION_AP_APP_RELEASE - FOREIGN KEY (APPLICATION_UUID) - REFERENCES AP_APP_RELEASE (UUID) ON DELETE NO ACTION ON UPDATE NO ACTION -); + PRIMARY KEY (ID) +); \ No newline at end of file