From 40bf2ca1e9ae5c6e57c78a05ba71153cad7e6a22 Mon Sep 17 00:00:00 2001 From: Shamalka Navod Date: Wed, 8 Jan 2020 10:30:53 +0000 Subject: [PATCH] UI for device enrollment reports --- .../react-app/package.json | 2 + .../react-app/src/App.js | 24 +- .../Reports/Templates/DeviceStatusReport.js | 125 +++++++ .../Reports/Templates/EnrollmentTypeReport.js | 133 ++++++++ .../EnrollmentsVsUnenrollmentsReport.js | 172 ++++++++++ .../components/Reports/Widgets/CountWidget.js | 63 ++++ .../components/Reports/Widgets/PieChart.js | 322 ++++++++++++++++++ .../react-app/src/index.js | 23 ++ .../Reports/ReportDurationItemList.js | 152 +++++++++ .../src/pages/Dashboard/Reports/Reports.js | 51 +-- .../service/api/ReportManagementService.java | 75 +++- .../impl/ReportManagementServiceImpl.java | 30 +- .../report/mgt/ReportManagementService.java | 7 +- .../carbon/device/mgt/core/dao/DeviceDAO.java | 5 + .../dao/impl/device/GenericDeviceDAOImpl.java | 87 ++++- .../dao/impl/device/OracleDeviceDAOImpl.java | 7 +- .../impl/device/PostgreSQLDeviceDAOImpl.java | 7 +- .../impl/device/SQLServerDeviceDAOImpl.java | 7 +- .../mgt/ReportManagementServiceImpl.java | 22 +- 19 files changed, 1251 insertions(+), 63 deletions(-) create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/DeviceStatusReport.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentTypeReport.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentsVsUnenrollmentsReport.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/CountWidget.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js create mode 100644 components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/ReportDurationItemList.js diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json b/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json index 05bc6857319..04c40c1edc0 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/package.json @@ -8,6 +8,7 @@ "acorn": "^6.2.0", "antd": "^3.23.5", "axios": "^0.18.1", + "bizcharts": "^3.5.6", "bootstrap": "^4.3.1", "javascript-time-ago": "^2.0.1", "keymirror": "^0.1.1", @@ -35,6 +36,7 @@ "storm-react-diagrams": "^5.2.1" }, "devDependencies": { + "@antv/data-set": "^0.10.2", "@babel/core": "^7.5.4", "@babel/plugin-proposal-class-properties": "^7.5.0", "@babel/preset-env": "^7.5.4", diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/App.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/App.js index 5f8f429e8e4..078ceaaaebb 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/App.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/App.js @@ -24,7 +24,7 @@ import { Redirect, Switch, } from 'react-router-dom'; import axios from "axios"; -import {Layout, Spin, Result} from "antd"; +import {Layout, Spin, Result, message, notification} from "antd"; import ConfigContext from "./context/ConfigContext"; const {Content} = Layout; @@ -93,6 +93,7 @@ class App extends React.Component { config: config }); } + this.getDeviceTypes(config); }).catch((error) => { if (error.hasOwnProperty("response") && error.response.status === 401) { const redirectUrl = encodeURI(window.location.href); @@ -115,9 +116,30 @@ class App extends React.Component { }); }; + getDeviceTypes = (config) => { + axios.get( + window.location.origin + "/entgra-ui-request-handler/invoke/device-mgt/v1.0/device-types", + ).then(res => { + config.deviceTypes = JSON.parse(res.data.data); + this.setState({ + config: config, + loading: false + }); + }).catch((error) => { + + notification["error"]({ + message: "There was a problem", + duration: 0, + description:"Error occurred while trying to load device types.", + }); + + }); + }; + render() { const {loading, error} = this.state; + const abc = this.state.deviceTypes; const applicationView = ( diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/DeviceStatusReport.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/DeviceStatusReport.js new file mode 100644 index 00000000000..44249aba0a4 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/DeviceStatusReport.js @@ -0,0 +1,125 @@ +/* + * 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 { + PageHeader, + Typography, + Breadcrumb, + Icon, + Tag, + Radio, Select, Button, Card, + Row, Col, message, notification +} from "antd"; + +import {Link} from "react-router-dom"; +import PoliciesTable from "../../../components/Policies/PoliciesTable"; +import DevicesTable from "../../../components/Devices/DevicesTable"; +import DateRangePicker from "../../../components/Reports/DateRangePicker"; +import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable"; +import PieChart from "../../../components/Reports/Widgets/PieChart"; +import axios from "axios"; +import CountWidget from "../../../components/Reports/Widgets/CountWidget"; +import {withConfigContext} from "../../../context/ConfigContext"; +const {Paragraph} = Typography; +const { CheckableTag } = Tag; + +const { Option } = Select; +let config = null; + + +class DeviceStatusReport extends React.Component { + routes; + + constructor(props) { + super(props); + this.routes = props.routes; + config = this.props.context; + const { reportData } = this.props.location; + this.state = { + selectedTags: ['Enrolled'], + paramsObject:{ + from:reportData.duration[0], + to:reportData.duration[1] + }, + statsObject:{}, + statArray:[{item:"ACTIVE",count:0},{item:"INACTIVE",count:0},{item:"REMOVED",count:0}] + }; + } + + onClickPieChart = (value) => { + console.log(value.data.point.item); + const chartValue = value.data.point.item; + let tempParamObj = this.state.paramsObject; + + tempParamObj.status = chartValue; + + + this.setState({paramsObject:tempParamObj}); + console.log(this.state.paramsObject) + }; + + render() { + const { statArray } = this.state; + const { reportData } = this.props.location; + + const params = {...this.state.paramsObject}; + return ( +
+ + + + Home + + Report + +
+

Summary of enrollments

+
+ + +
+
+ +
+ + + + +
+ +
+ +
+
+
+ +
+
+ ); + } +} + +export default withConfigContext(DeviceStatusReport); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentTypeReport.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentTypeReport.js new file mode 100644 index 00000000000..595aa8856e8 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentTypeReport.js @@ -0,0 +1,133 @@ +/* + * 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 { + PageHeader, + Typography, + Breadcrumb, + Icon, + Tag, + Radio, Select, Button, Card, + Row, Col, message, notification +} from "antd"; + +import {Link} from "react-router-dom"; +import PoliciesTable from "../../../components/Policies/PoliciesTable"; +import DevicesTable from "../../../components/Devices/DevicesTable"; +import DateRangePicker from "../../../components/Reports/DateRangePicker"; +import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable"; +import PieChart from "../../../components/Reports/Widgets/PieChart"; +import axios from "axios"; +import CountWidget from "../../../components/Reports/Widgets/CountWidget"; +import {withConfigContext} from "../../../context/ConfigContext"; +const {Paragraph} = Typography; +const { CheckableTag } = Tag; + +const { Option } = Select; +let config = null; + + +class EnrollmentTypeReport extends React.Component { + routes; + + constructor(props) { + super(props); + this.routes = props.routes; + config = this.props.context; + const { reportData } = this.props.location; + this.state = { + paramsObject:{ + from:reportData.duration[0], + to:reportData.duration[1] + } + }; + + + console.log(reportData.duration); + } + + setParam = (tempParamObj, type, value) => { + if(type==="status"){ + tempParamObj.status = value; + if(tempParamObj.status) { + delete tempParamObj.status; + } + } else if(type=="ownership"){ + tempParamObj.ownership = value; + if(value=="ALL" && tempParamObj.ownership) { + delete tempParamObj.ownership; + } + } + }; + + onClickPieChart = (value) => { + const chartValue = value.data.point.item; + let tempParamObj = this.state.paramsObject; + + console.log(chartValue) + + tempParamObj.ownership = chartValue; + + this.setState({paramsObject:tempParamObj}); + }; + + render() { + const { reportData } = this.props.location; + + const params = {...this.state.paramsObject}; + return ( +
+ + + + Home + + Report + +
+

Summary of enrollments

+ +
+ +
+ + + + + + + +
+ +
+ +
+
+
+ +
+
+ ); + } +} + +export default withConfigContext(EnrollmentTypeReport); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentsVsUnenrollmentsReport.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentsVsUnenrollmentsReport.js new file mode 100644 index 00000000000..b6ab7c29352 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Templates/EnrollmentsVsUnenrollmentsReport.js @@ -0,0 +1,172 @@ +/* + * 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 { + PageHeader, + Typography, + Breadcrumb, + Icon, + Tag, + Radio, Select, Button, Card, + Row, Col, message, notification +} from "antd"; + +import {Link, Redirect} from "react-router-dom"; +import PoliciesTable from "../../../components/Policies/PoliciesTable"; +import DevicesTable from "../../../components/Devices/DevicesTable"; +import DateRangePicker from "../../../components/Reports/DateRangePicker"; +import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable"; +import PieChart from "../../../components/Reports/Widgets/PieChart"; +import axios from "axios"; +import CountWidget from "../../../components/Reports/Widgets/CountWidget"; +import {withConfigContext} from "../../../context/ConfigContext"; +const {Paragraph} = Typography; +const { CheckableTag } = Tag; + +const { Option } = Select; +let config = null; + + +class EnrollmentsVsUnenrollmentsReport extends React.Component { + routes; + + constructor(props) { + super(props); + this.routes = props.routes; + config = this.props.context; + const { reportData } = this.props.location; + + this.state = { + paramsObject:{ + from:reportData? reportData.duration[0]: "2019-01-01", + to:reportData? reportData.duration[1]: "2019-01-01" + }, + redirect: false + }; + + this.redirectToHome(); + console.log(this.state.paramsObject); + } + + setParam = (tempParamObj, type, value) => { + if(type==="status"){ + tempParamObj.status = value; + if(tempParamObj.status) { + delete tempParamObj.status; + } + } else if(type=="ownership"){ + tempParamObj.ownership = value; + if(value=="ALL" && tempParamObj.ownership) { + delete tempParamObj.ownership; + } + } + }; + + redirectToHome = () => { + return + }; + + setRedirect = (reportData) => { + if(!reportData){ + this.setState({ + redirect: true + }) + } + }; + + renderRedirect = () => { + if (this.state.redirect) { + return + } + } + + onClickPieChart = (value) => { + const chartValue = value.data.point.item; + let tempParamObj = this.state.paramsObject; + + console.log(chartValue) + + // tempParamObj.status = chartValue; + + if(chartValue==="Enrollments"){ + tempParamObj.status = "ACTIVE&status=INACTIVE" + }else{ + tempParamObj.status = "REMOVED" + } + + + this.setState({paramsObject:tempParamObj}); + }; + + render() { + const { reportData } = this.props.location; + + console.log("======") + console.log(reportData) + console.log("======") + + let reportDataClone = { + params: ["ACTIVE"], + duration: ["2020-01-01","2020-01-01"] + }; + + const params = {...this.state.paramsObject}; + return ( +
+ +
{!reportData ? ( + + ) : ( + + + + Home + + Report + +
+

Summary of enrollments

+ +
+ +
+ + + + + + + +
+ +
+ +
+
+ + )}
+
+ ); + } +} + +export default withConfigContext(EnrollmentsVsUnenrollmentsReport); diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/CountWidget.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/CountWidget.js new file mode 100644 index 00000000000..f1854f87372 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/CountWidget.js @@ -0,0 +1,63 @@ +import React from "react"; + +import {Card, Col, Icon} from "antd"; +import {Link} from "react-router-dom"; + +class CountWidget extends React.Component { + + constructor(props) { + super(props); + this.routes = props.routes; + this.state = { + statArray:[] + } + } + + componentDidMount() { + this.setState({statArray:this.props.statArray}) + console.log("$$$$") + console.log(this.props.statArray) + } + + + render() { + const countObj = [ + {item:"All",count:100}, + {item:"Enrolled",count:80}, + {item:"Unenrolled",count:20}]; + + const { statArray } = this.state; + + let card = statArray.map((data) => + // + // + //

{data.item} Devices: {data.count}

+ // + //
+ + + +
+

{data.item}

+

{data.count}

+ {/*

{data.duration}

*/} + {/**/} +
+
+ + ) + + return( +
+ {card} +
+ + ) + } +} + +export default CountWidget; \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js new file mode 100644 index 00000000000..f66eac10b74 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/components/Reports/Widgets/PieChart.js @@ -0,0 +1,322 @@ +import React from "react"; +import { + G2, + Chart, + Geom, + Axis, + Tooltip, + Coord, + Label, + Legend, + View, + Guide, + Shape, + Facet, + Util +} from "bizcharts"; +import DataSet from "@antv/data-set"; +import axios from "axios"; +import {message, notification} from "antd"; +import {withConfigContext} from "../../../context/ConfigContext"; + +let config = null; + +class PieChart extends React.Component { + + constructor(props) { + super(props); + config = this.props.context; + this.state = { + loading:true, + statArray:[] + }; + + } + + componentDidMount() { + let { statArray } = this.state; + const { reportData } = this.props; + let params = { + status: reportData.params[0], + from: reportData.duration[0], + to: reportData.duration[1] + }; + + const urlSet = { + paramsList:reportData.params, + duration:reportData.duration + }; + + console.log(urlSet) + + if(reportData.params[0]==="Enrollments"){ + this.getEnrollmentsVsUnenrollmentsCount(params, urlSet) + }else if(reportData.params[0]==="BYOD"){ + this.getEnrollmentTypeCount(params, urlSet); + }else{ + this.getCount(params, urlSet); + } + } + + clicked = () => { + console.log("Clicked...!!") + }; + + onChartChange = (data) => { + this.props.onClickPieChart(data); + }; + + statArray = []; + + //Call count APIs and get count for given parameters, then create data object to build pie chart + getCount = (params, urlSet) => { + + this.setState({loading: true}); + + let { statArray } = this.state; + + console.log(urlSet); + + const urlArray = []; + + urlSet.paramsList.map((data) => { + const paramsObj = { + status:data, + from:urlSet.duration[0], + to:urlSet.duration[1] + } + // console.log(paramsObj) + const encodedExtraParams = Object.keys(paramsObj) + .map(key => key + '=' + paramsObj[key]).join('&'); + const apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/reports/devices/count?" + encodedExtraParams; + + urlArray.push(axios.get(apiUrl, data)); + }); + + console.log(urlArray) + + + axios.all(urlArray).then(res => { + + res.map((response) => { + if(response.status === 200){ + let countData = {item:response.config[0], count:parseInt(response.data.data)} + statArray.push(countData); + } + }) + this.setState({statArray}) + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popup 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 get device count.", + }); + } + }); + }; + + //Call count APIs and get count for given parameters, then create data object to build pie chart + getEnrollmentsVsUnenrollmentsCount = (params, urlSet) => { + + this.setState({loading: true}); + + let { statArray } = this.state; + + console.log(urlSet); + + const urlArray = []; + + urlSet.paramsList.map((data) => { + const paramsObj = { + from:urlSet.duration[0], + to:urlSet.duration[1] + } + const encodedExtraParams = Object.keys(paramsObj) + .map(key => key + '=' + paramsObj[key]).join('&'); + + let apiUrl; + if(data==="Enrollments"){ + apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/reports/devices/count?status=ACTIVE&status=INACTIVE&" + encodedExtraParams; + }else{ + apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/reports/devices/count?status=REMOVED&" + encodedExtraParams; + } + + urlArray.push(axios.get(apiUrl, data)); + }); + + console.log(urlArray) + + + axios.all(urlArray).then(res => { + res.map((response) => { + if(response.status === 200){ + let countData = {item:response.config[0], count:parseInt(response.data.data)} + statArray.push(countData); + } + }) + this.setState({statArray}) + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popup 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 get device count.", + }); + } + }); + }; + + //Call count APIs and get count for given parameters, then create data object to build pie chart + getEnrollmentTypeCount = (params, urlSet) => { + + this.setState({loading: true}); + + let { statArray } = this.state; + + console.log(urlSet); + + const urlArray = []; + + urlSet.paramsList.map((data) => { + const paramsObj = { + ownership:data, + from:urlSet.duration[0], + to:urlSet.duration[1] + } + const encodedExtraParams = Object.keys(paramsObj) + .map(key => key + '=' + paramsObj[key]).join('&'); + const apiUrl = window.location.origin + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + "/reports/devices/count?" + encodedExtraParams; + + urlArray.push(axios.get(apiUrl, data)); + }); + + console.log(urlArray) + + + axios.all(urlArray).then(res => { + res.map((response) => { + if(response.status === 200){ + let countData = {item:response.config[0], count:parseInt(response.data.data)} + statArray.push(countData); + } + }) + this.setState({statArray}) + }).catch((error) => { + if (error.hasOwnProperty("response") && error.response.status === 401) { + //todo display a popup 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 get device count.", + }); + } + }); + }; + + render() { + const { DataView } = DataSet; + const { Html } = Guide; + const { statArray , loading} = this.state; + + const dv = new DataView(); + dv.source(statArray).transform({ + type: "percent", + field: "count", + dimension: "item", + as: "percent" + }); + const cols = { + percent: { + formatter: val => { + val = val * 100 + "%"; + return val; + } + } + }; + + return ( +
+ + + + + + + + +
+ { + percent = percent * 100 + "%"; + return { + name: item, + value: percent + }; + } + ]} + style={{ + lineWidth: 1, + stroke: "#fff" + }} + > + +
+ +
+
+ ); + } +} + +export default withConfigContext(PieChart); \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js index 32eb56672d4..2f9c0179d35 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/index.js @@ -34,6 +34,9 @@ import DeviceTypes from "./pages/Dashboard/DeviceTypes/DeviceTypes"; import DeviceEnroll from "./pages/Dashboard/Devices/DeviceEnroll"; import AddNewPolicy from "./pages/Dashboard/Policies/AddNewPolicy"; import Certificates from "./pages/Dashboard/Configurations/Certificates/Certificates"; +import ReportDurationItemList from "./pages/Dashboard/Reports/ReportDurationItemList"; +import EnrollmentsVsUnenrollmentsReport from "./components/Reports/Templates/EnrollmentsVsUnenrollmentsReport"; +import EnrollmentTypeReport from "./components/Reports/Templates/EnrollmentTypeReport"; const routes = [ { @@ -100,6 +103,26 @@ const routes = [ path: '/entgra/certificates', component: Certificates, exact: true + }, + { + path: '/entgra/reportList', + component: ReportDurationItemList, + exact: true + }, + { + path: '/entgra/enrollmentsvsunenrollments', + component: EnrollmentsVsUnenrollmentsReport, + exact: true + }, + { + path: '/entgra/enrollmenttype', + component: EnrollmentTypeReport, + exact: true + }, + { + path: '/entgra/devicestatus', + component: DeviceStatusReport, + exact: true } ] } diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/ReportDurationItemList.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/ReportDurationItemList.js new file mode 100644 index 00000000000..13804d845e4 --- /dev/null +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/ReportDurationItemList.js @@ -0,0 +1,152 @@ +/* + * 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 { + Icon, + Col, + Row, Select, + Radio, Card, + Button +} from "antd"; + +import {Link} from "react-router-dom"; +import moment from "moment"; + + +const { Option } = Select; + +class ReportDurationItemList extends React.Component { + + constructor(props) { + super(props); + this.state = { + reportParams:["ACTIVE","INACTIVE","REMOVED"], + enrollmentsVsUnenrollmentsParams:["Enrollments", "Unenrollments"], + enrollmentTypeParams:["BYOD", "COPE"] + } + } + + durationItemArray = [ + {name:"Daily Report", description:"Enrollments of today", duration:[moment().format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]}, + {name:"Weekly Report", description:"Enrollments of last 7 days", duration:[moment().subtract(6, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]}, + {name:"Monthly Report", description:"Enrollments of last month", duration:[moment().subtract(29, 'days').format('YYYY-MM-DD'), moment().add(1, 'days').format('YYYY-MM-DD')]}] + + + render(){ + + let itemStatus = this.durationItemArray.map((data) => + + + + +
+ +

{data.name}

+

{data.description}

+ {/*

{data.duration}

*/} +
+
+ + + ); + + let itemEnrollmentsVsUnenrollments = this.durationItemArray.map((data) => + + + + +
+ +

{data.name}

+

{data.description}

+
+
+ + + ); + + let itemEnrollmentType = this.durationItemArray.map((data) => + + + + +
+ +

{data.name}

+

{data.description}

+
+
+ + + ); + return( +
+
+ + {itemStatus} + +
+ +
+ + {itemEnrollmentsVsUnenrollments} + +
+ +
+ + {itemEnrollmentType} + +
+
+ ) + } +} + +export default ReportDurationItemList; \ No newline at end of file diff --git a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js index 0f271fa05a6..17abf992f71 100644 --- a/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js +++ b/components/device-mgt/io.entgra.device.mgt.ui/react-app/src/pages/Dashboard/Reports/Reports.js @@ -24,9 +24,7 @@ import { Icon } from "antd"; import {Link} from "react-router-dom"; -import ReportDeviceTable from "../../../components/Devices/ReportDevicesTable"; -import Filter from "../../../components/Reports/Filter"; -import DateRangePicker from "../../../components/Reports/DateRangePicker"; +import ReportDurationItemList from "./ReportDurationItemList"; const {Paragraph} = Typography; @@ -37,17 +35,16 @@ class Reports extends React.Component { super(props); this.routes = props.routes; this.state = { - paramsObject:{} + paramsObject:{}, } } - - //Get modified value from datepicker and set it to paramsObject + //Get modified value from datepicker and set it to paramsObject updateDurationValue = (modifiedFromDate,modifiedToDate) => { let tempParamObj = this.state.paramsObject; tempParamObj.from = modifiedFromDate; tempParamObj.to = modifiedToDate; this.setState({paramsObject:tempParamObj}); - } + }; //Get modified value from filters and set it to paramsObject updateFiltersValue = (modifiedValue,filterType) => { @@ -64,13 +61,13 @@ class Reports extends React.Component { } } this.setState({paramsObject:tempParamObj}); - } + }; render() { //Arrays for filters const statusObj = ['ALL','ACTIVE','INACTIVE','REMOVED']; const ownershipObj = ['ALL','BYOD','COPE']; - + const params = {...this.state.paramsObject}; return ( @@ -84,41 +81,7 @@ class Reports extends React.Component {

Reports

- - To generate a report, select a duration and apply filters - -
- - - - - - - - - - - - - -
Select DurationDevice StatusDevice Ownership
- - - - - -
-
-
- -
+
diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java index 6f3427181b9..37325c58b47 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/api/ReportManagementService.java @@ -42,6 +42,7 @@ 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; @SwaggerDefinition( info = @Info( @@ -127,7 +128,7 @@ public interface ReportManagementService { @ApiParam( name = "status", value = "Provide the device status details, such as active or inactive.") - @QueryParam("status") String status, + @QueryParam("status") List status, @ApiParam( name = "ownership", allowableValues = "BYOD, COPE", @@ -157,4 +158,76 @@ public interface ReportManagementService { defaultValue = "5") @QueryParam("limit") int limit) throws ReportManagementException; + + + @GET + @Path("/devices/count") + @ApiOperation( + produces = MediaType.APPLICATION_JSON, + httpMethod = "GET", + value = "Getting Details of Registered Devices", + notes = "Provides details of all the devices enrolled with WSO2 IoT Server.", + tags = "Device Management", + extensions = { + @Extension(properties = { + @ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:view") + }) + } + ) + @ApiResponses( + value = { + @ApiResponse( + code = 200, + message = "OK. \n Successfully fetched the list of devices.", + response = DeviceList.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 was last modified.\n" + + "Used by caches, or in conditional requests."), + }), + @ApiResponse( + code = 400, + message = "Bad Request. \n Invalid device status type received. \n" + + "Valid status types are NEW | CHECKED", + response = ErrorResponse.class), + @ApiResponse( + code = 404, + message = "Not Found. \n There are no devices.", + response = ErrorResponse.class), + @ApiResponse( + code = 500, + message = "Internal Server Error. " + + "\n Server error occurred while fetching the device list.", + response = ErrorResponse.class) + }) + Response getDevicesByDurationCount( + @ApiParam( + name = "status", + value = "Provide the device status details, such as active or inactive.") + @QueryParam("status") List status, + @ApiParam( + name = "ownership", + allowableValues = "BYOD, COPE", + value = "Provide the ownership status of the device. The following values can be assigned:\n" + + "- BYOD: Bring Your Own Device\n" + + "- COPE: Corporate-Owned, Personally-Enabled") + @QueryParam("ownership") String ownership, + @ApiParam( + name = "fromDate", + value = "Start date of the duration", + required = true) + @QueryParam("from") String fromDate, + @ApiParam( + name = "toDate", + value = "end date of the duration", + required = true) + @QueryParam("to") String toDate) throws ReportManagementException; } \ No newline at end of file diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java index c06542ea15d..cebd3c1cbeb 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.api/src/main/java/org/wso2/carbon/device/mgt/jaxrs/service/impl/ReportManagementServiceImpl.java @@ -23,6 +23,7 @@ import org.apache.commons.logging.LogFactory; import org.wso2.carbon.device.mgt.common.Device; import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; +import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException; import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException; import org.wso2.carbon.device.mgt.jaxrs.beans.DeviceList; import org.wso2.carbon.device.mgt.jaxrs.beans.ErrorResponse; @@ -54,13 +55,13 @@ public class ReportManagementServiceImpl implements ReportManagementService { @Path("/devices") @Override public Response getDevicesByDuration( - @QueryParam("status") String status, + @QueryParam("status") List status, @QueryParam("ownership") String ownership, @QueryParam("from") String fromDate, @QueryParam("to") String toDate, @DefaultValue("0") @QueryParam("offset") int offset, - @DefaultValue("5") + @DefaultValue("10") @QueryParam("limit") int limit) { try { RequestValidationUtil.validatePaginationParameters(offset, limit); @@ -68,15 +69,12 @@ public class ReportManagementServiceImpl implements ReportManagementService { PaginationResult result; DeviceList devices = new DeviceList(); - if (!StringUtils.isBlank(status)) { - request.setStatus(status); - } if (!StringUtils.isBlank(ownership)) { request.setOwnership(ownership); } result = DeviceMgtAPIUtils.getReportManagementService() - .getDevicesByDuration(request, fromDate, toDate); + .getDevicesByDuration(request, status, fromDate, toDate); if (result.getData().isEmpty()) { String msg = "No devices have enrolled between " + fromDate + " to " + toDate + " or doesn't match with" + @@ -94,4 +92,24 @@ public class ReportManagementServiceImpl implements ReportManagementService { new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build(); } } + + @GET + @Path("/devices/count") + @Override + public Response getDevicesByDurationCount( + @QueryParam("status") List status, + @QueryParam("ownership") String ownership, + @QueryParam("from") String fromDate, + @QueryParam("to") String toDate) { + int deviceCount; + try { + deviceCount = DeviceMgtAPIUtils.getReportManagementService().getDevicesByDurationCount(status, ownership, fromDate, toDate); + return Response.status(Response.Status.OK).entity(deviceCount).build(); + } catch (ReportManagementException 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(); + } + } } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java index b4fe1a98e46..f788508f9e4 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.common/src/main/java/org/wso2/carbon/device/mgt/common/report/mgt/ReportManagementService.java @@ -21,6 +21,8 @@ import org.wso2.carbon.device.mgt.common.PaginationRequest; import org.wso2.carbon.device.mgt.common.PaginationResult; import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException; +import java.util.List; + /** * This is the service class for reports which connects with DAO layer */ @@ -36,6 +38,9 @@ public interface ReportManagementService { * @throws {@Link DeviceManagementException} When error occurred while validating device list page size * @throws {@Link ReportManagementException} When failed to retrieve devices. */ - PaginationResult getDevicesByDuration(PaginationRequest request, String fromDate, String toDate) + PaginationResult getDevicesByDuration(PaginationRequest request, List statusList, String fromDate, String toDate) + throws ReportManagementException; + + int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate) throws ReportManagementException; } diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java index 695a9766c81..6ff205517fe 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/DeviceDAO.java @@ -552,10 +552,15 @@ public interface DeviceDAO { * */ List getDevicesByDuration(PaginationRequest request, + List statusList, int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException; + int getDevicesByDurationCount( + List statusList, String ownership, String fromDate, String toDate, int tenantId) + throws DeviceManagementDAOException; + /** * Retrieve device location information * @param deviceIdentifier Device Identifier object diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java index e316baa78c1..e8ce9b0cca1 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/GenericDeviceDAOImpl.java @@ -455,12 +455,12 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getDevicesByDuration(PaginationRequest request, int tenantId, + public List getDevicesByDuration(PaginationRequest request, List statusList, int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException { List devices; - String deviceStatus = request.getStatus(); String ownership = request.getOwnership(); + boolean isStatusProvided = false; String sql = "SELECT " + "d.ID AS DEVICE_ID, " + @@ -479,9 +479,15 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { "e.TENANT_ID = ? AND " + "e.DATE_OF_ENROLMENT BETWEEN ? AND ?"; - if (deviceStatus != null) { - sql = sql + " AND e.STATUS = ?"; + //Add the query for status + StringBuilder sqlBuilder = new StringBuilder(sql); + isStatusProvided = buildStatusQuery(statusList, sqlBuilder); + sql = sqlBuilder.toString(); + + if(statusList != null && !statusList.isEmpty()){ + isStatusProvided = true; } + if (ownership != null) { sql = sql + " AND e.OWNERSHIP = ?"; } @@ -494,8 +500,10 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { stmt.setInt(paramIdx++, tenantId); stmt.setString(paramIdx++, fromDate); stmt.setString(paramIdx++, toDate); - if (deviceStatus != null) { - stmt.setString(paramIdx++, deviceStatus); + if (isStatusProvided) { + for (String status : statusList) { + stmt.setString(paramIdx++, status); + } } if (ownership != null) { stmt.setString(paramIdx++, ownership); @@ -518,6 +526,73 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException { + int deviceCount = 0; + boolean isStatusProvided = false; + + String sql = "SELECT " + + "COUNT(d.ID) AS DEVICE_COUNT " + + "FROM DM_DEVICE AS d , DM_ENROLMENT AS e , DM_DEVICE_TYPE AS t " + + "WHERE d.ID = e.DEVICE_ID AND " + + "d.DEVICE_TYPE_ID = t.ID AND " + + "e.TENANT_ID = ? AND " + + "e.DATE_OF_ENROLMENT BETWEEN ? AND ?"; + + //Add the query for status + StringBuilder sqlBuilder = new StringBuilder(sql); + isStatusProvided = buildStatusQuery(statusList, sqlBuilder); + sql = sqlBuilder.toString(); + + if (ownership != null) { + sql = sql + " AND e.OWNERSHIP = ?"; + } + + try (Connection conn = this.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + int paramIdx = 1; + stmt.setInt(paramIdx++, tenantId); + stmt.setString(paramIdx++, fromDate); + stmt.setString(paramIdx++, toDate); + if (isStatusProvided) { + for (String status : statusList) { + stmt.setString(paramIdx++, status); + } + } + if (ownership != null) { + stmt.setString(paramIdx++, ownership); + } + try (ResultSet rs = stmt.executeQuery()) { + if (rs.next()) { + deviceCount = rs.getInt("DEVICE_COUNT"); + } + } + } catch (SQLException e) { + String msg = "Error occurred while retrieving information of all " + + "registered devices under tenant id " + tenantId; + log.error(msg, e); + throw new DeviceManagementDAOException(msg, e); + } + return deviceCount; + } + + protected boolean buildStatusQuery(List statusList, StringBuilder sqlBuilder) { + if (statusList != null && !statusList.isEmpty() && !statusList.get(0).isEmpty()) { + sqlBuilder.append(" AND e.STATUS IN("); + for (int i = 0; i < statusList.size(); i++) { + sqlBuilder.append("?"); + if (i != statusList.size() - 1) { + sqlBuilder.append(","); + } + } + sqlBuilder.append(")"); + return true; + }else { + return false; + } + } + + /** * Get the list of devices that matches with the given device name and (or) device type. * diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java index 9cd59077a93..25b37095f0b 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/OracleDeviceDAOImpl.java @@ -459,7 +459,7 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getDevicesByDuration(PaginationRequest request, int tenantId, + public List getDevicesByDuration(PaginationRequest request, List statusList, int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException { List devices; @@ -522,6 +522,11 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException { + return 0; + } + /** * Get the list of devices that matches with the given device name and (or) device type. * diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java index 044bbeb85a1..f0c53ea9c09 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/PostgreSQLDeviceDAOImpl.java @@ -438,7 +438,7 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getDevicesByDuration(PaginationRequest request, int tenantId, + public List getDevicesByDuration(PaginationRequest request, List statusList, int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException { List devices; @@ -501,6 +501,11 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException { + return 0; + } + /** * Get the list of devices that matches with the given device name and (or) device type. * diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java index 706dee61482..b7c1e30a6ad 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/dao/impl/device/SQLServerDeviceDAOImpl.java @@ -601,7 +601,7 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { } @Override - public List getDevicesByDuration(PaginationRequest request, int tenantId, + public List getDevicesByDuration(PaginationRequest request, List statusList, int tenantId, String fromDate, String toDate) throws DeviceManagementDAOException { List devices; @@ -664,6 +664,11 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl { return devices; } + @Override + public int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException { + return 0; + } + @Override public int getSubscribedDeviceCount(List deviceIds, int tenantId, String status) throws DeviceManagementDAOException { diff --git a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java index 282e11c5f9d..a1d39e29cb7 100644 --- a/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java +++ b/components/device-mgt/org.wso2.carbon.device.mgt.core/src/main/java/org/wso2/carbon/device/mgt/core/report/mgt/ReportManagementServiceImpl.java @@ -49,7 +49,7 @@ public class ReportManagementServiceImpl implements ReportManagementService { } @Override - public PaginationResult getDevicesByDuration(PaginationRequest request, String fromDate, + public PaginationResult getDevicesByDuration(PaginationRequest request, List statusList, String fromDate, String toDate) throws ReportManagementException { PaginationResult paginationResult = new PaginationResult(); @@ -64,6 +64,7 @@ public class ReportManagementServiceImpl implements ReportManagementService { DeviceManagementDAOFactory.openConnection(); List devices = deviceDAO.getDevicesByDuration( request, + statusList, DeviceManagementDAOUtil.getTenantId(), fromDate, toDate @@ -85,4 +86,23 @@ public class ReportManagementServiceImpl implements ReportManagementService { DeviceManagementDAOFactory.closeConnection(); } } + + @Override + public int getDevicesByDurationCount(List statusList, String ownership, String fromDate, String toDate) + throws ReportManagementException { + try { + DeviceManagementDAOFactory.openConnection(); + return deviceDAO.getDevicesByDurationCount(statusList, ownership, fromDate, toDate, DeviceManagementDAOUtil.getTenantId()); + } catch (DeviceManagementDAOException e) { + String msg = "Error occurred in while retrieving device count by status for " + statusList + "devices."; + log.error(msg, e); + throw new ReportManagementException(msg, e); + } catch (SQLException e) { + String msg = "Error occurred while opening a connection to the data source"; + log.error(msg, e); + throw new ReportManagementException(msg, e); + } finally { + DeviceManagementDAOFactory.closeConnection(); + } + } }