diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/BulkActionBar.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/BulkActionBar.js
index 4964d4d9cb..5b4f49e6ed 100644
--- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/BulkActionBar.js
+++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Devices/BulkActionBar.js
@@ -17,67 +17,106 @@
*/
import React from "react";
-import {Button, Icon, notification} from "antd";
+import {Button, Tooltip, Popconfirm, Divider} from "antd";
class BulkActionBar extends React.Component {
- constructor(props){
+ constructor(props) {
super(props);
this.state = {
- selectedMultiple:false,
- selectedSingle:false
+ selectedMultiple: false,
+ selectedSingle: false,
+ canDelete: true,
}
}
- //This method is used to trigger delete request on selected devices
- deleteDevice = () => {
- const deviceStatusArray = this.props.selectedRows.map(obj => obj.enrolmentInfo.status);
- if(deviceStatusArray.includes("ACTIVE") || deviceStatusArray.includes("INACTIVE")){
- notification["error"]({
- message: "There was a problem",
- duration: 0,
- description:
- "Cannot delete ACTIVE/INACTIVE devices.",
- });
- }else{
- this.props.deleteDevice();
+ //This method checks whether NON-REMOVED devices are selected
+ onDeleteDeviceCall = () => {
+ let tempDeleteState;
+ for(let i=0; i < this.props.selectedRows.length; i++){
+ if(this.props.selectedRows[i].enrolmentInfo.status != "REMOVED"){
+ tempDeleteState = false;
+ break;
+ }
+ tempDeleteState = true;
}
- }
+ this.setState({canDelete:tempDeleteState})
+ };
- componentDidUpdate(prevProps, prevState, snapshot) {
- if(prevProps.selectedRows !== this.props.selectedRows){
- if(this.props.selectedRows.length > 1){
- this.setState({selectedMultiple:true,selectedSingle:false})
- }else if(this.props.selectedRows.length == 1){
- this.setState({selectedSingle:true,selectedMultiple:true})
- }else{
- this.setState({selectedSingle:false,selectedMultiple:false})
- }
+ onConfirmDelete = () => {
+ if (this.state.canDelete) {
+ this.props.deleteDevice();
}
+ };
+
+ onConfirmDisenroll = () => {
+ //TODO: Implement disenrollment function
+ };
+
+ onDeviceGroupCall = () => {
+ this.props.getGroups();
}
render() {
- return(
-
-
+ const isSelected = this.props.selectedRows.length > 0;
+ const isSelectedSingle = this.props.selectedRows.length == 1;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
)
}
}
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 7a096a2147..fd87a6a7e1 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,7 +18,7 @@
import React from "react";
import axios from "axios";
-import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Button} from "antd";
+import {Tag, message, notification, Table, Typography, Tooltip, Icon, Divider, Button, Modal, Select} from "antd";
import TimeAgo from 'javascript-time-ago'
// Load locale-specific relative date/time formatting rules.
@@ -112,18 +112,7 @@ const columns = [
return {timeAgoString};
}
// todo add filtering options
- },
- {
- title: 'Action',
- key: 'action',
- render: () => (
-
-
-
-
-
- ),
- },
+ }
];
const getTimeAgo = (time) => {
@@ -135,14 +124,16 @@ const getTimeAgo = (time) => {
class DeviceTable extends React.Component {
constructor(props) {
super(props);
- config = this.props.context;
+ config = this.props.context;
TimeAgo.addLocale(en);
this.state = {
data: [],
pagination: {},
loading: false,
selectedRows: [],
- deviceIds: []
+ deviceGroups: [],
+ groupModalVisible: false,
+ selectedGroupId: []
};
}
@@ -151,7 +142,6 @@ class DeviceTable extends React.Component {
this.setState({
selectedRows: selectedRows
});
- this.state.deviceIds = selectedRows.map(obj => obj.deviceIdentifier);
}
};
@@ -173,7 +163,7 @@ class DeviceTable extends React.Component {
};
const encodedExtraParams = Object.keys(extraParams)
- .map(key => key + '=' + extraParams[key]).join('&');
+ .map(key => key + '=' + extraParams[key]).join('&');
//send request to the invoker
axios.get(
@@ -212,26 +202,112 @@ class DeviceTable extends React.Component {
const config = this.props.context;
this.setState({loading: true});
- const deviceData = this.state.deviceIds;
+ const deviceData = this.state.selectedRows.map(obj => obj.deviceIdentifier);
//send request to the invoker
axios.put(
- window.location.origin + config.serverConfig.invoker.uri +
+ window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/admin/devices/permanent-delete",
+ deviceData,
+ {headers: {'Content-Type': 'application/json'}}
+ ).then(res => {
+ if (res.status === 200) {
+ this.fetch();
+ }
+ }).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 devices.",
+ });
+ }
+
+ this.setState({loading: false});
+ });
+ };
+
+ addDevicesToGroup = (groupId) => {
+ const config = this.props.context;
+ this.setState({loading: true});
+
+ let apiUrl;
+ let deviceData;
+ if (this.state.selectedRows.length === 1) {
+ apiUrl = window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/groups/device/assign";
+ deviceData = {
+ deviceIdentifier: {
+ id: this.state.selectedRows[0].deviceIdentifier,
+ type: this.state.selectedRows[0].type
+ },
+ deviceGroupIds: groupId
+ }
+ } else if (!groupId[0]){
+ apiUrl = window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/groups/id/" + groupId + "/devices/add";
+ deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
+ } else{
+ apiUrl = window.location.origin + config.serverConfig.invoker.uri +
config.serverConfig.invoker.deviceMgt +
- "/admin/devices/permanent-delete",
- deviceData,
- { headers : {'Content-Type': 'application/json'}}
+ "/groups/id/" + groupId[0] + "/devices/add";
+ deviceData = this.state.selectedRows.map(obj => ({id: obj.deviceIdentifier, type: obj.type}));
+ }
+ //send request to the invoker
+ axios.post(
+ apiUrl,
+ deviceData,
+ {headers: {'Content-Type': 'application/json'}}
).then(res => {
if (res.status === 200) {
- this.fetch();
- const pagination = {...this.state.pagination};
this.setState({
- loading: false,
- data: res.data.data.devices,
- pagination,
- });
+ loading: false
+ });
+ notification["success"]({
+ message: "Done",
+ duration: 4,
+ description:
+ "Successfully added to the device 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 adding to the device group.",
+ });
}
+
+ this.setState({loading: false});
+ });
+ };
+
+ getGroups = () => {
+ this.setState({
+ groupModalVisible: true
+ });
+ //send request to the invoker
+ axios.get(
+ window.location.origin + config.serverConfig.invoker.uri +
+ config.serverConfig.invoker.deviceMgt +
+ "/groups"
+ ).then(res => {
+ this.setState({deviceGroups: res.data.data.deviceGroups})
}).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) {
//todo display a popop with error
@@ -239,16 +315,43 @@ class DeviceTable extends React.Component {
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 devices.",
- });
+ message: "There was a problem",
+ duration: 0,
+ description:
+ "Error occurred while retrieving device groups.",
+ });
}
this.setState({loading: false});
});
- }
+ };
+
+ handleOk = e => {
+ if(this.state.selectedGroupId){
+ this.addDevicesToGroup(this.state.selectedGroupId);
+ this.setState({
+ groupModalVisible: false
+ });
+ }else{
+ notification["error"]({
+ message: "There was a problem",
+ duration: 0,
+ description:
+ "Please select a group.",
+ });
+ }
+
+ };
+
+ handleCancel = e => {
+ this.setState({
+ groupModalVisible: false,
+ });
+ };
+
+ onGroupSelectChange = (value) => {
+ this.setState({selectedGroupId: value});
+ };
handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination};
@@ -267,27 +370,58 @@ class DeviceTable extends React.Component {
render() {
const {data, pagination, loading, selectedRows} = this.state;
+
+ const isSelectedSingle = this.state.selectedRows.length == 1;
+
+ let item = this.state.deviceGroups.map((data) =>
+
+ {data.name}
+ );
return (
- (record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
- dataSource={data}
- pagination={{
- ...pagination,
- size: "small",
- // position: "top",
- showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
- // showQuickJumper: true
- }}
- loading={loading}
- onChange={this.handleTableChange}
- rowSelection={this.rowSelection}
- scroll={{x: 1000}}
- />
+ deleteDevice={this.deleteDevice}
+ getGroups={this.getGroups}
+ selectedRows={this.state.selectedRows}/>
+
+
(record.deviceIdentifier + record.enrolmentInfo.owner + record.enrolmentInfo.ownership)}
+ dataSource={data}
+ pagination={{
+ ...pagination,
+ size: "small",
+ // position: "top",
+ showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
+ // showQuickJumper: true
+ }}
+ loading={loading}
+ onChange={this.handleTableChange}
+ rowSelection={this.rowSelection}
+ scroll={{x: 1000}}
+ />
+
+
+
+
+
);
}
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 0e52285893..3be6900f90 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
@@ -3271,7 +3271,9 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
distance = p.getValue();
}
}
- if (latitude != null && longitude != null && !latitude.isEmpty() && !longitude.isEmpty()) {
+ if (StringUtils.isNotBlank(latitude) && StringUtils.isNotBlank(longitude) &&
+ StringUtils.isNotBlank(altitude) && StringUtils.isNotBlank(speed) &&
+ StringUtils.isNotBlank(bearing) && StringUtils.isNotBlank(distance)) {
DeviceLocation deviceLocation = new DeviceLocation();
deviceLocation.setDeviceId(device.getId());
deviceLocation.setDeviceIdentifier(new DeviceIdentifier(device.getDeviceIdentifier(),
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
index 314a863c56..1d046a4aed 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/LoginHandler.java
@@ -191,7 +191,6 @@ public class LoginHandler extends HttpServlet {
authData.setScope(jTokenResultAsJsonObject.get("scope").getAsString());
session.setAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY, authData);
return true;
-
}
}
return false;
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
new file mode 100644
index 0000000000..e742e543fd
--- /dev/null
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/UserHandler.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2019, Entgra (Pvt) Ltd. (http://www.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.
+ */
+
+package io.entgra.ui.request.interceptor;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSyntaxException;
+import io.entgra.ui.request.interceptor.beans.AuthData;
+import io.entgra.ui.request.interceptor.util.HandlerConstants;
+import io.entgra.ui.request.interceptor.util.HandlerUtil;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.wso2.carbon.device.application.mgt.common.ProxyResponse;
+
+import javax.servlet.annotation.MultipartConfig;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+
+@MultipartConfig @WebServlet("/user") public class UserHandler extends HttpServlet {
+ private static final Log log = LogFactory.getLog(UserHandler.class);
+ private static final long serialVersionUID = 9050048549140517002L;
+
+ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
+ try {
+ String platform = req.getParameter(HandlerConstants.PLATFORM);
+ String serverUrl =
+ req.getScheme() + HandlerConstants.SCHEME_SEPARATOR + req.getServerName() + HandlerConstants.COLON
+ + System.getProperty("iot.gateway.https.port");
+ if (StringUtils.isBlank(platform)) {
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_BAD_REQUEST);
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+
+ HttpSession httpSession = req.getSession(false);
+ if (httpSession == null) {
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+
+ AuthData authData = (AuthData) httpSession.getAttribute(HandlerConstants.SESSION_AUTH_DATA_KEY);
+ String accessToken = authData.getAccessToken();
+
+ HttpPost tokenEndpoint = new HttpPost(serverUrl + HandlerConstants.INTROSPECT_ENDPOINT);
+ tokenEndpoint.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_FORM_URLENCODED.toString());
+ StringEntity tokenEPPayload = new StringEntity("token=" + accessToken,
+ ContentType.APPLICATION_FORM_URLENCODED);
+ tokenEndpoint.setEntity(tokenEPPayload);
+ ProxyResponse tokenStatus = HandlerUtil.execute(tokenEndpoint);
+
+ if (tokenStatus.getExecutorResponse().contains(HandlerConstants.EXECUTOR_EXCEPTION_PREFIX)) {
+ log.error("Error occurred while invoking the API to get token status.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, tokenStatus);
+ return;
+ }
+ String tokenData = tokenStatus.getData();
+ if (tokenData == null) {
+ log.error("Invalid token data is received.");
+ HandlerUtil.handleError(req, resp, serverUrl, platform, tokenStatus);
+ return;
+ }
+ JsonParser jsonParser = new JsonParser();
+ JsonElement jTokenResult = jsonParser.parse(tokenData);
+ if (jTokenResult.isJsonObject()) {
+ JsonObject jTokenResultAsJsonObject = jTokenResult.getAsJsonObject();
+ if (!jTokenResultAsJsonObject.get("active").getAsBoolean()) {
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_UNAUTHORIZED);
+ HandlerUtil.handleError(req, resp, serverUrl, platform, proxyResponse);
+ return;
+ }
+ ProxyResponse proxyResponse = new ProxyResponse();
+ proxyResponse.setCode(HttpStatus.SC_OK);
+ proxyResponse.setData(jTokenResultAsJsonObject.get("username").getAsString());
+ HandlerUtil.handleSuccess(req, resp, serverUrl, platform, proxyResponse);
+ }
+ } catch (IOException e) {
+ log.error("Error occurred while sending the response into the socket. ", e);
+ } catch (JsonSyntaxException e) {
+ log.error("Error occurred while parsing the response. ", e);
+ }
+ }
+}
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
index 562f497678..d74308104f 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerConstants.java
@@ -23,6 +23,7 @@ public class HandlerConstants {
public static final String APP_REG_ENDPOINT = "/api-application-registration/register";
public static final String UI_CONFIG_ENDPOINT = "/api/application-mgt/v1.0/config/ui-config";
public static final String TOKEN_ENDPOINT = "/token";
+ public static final String INTROSPECT_ENDPOINT = "/oauth2/introspect";
public static final String LOGIN_PAGE = "/login";
public static final String BASIC = "Basic ";
public static final String BEARER = "Bearer ";
diff --git a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
index 4093902327..ae0fe3c639 100644
--- a/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
+++ b/components/ui-request-interceptor/io.entgra.ui.request.interceptor/src/main/java/io/entgra/ui/request/interceptor/util/HandlerUtil.java
@@ -20,7 +20,6 @@ package io.entgra.ui.request.interceptor.util;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;