mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Implement reports for device enrollment and policy compliance
This commit is contained in:
parent
76912b6492
commit
39e3e7fa1d
@ -148,7 +148,7 @@ class App extends React.Component {
|
||||
<ConfigContext.Provider value={this.state.config}>
|
||||
<div>
|
||||
<Switch>
|
||||
<Redirect exact from="/entgra" to="/entgra/devices" />
|
||||
<Redirect exact from="/entgra" to="/entgra/reports" />
|
||||
{this.props.routes.map(route => (
|
||||
<RouteWithSubRoutes key={route.path} {...route} />
|
||||
))}
|
||||
|
||||
@ -33,28 +33,27 @@ class DateRangePicker extends React.Component {
|
||||
render() {
|
||||
const { RangePicker } = DatePicker;
|
||||
return (
|
||||
<RangePicker
|
||||
ranges={{
|
||||
Today: [moment(), moment()],
|
||||
Yesterday: [
|
||||
moment().subtract(1, 'days'),
|
||||
moment().subtract(1, 'days'),
|
||||
],
|
||||
'Last 7 Days': [moment().subtract(6, 'days'), moment()],
|
||||
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
|
||||
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
||||
'Last Month': [
|
||||
moment()
|
||||
.subtract(1, 'month')
|
||||
.startOf('month'),
|
||||
moment()
|
||||
.subtract(1, 'month')
|
||||
.endOf('month'),
|
||||
],
|
||||
}}
|
||||
format="YYYY-MM-DD"
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
<div>
|
||||
<RangePicker
|
||||
ranges={{
|
||||
Today: [moment(), moment()],
|
||||
Yesterday: [moment().subtract(1, 'days'), moment()],
|
||||
'Last 7 Days': [moment().subtract(7, 'days'), moment()],
|
||||
'Last 30 Days': [moment().subtract(30, 'days'), moment()],
|
||||
'This Month': [moment().startOf('month'), moment().endOf('month')],
|
||||
'Last Month': [
|
||||
moment()
|
||||
.subtract(1, 'month')
|
||||
.startOf('month'),
|
||||
moment()
|
||||
.subtract(1, 'month')
|
||||
.endOf('month'),
|
||||
],
|
||||
}}
|
||||
format="YYYY-MM-DD"
|
||||
onChange={this.onChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
* Copyright (c) 2020, 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
|
||||
@ -17,14 +17,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { PageHeader, Breadcrumb, Icon, Select, Button, Card } from 'antd';
|
||||
import { PageHeader, Breadcrumb, Icon, Radio, Popover, Button } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
|
||||
import PieChart from '../../../components/Reports/Widgets/PieChart';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
const { Option } = Select;
|
||||
import axios from 'axios';
|
||||
import DateRangePicker from '../DateRangePicker';
|
||||
import moment from 'moment';
|
||||
import { Chart, Geom, Axis, Tooltip, Legend } from 'bizcharts';
|
||||
import DataSet from '@antv/data-set';
|
||||
import { handleApiError } from '../../../js/Utils';
|
||||
|
||||
class DeviceStatusReport extends React.Component {
|
||||
routes;
|
||||
@ -32,37 +34,145 @@ class DeviceStatusReport extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
const { reportData } = this.props.location;
|
||||
this.state = {
|
||||
selectedTags: ['Enrolled'],
|
||||
paramsObject: {
|
||||
from: reportData.duration[0],
|
||||
to: reportData.duration[1],
|
||||
from: moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
to: moment().format('YYYY-MM-DD'),
|
||||
},
|
||||
statsObject: {},
|
||||
statArray: [
|
||||
{ item: 'ACTIVE', count: 0 },
|
||||
{ item: 'INACTIVE', count: 0 },
|
||||
{ item: 'REMOVED', count: 0 },
|
||||
],
|
||||
data: [],
|
||||
fields: [],
|
||||
durationMode: 'weekly',
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
|
||||
onClickPieChart = value => {
|
||||
console.log(value.data.point.item);
|
||||
const chartValue = value.data.point.item;
|
||||
handleDurationModeChange = e => {
|
||||
const durationMode = e.target.value;
|
||||
switch (durationMode) {
|
||||
case 'daily':
|
||||
this.updateDurationValue(
|
||||
moment().format('YYYY-MM-DD'),
|
||||
moment()
|
||||
.add(1, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'weekly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'monthly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(30, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
}
|
||||
this.setState({ durationMode });
|
||||
};
|
||||
|
||||
handlePopoverVisibleChange = visible => {
|
||||
this.setState({ visible });
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
// Get modified value from datepicker and set it to paramsObject
|
||||
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
tempParamObj.status = chartValue;
|
||||
|
||||
tempParamObj.from = modifiedFromDate;
|
||||
tempParamObj.to = modifiedToDate;
|
||||
this.setState({ paramsObject: tempParamObj });
|
||||
console.log(this.state.paramsObject);
|
||||
this.fetchData();
|
||||
};
|
||||
|
||||
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
fetchData = () => {
|
||||
this.setState({ loading: true });
|
||||
|
||||
const { paramsObject } = this.state;
|
||||
const config = this.props.context;
|
||||
|
||||
const encodedExtraParams = Object.keys(paramsObject)
|
||||
.map(key => key + '=' + paramsObject[key])
|
||||
.join('&');
|
||||
|
||||
axios
|
||||
.all([
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?status=ACTIVE&' +
|
||||
encodedExtraParams,
|
||||
'Active',
|
||||
),
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?status=INACTIVE&' +
|
||||
encodedExtraParams,
|
||||
'Inactive',
|
||||
),
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?status=REMOVED&' +
|
||||
encodedExtraParams,
|
||||
'Removed',
|
||||
),
|
||||
])
|
||||
.then(res => {
|
||||
let keys = Object.keys(res[0].data.data);
|
||||
let active = res[0].data.data;
|
||||
let inactive = res[1].data.data;
|
||||
let removed = res[2].data.data;
|
||||
|
||||
if (Object.keys(active).length != 0) {
|
||||
active.name = 'Active';
|
||||
inactive.name = 'Inactive';
|
||||
removed.name = 'Removed';
|
||||
}
|
||||
|
||||
const finalData = [active, inactive, removed];
|
||||
|
||||
this.setState({
|
||||
data: finalData,
|
||||
fields: keys,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
handleApiError(
|
||||
error,
|
||||
'Error occurred while trying to get device count.',
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { reportData } = this.props.location;
|
||||
const { durationMode } = this.state;
|
||||
|
||||
const ds = new DataSet();
|
||||
const dv = ds.createView().source(this.state.data);
|
||||
dv.transform({
|
||||
type: 'fold',
|
||||
fields: this.state.fields,
|
||||
key: 'Time',
|
||||
value: 'Number of Devices',
|
||||
});
|
||||
|
||||
const params = { ...this.state.paramsObject };
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
@ -75,45 +185,63 @@ class DeviceStatusReport extends React.Component {
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<Select
|
||||
defaultValue="android"
|
||||
style={{ width: 120, marginRight: 10 }}
|
||||
>
|
||||
<Option value="android">Android</Option>
|
||||
<Option value="ios">IOS</Option>
|
||||
<Option value="windows">Windows</Option>
|
||||
</Select>
|
||||
<Button
|
||||
onClick={this.onSubmitReport}
|
||||
style={{ marginLeft: 10 }}
|
||||
type="primary"
|
||||
>
|
||||
Generate Report
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Device Status Report</h3>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
<Radio.Group
|
||||
onChange={this.handleDurationModeChange}
|
||||
defaultValue={'weekly'}
|
||||
value={durationMode}
|
||||
style={{ marginBottom: 8, marginRight: 5 }}
|
||||
>
|
||||
<Radio.Button value={'daily'}>Today</Radio.Button>
|
||||
<Radio.Button value={'weekly'}>Last Week</Radio.Button>
|
||||
<Radio.Button value={'monthly'}>Last Month</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<Popover
|
||||
trigger="hover"
|
||||
content={
|
||||
<div>
|
||||
<DateRangePicker
|
||||
updateDurationValue={this.updateDurationValue}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.handlePopoverVisibleChange}
|
||||
>
|
||||
<Button style={{ marginRight: 10 }}>Custom Date</Button>
|
||||
</Popover>
|
||||
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: '#ffffff',
|
||||
borderRadius: 5,
|
||||
marginBottom: 10,
|
||||
height: window.innerHeight * 0.5,
|
||||
marginTop: 10,
|
||||
}}
|
||||
>
|
||||
<PieChart
|
||||
onClickPieChart={this.onClickPieChart}
|
||||
reportData={reportData}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||
<ReportDeviceTable paramsObject={params} />
|
||||
<Chart height={400} data={dv} forceFit>
|
||||
<Axis name="Time" />
|
||||
<Axis name="Number of Devices" />
|
||||
<Legend />
|
||||
<Tooltip
|
||||
crosshairs={{
|
||||
type: 'y',
|
||||
}}
|
||||
/>
|
||||
<Geom
|
||||
type="interval"
|
||||
position="Time*Number of Devices"
|
||||
color={'name'}
|
||||
adjust={[
|
||||
{
|
||||
type: 'dodge',
|
||||
marginRatio: 1 / 32,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Chart>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
* Copyright (c) 2020, 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
|
||||
@ -17,12 +17,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
|
||||
import { PageHeader, Breadcrumb, Icon, Radio, Popover, Button } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
|
||||
import PieChart from '../../../components/Reports/Widgets/PieChart';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
import axios from 'axios';
|
||||
import DateRangePicker from '../DateRangePicker';
|
||||
import moment from 'moment';
|
||||
import { Chart, Geom, Axis, Tooltip, Legend } from 'bizcharts';
|
||||
import DataSet from '@antv/data-set';
|
||||
import { handleApiError } from '../../../js/Utils';
|
||||
|
||||
class EnrollmentTypeReport extends React.Component {
|
||||
routes;
|
||||
@ -30,32 +34,134 @@ class EnrollmentTypeReport extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
const { reportData } = this.props.location;
|
||||
this.state = {
|
||||
paramsObject: {
|
||||
from: reportData.duration[0],
|
||||
to: reportData.duration[1],
|
||||
from: moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
to: moment().format('YYYY-MM-DD'),
|
||||
},
|
||||
data: [],
|
||||
fields: [],
|
||||
durationMode: 'weekly',
|
||||
visible: false,
|
||||
};
|
||||
|
||||
console.log(reportData.duration);
|
||||
}
|
||||
|
||||
onClickPieChart = value => {
|
||||
const chartValue = value.data.point.item;
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
handleDurationModeChange = e => {
|
||||
const durationMode = e.target.value;
|
||||
switch (durationMode) {
|
||||
case 'daily':
|
||||
this.updateDurationValue(
|
||||
moment().format('YYYY-MM-DD'),
|
||||
moment()
|
||||
.add(1, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'weekly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'monthly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(30, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
}
|
||||
this.setState({ durationMode });
|
||||
};
|
||||
|
||||
handlePopoverVisibleChange = visible => {
|
||||
this.setState({ visible });
|
||||
};
|
||||
|
||||
// Get modified value from datepicker and set it to paramsObject
|
||||
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
console.log(chartValue);
|
||||
|
||||
tempParamObj.ownership = chartValue;
|
||||
|
||||
tempParamObj.from = modifiedFromDate;
|
||||
tempParamObj.to = modifiedToDate;
|
||||
this.setState({ paramsObject: tempParamObj });
|
||||
this.fetchData();
|
||||
};
|
||||
|
||||
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
fetchData = () => {
|
||||
this.setState({ loading: true });
|
||||
|
||||
const { paramsObject } = this.state;
|
||||
const config = this.props.context;
|
||||
|
||||
const encodedExtraParams = Object.keys(paramsObject)
|
||||
.map(key => key + '=' + paramsObject[key])
|
||||
.join('&');
|
||||
|
||||
axios
|
||||
.all([
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?ownership=BYOD&' +
|
||||
encodedExtraParams,
|
||||
'BYOD',
|
||||
),
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?ownership=COPE&' +
|
||||
encodedExtraParams,
|
||||
'COPE',
|
||||
),
|
||||
])
|
||||
.then(res => {
|
||||
let keys = Object.keys(res[0].data.data);
|
||||
let byod = res[0].data.data;
|
||||
let cope = res[1].data.data;
|
||||
if (Object.keys(byod).length != 0) {
|
||||
byod.name = 'BYOD';
|
||||
cope.name = 'COPE';
|
||||
}
|
||||
|
||||
const finalData = [byod, cope];
|
||||
|
||||
this.setState({
|
||||
data: finalData,
|
||||
fields: keys,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
handleApiError(
|
||||
error,
|
||||
'Error occurred while trying to get device count.',
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { reportData } = this.props.location;
|
||||
const { durationMode } = this.state;
|
||||
|
||||
const ds = new DataSet();
|
||||
const dv = ds.createView().source(this.state.data);
|
||||
dv.transform({
|
||||
type: 'fold',
|
||||
fields: this.state.fields,
|
||||
key: 'Time',
|
||||
value: 'Number of Devices',
|
||||
});
|
||||
|
||||
const params = { ...this.state.paramsObject };
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
@ -68,28 +174,62 @@ class EnrollmentTypeReport extends React.Component {
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
</div>
|
||||
<h3>Device Enrollment Type Report</h3>
|
||||
<Radio.Group
|
||||
onChange={this.handleDurationModeChange}
|
||||
defaultValue={'weekly'}
|
||||
value={durationMode}
|
||||
style={{ marginBottom: 8, marginRight: 5 }}
|
||||
>
|
||||
<Radio.Button value={'daily'}>Today</Radio.Button>
|
||||
<Radio.Button value={'weekly'}>Last Week</Radio.Button>
|
||||
<Radio.Button value={'monthly'}>Last Month</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
<Popover
|
||||
trigger="hover"
|
||||
content={
|
||||
<div>
|
||||
<DateRangePicker
|
||||
updateDurationValue={this.updateDurationValue}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.handlePopoverVisibleChange}
|
||||
>
|
||||
<Button style={{ marginRight: 10 }}>Custom Date</Button>
|
||||
</Popover>
|
||||
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: '#ffffff',
|
||||
borderRadius: 5,
|
||||
marginBottom: 10,
|
||||
height: window.innerHeight * 0.5,
|
||||
marginTop: 10,
|
||||
}}
|
||||
>
|
||||
<PieChart
|
||||
onClickPieChart={this.onClickPieChart}
|
||||
reportData={reportData}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||
<ReportDeviceTable paramsObject={params} />
|
||||
<Chart height={400} data={dv} forceFit>
|
||||
<Axis name="Time" />
|
||||
<Axis name="Number of Devices" />
|
||||
<Legend />
|
||||
<Tooltip
|
||||
crosshairs={{
|
||||
type: 'y',
|
||||
}}
|
||||
/>
|
||||
<Geom
|
||||
type="interval"
|
||||
position="Time*Number of Devices"
|
||||
color={'name'}
|
||||
adjust={[
|
||||
{
|
||||
type: 'dodge',
|
||||
marginRatio: 1 / 32,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Chart>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||
* Copyright (c) 2020, 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
|
||||
@ -17,12 +17,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { PageHeader, Breadcrumb, Icon, Card } from 'antd';
|
||||
import { PageHeader, Breadcrumb, Icon, Radio, Popover, Button } from 'antd';
|
||||
|
||||
import { Link, Redirect } from 'react-router-dom';
|
||||
import ReportDeviceTable from '../../../components/Devices/ReportDevicesTable';
|
||||
import PieChart from '../../../components/Reports/Widgets/PieChart';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
import axios from 'axios';
|
||||
import DateRangePicker from '../DateRangePicker';
|
||||
import moment from 'moment';
|
||||
import { Chart, Geom, Axis, Tooltip, Legend } from 'bizcharts';
|
||||
import DataSet from '@antv/data-set';
|
||||
import { handleApiError } from '../../../js/Utils';
|
||||
|
||||
class EnrollmentsVsUnenrollmentsReport extends React.Component {
|
||||
routes;
|
||||
@ -30,94 +34,208 @@ class EnrollmentsVsUnenrollmentsReport extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
const { reportData } = this.props.location;
|
||||
|
||||
this.state = {
|
||||
paramsObject: {
|
||||
from: reportData ? reportData.duration[0] : '2019-01-01',
|
||||
to: reportData ? reportData.duration[1] : '2019-01-01',
|
||||
from: moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
to: moment().format('YYYY-MM-DD'),
|
||||
},
|
||||
redirect: false,
|
||||
data: [],
|
||||
fields: [],
|
||||
durationMode: 'weekly',
|
||||
visible: false,
|
||||
};
|
||||
|
||||
this.redirectToHome();
|
||||
console.log(this.state.paramsObject);
|
||||
}
|
||||
|
||||
redirectToHome = () => {
|
||||
return <Redirect to="/entgra" />;
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
handleDurationModeChange = e => {
|
||||
const durationMode = e.target.value;
|
||||
switch (durationMode) {
|
||||
case 'daily':
|
||||
this.updateDurationValue(
|
||||
moment().format('YYYY-MM-DD'),
|
||||
moment()
|
||||
.add(1, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'weekly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'monthly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(30, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
}
|
||||
this.setState({ durationMode });
|
||||
};
|
||||
|
||||
onClickPieChart = value => {
|
||||
const chartValue = value.data.point.item;
|
||||
handlePopoverVisibleChange = visible => {
|
||||
this.setState({ visible });
|
||||
};
|
||||
|
||||
// Get modified value from datepicker and set it to paramsObject
|
||||
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
|
||||
let tempParamObj = this.state.paramsObject;
|
||||
|
||||
console.log(chartValue);
|
||||
|
||||
if (chartValue === 'Enrollments') {
|
||||
tempParamObj.status = 'ACTIVE&status=INACTIVE';
|
||||
} else {
|
||||
tempParamObj.status = 'REMOVED';
|
||||
}
|
||||
|
||||
tempParamObj.from = modifiedFromDate;
|
||||
tempParamObj.to = modifiedToDate;
|
||||
this.setState({ paramsObject: tempParamObj });
|
||||
this.fetchData();
|
||||
};
|
||||
|
||||
// Call count APIs and get count for given parameters, then create data object to build pie chart
|
||||
fetchData = () => {
|
||||
this.setState({ loading: true });
|
||||
|
||||
const { paramsObject } = this.state;
|
||||
const config = this.props.context;
|
||||
|
||||
const encodedExtraParams = Object.keys(paramsObject)
|
||||
.map(key => key + '=' + paramsObject[key])
|
||||
.join('&');
|
||||
|
||||
axios
|
||||
.all([
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?status=ACTIVE&status=INACTIVE&' +
|
||||
encodedExtraParams,
|
||||
'Enrollments',
|
||||
),
|
||||
axios.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/count?status=REMOVED&' +
|
||||
encodedExtraParams,
|
||||
'Unenrollments',
|
||||
),
|
||||
])
|
||||
.then(res => {
|
||||
let keys = Object.keys(res[0].data.data);
|
||||
let enrollments = res[0].data.data;
|
||||
let unenrollments = res[1].data.data;
|
||||
if (Object.keys(enrollments).length != 0) {
|
||||
enrollments.name = 'Enrollments';
|
||||
unenrollments.name = 'Unenrollments';
|
||||
}
|
||||
|
||||
const finalData = [enrollments, unenrollments];
|
||||
|
||||
this.setState({
|
||||
data: finalData,
|
||||
fields: keys,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
handleApiError(
|
||||
error,
|
||||
'Error occurred while trying to get device count.',
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { reportData } = this.props.location;
|
||||
const { durationMode } = this.state;
|
||||
|
||||
console.log('======');
|
||||
console.log(reportData);
|
||||
console.log('======');
|
||||
const ds = new DataSet();
|
||||
const dv = ds.createView().source(this.state.data);
|
||||
dv.transform({
|
||||
type: 'fold',
|
||||
fields: this.state.fields,
|
||||
key: 'Time',
|
||||
value: 'Number of Devices',
|
||||
});
|
||||
|
||||
let reportDataClone = {
|
||||
params: ['ACTIVE'],
|
||||
duration: ['2020-01-01', '2020-01-01'],
|
||||
};
|
||||
|
||||
const params = { ...this.state.paramsObject };
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
{!reportData ? (
|
||||
<Redirect to="/entgra/reports" />
|
||||
) : (
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Summary of enrollments</h3>
|
||||
</div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Enrollments vs Unenrollments Report</h3>
|
||||
|
||||
<div>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{
|
||||
borderRadius: 5,
|
||||
marginBottom: 10,
|
||||
height: window.innerHeight * 0.5,
|
||||
}}
|
||||
>
|
||||
<PieChart
|
||||
onClickPieChart={this.onClickPieChart}
|
||||
reportData={reportData ? reportData : reportDataClone}
|
||||
<Radio.Group
|
||||
onChange={this.handleDurationModeChange}
|
||||
defaultValue={'weekly'}
|
||||
value={durationMode}
|
||||
style={{ marginBottom: 8, marginRight: 5 }}
|
||||
>
|
||||
<Radio.Button value={'daily'}>Today</Radio.Button>
|
||||
<Radio.Button value={'weekly'}>Last Week</Radio.Button>
|
||||
<Radio.Button value={'monthly'}>Last Month</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<Popover
|
||||
trigger="hover"
|
||||
content={
|
||||
<div>
|
||||
<DateRangePicker
|
||||
updateDurationValue={this.updateDurationValue}
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.handlePopoverVisibleChange}
|
||||
>
|
||||
<Button style={{ marginRight: 10 }}>Custom Date</Button>
|
||||
</Popover>
|
||||
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||
<ReportDeviceTable paramsObject={params} />
|
||||
</div>
|
||||
</PageHeader>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: '#ffffff',
|
||||
borderRadius: 5,
|
||||
marginTop: 10,
|
||||
}}
|
||||
>
|
||||
<Chart height={400} data={dv} forceFit>
|
||||
<Axis name="Time" />
|
||||
<Axis name="Number of Devices" />
|
||||
<Legend />
|
||||
<Tooltip
|
||||
crosshairs={{
|
||||
type: 'y',
|
||||
}}
|
||||
/>
|
||||
<Geom
|
||||
type="interval"
|
||||
position="Time*Number of Devices"
|
||||
color={'name'}
|
||||
adjust={[
|
||||
{
|
||||
type: 'dodge',
|
||||
marginRatio: 1 / 32,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Chart>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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, Breadcrumb, Icon, Radio, Popover, Button } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
import PolicyDevicesTable from '../Widgets/PolicyDevicesTable';
|
||||
import moment from 'moment';
|
||||
import DateRangePicker from '../DateRangePicker';
|
||||
import SelectPolicyDropDown from '../Widgets/SelectPolicyDropDown';
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let config = null;
|
||||
|
||||
class PolicyReport extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
config = this.props.context;
|
||||
this.state = {
|
||||
durationMode: 'weekly',
|
||||
isCompliant: true,
|
||||
// This object contains parameters which pass into API endpoint
|
||||
policyReportData: {
|
||||
from: moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
to: moment().format('YYYY-MM-DD'),
|
||||
},
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
|
||||
handleModeChange = e => {
|
||||
const isCompliant = e.target.value;
|
||||
this.setState({ isCompliant });
|
||||
};
|
||||
|
||||
handleDurationModeChange = e => {
|
||||
const durationMode = e.target.value;
|
||||
switch (durationMode) {
|
||||
case 'daily':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(1, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'weekly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(7, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
case 'monthly':
|
||||
this.updateDurationValue(
|
||||
moment()
|
||||
.subtract(30, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
moment().format('YYYY-MM-DD'),
|
||||
);
|
||||
break;
|
||||
}
|
||||
this.setState({ durationMode });
|
||||
};
|
||||
|
||||
hidePopover = () => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
};
|
||||
|
||||
handlePopoverVisibleChange = visible => {
|
||||
this.setState({ visible });
|
||||
};
|
||||
|
||||
getPolicyId = policyId => {
|
||||
let tempParamObj = this.state.policyReportData;
|
||||
if (policyId === 'all') {
|
||||
delete tempParamObj.policy;
|
||||
} else {
|
||||
tempParamObj.policy = policyId;
|
||||
}
|
||||
this.setState({ policyReportData: tempParamObj });
|
||||
};
|
||||
|
||||
// Get modified value from datepicker and set it to paramsObject
|
||||
updateDurationValue = (modifiedFromDate, modifiedToDate) => {
|
||||
let tempParamObj = this.state.policyReportData;
|
||||
tempParamObj.from = modifiedFromDate;
|
||||
tempParamObj.to = modifiedToDate;
|
||||
this.setState({ policyReportData: tempParamObj });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { isCompliant, durationMode } = this.state;
|
||||
const policyData = { ...this.state.policyReportData };
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Policy Report</h3>
|
||||
|
||||
<Radio.Group
|
||||
onChange={this.handleModeChange}
|
||||
defaultValue={true}
|
||||
value={isCompliant}
|
||||
style={{ marginBottom: 8, marginRight: 10 }}
|
||||
>
|
||||
<Radio.Button value={true}>Policy Compliant Devices</Radio.Button>
|
||||
<Radio.Button value={false}>
|
||||
Policy Non-Compliant Devices
|
||||
</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<Radio.Group
|
||||
onChange={this.handleDurationModeChange}
|
||||
defaultValue={'weekly'}
|
||||
value={durationMode}
|
||||
style={{ marginBottom: 8, marginRight: 5 }}
|
||||
>
|
||||
<Radio.Button value={'daily'}>Today</Radio.Button>
|
||||
<Radio.Button value={'weekly'}>Last Week</Radio.Button>
|
||||
<Radio.Button value={'monthly'}>Last Month</Radio.Button>
|
||||
</Radio.Group>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
content={
|
||||
<div>
|
||||
<DateRangePicker
|
||||
updateDurationValue={this.updateDurationValue}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
visible={this.state.visible}
|
||||
onVisibleChange={this.handlePopoverVisibleChange}
|
||||
>
|
||||
<Button style={{ marginRight: 10 }}>Custom Date</Button>
|
||||
</Popover>
|
||||
|
||||
<SelectPolicyDropDown getPolicyId={this.getPolicyId} />
|
||||
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||
<PolicyDevicesTable
|
||||
policyReportData={policyData}
|
||||
isCompliant={isCompliant}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(PolicyReport);
|
||||
@ -33,8 +33,6 @@ class CountWidget extends React.Component {
|
||||
<b>{data.item}</b>
|
||||
</h2>
|
||||
<h1>{data.count}</h1>
|
||||
{/* <p>{data.duration}</p>*/}
|
||||
{/* <ReportFilterModal/>*/}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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, message, Modal, notification, List, Typography } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
class FeatureListModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
modalVisible: false,
|
||||
name: '',
|
||||
description: '',
|
||||
features: [],
|
||||
};
|
||||
}
|
||||
|
||||
fetchViolatedFeatures = id => {
|
||||
const config = this.props.context;
|
||||
|
||||
axios
|
||||
.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices/' +
|
||||
id +
|
||||
'/features',
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
this.setState({
|
||||
features: JSON.parse(res.data.data),
|
||||
});
|
||||
}
|
||||
})
|
||||
.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 non compliance feature list.',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
openModal = () => {
|
||||
this.fetchViolatedFeatures(this.props.id);
|
||||
this.setState({
|
||||
modalVisible: true,
|
||||
});
|
||||
};
|
||||
|
||||
handleOk = e => {
|
||||
this.setState({
|
||||
modalVisible: false,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { features, modalVisible } = this.state;
|
||||
|
||||
let featureList = features.map(data => (
|
||||
<List.Item key={data.featureCodes}>
|
||||
<Typography.Text key={data.featureCodes} mark>
|
||||
{data.featureCode}
|
||||
</Typography.Text>
|
||||
</List.Item>
|
||||
));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>
|
||||
<Button
|
||||
type="primary"
|
||||
size={'small'}
|
||||
icon="book"
|
||||
onClick={this.openModal}
|
||||
>
|
||||
Violated Features
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Modal
|
||||
title="VIOLATED FEATURES"
|
||||
width="40%"
|
||||
visible={modalVisible}
|
||||
onOk={this.handleOk}
|
||||
footer={[
|
||||
<Button key="submit" type="primary" onClick={this.handleOk}>
|
||||
OK
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<List size="large" bordered>
|
||||
{featureList}
|
||||
</List>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(FeatureListModal);
|
||||
@ -39,8 +39,6 @@ class PieChart extends React.Component {
|
||||
duration: reportData.duration,
|
||||
};
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
if (reportData.params[0] === 'Enrollments') {
|
||||
this.getEnrollmentsVsUnenrollmentsCount(params, urlSet);
|
||||
} else if (reportData.params[0] === 'BYOD') {
|
||||
@ -50,10 +48,6 @@ class PieChart extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
clicked = () => {
|
||||
console.log('Clicked...!!');
|
||||
};
|
||||
|
||||
onChartChange = data => {
|
||||
this.props.onClickPieChart(data);
|
||||
};
|
||||
@ -66,8 +60,6 @@ class PieChart extends React.Component {
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map(data => {
|
||||
@ -76,7 +68,6 @@ class PieChart extends React.Component {
|
||||
from: urlSet.duration[0],
|
||||
to: urlSet.duration[1],
|
||||
};
|
||||
// console.log(paramsObj)
|
||||
const encodedExtraParams = Object.keys(paramsObj)
|
||||
.map(key => key + '=' + paramsObj[key])
|
||||
.join('&');
|
||||
@ -90,8 +81,6 @@ class PieChart extends React.Component {
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray);
|
||||
|
||||
axios
|
||||
.all(urlArray)
|
||||
.then(res => {
|
||||
@ -128,8 +117,6 @@ class PieChart extends React.Component {
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map(data => {
|
||||
@ -161,8 +148,6 @@ class PieChart extends React.Component {
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray);
|
||||
|
||||
axios
|
||||
.all(urlArray)
|
||||
.then(res => {
|
||||
@ -199,8 +184,6 @@ class PieChart extends React.Component {
|
||||
|
||||
let { statArray } = this.state;
|
||||
|
||||
console.log(urlSet);
|
||||
|
||||
const urlArray = [];
|
||||
|
||||
urlSet.paramsList.map(data => {
|
||||
@ -222,8 +205,6 @@ class PieChart extends React.Component {
|
||||
urlArray.push(axios.get(apiUrl, data));
|
||||
});
|
||||
|
||||
console.log(urlArray);
|
||||
|
||||
axios
|
||||
.all(urlArray)
|
||||
.then(res => {
|
||||
|
||||
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 axios from 'axios';
|
||||
import { Button, Icon, Table, Tooltip } from 'antd';
|
||||
import TimeAgo from 'javascript-time-ago';
|
||||
import moment from 'moment';
|
||||
// Load locale-specific relative date/time formatting rules.
|
||||
import en from 'javascript-time-ago/locale/en';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
import FeatureListModal from './FeatureListModal';
|
||||
import { handleApiError } from '../../../js/Utils';
|
||||
|
||||
let config = null;
|
||||
|
||||
// Table columns for non compliant devices
|
||||
const columnsNonCompliant = [
|
||||
{
|
||||
title: 'Device',
|
||||
dataIndex: 'deviceName',
|
||||
width: 100,
|
||||
sorter: (a, b) => a.deviceName.localeCompare(b.deviceName),
|
||||
},
|
||||
{
|
||||
title: 'Type',
|
||||
dataIndex: 'deviceType',
|
||||
key: 'type',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: type => {
|
||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||
let icon = defaultPlatformIcons.default.icon;
|
||||
let color = defaultPlatformIcons.default.color;
|
||||
let theme = defaultPlatformIcons.default.theme;
|
||||
|
||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
||||
icon = defaultPlatformIcons[type].icon;
|
||||
color = defaultPlatformIcons[type].color;
|
||||
theme = defaultPlatformIcons[type].theme;
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
||||
<Icon type={icon} theme={theme} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
},
|
||||
{
|
||||
title: 'Policy',
|
||||
dataIndex: 'policyName',
|
||||
key: 'policy',
|
||||
sorter: (a, b) => a.policyName.localeCompare(b.policyName),
|
||||
},
|
||||
{
|
||||
title: 'Last Failed Time',
|
||||
dataIndex: 'lastFailedTime',
|
||||
key: 'lastFailedTime',
|
||||
render: data => {
|
||||
if (data) {
|
||||
return (
|
||||
<Tooltip title={new Date(data).toString()}>
|
||||
{moment(data).fromNow()}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return 'Not available';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Last Success Time',
|
||||
dataIndex: 'lastSucceededTime',
|
||||
key: 'lastSucceededTime',
|
||||
render: data => {
|
||||
if (data) {
|
||||
return (
|
||||
<Tooltip title={new Date(data).toString()}>
|
||||
{moment(data).fromNow()}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return 'Not available';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Attempts',
|
||||
dataIndex: 'attempts',
|
||||
key: 'attempts',
|
||||
},
|
||||
{
|
||||
title: 'Violated Features',
|
||||
dataIndex: 'id',
|
||||
key: 'violated_features',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: id => <FeatureListModal id={id} />,
|
||||
},
|
||||
{
|
||||
title: 'Device Details',
|
||||
dataIndex: 'id',
|
||||
key: 'device_details',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: id => (
|
||||
<Button type="primary" size={'small'} icon="book">
|
||||
Device Details
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// Table columns for compliant devices
|
||||
const columnsCompliant = [
|
||||
{
|
||||
title: 'Device',
|
||||
dataIndex: 'deviceName',
|
||||
width: 100,
|
||||
sorter: (a, b) => a.deviceName.localeCompare(b.deviceName),
|
||||
},
|
||||
{
|
||||
title: 'Type',
|
||||
dataIndex: 'deviceType',
|
||||
key: 'type',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: type => {
|
||||
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||
let icon = defaultPlatformIcons.default.icon;
|
||||
let color = defaultPlatformIcons.default.color;
|
||||
let theme = defaultPlatformIcons.default.theme;
|
||||
|
||||
if (defaultPlatformIcons.hasOwnProperty(type)) {
|
||||
icon = defaultPlatformIcons[type].icon;
|
||||
color = defaultPlatformIcons[type].color;
|
||||
theme = defaultPlatformIcons[type].theme;
|
||||
}
|
||||
|
||||
return (
|
||||
<span style={{ fontSize: 20, color: color, textAlign: 'center' }}>
|
||||
<Icon type={icon} theme={theme} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
dataIndex: 'owner',
|
||||
key: 'owner',
|
||||
},
|
||||
{
|
||||
title: 'Policy',
|
||||
dataIndex: 'policyName',
|
||||
key: 'policy',
|
||||
sorter: (a, b) => a.policyName.localeCompare(b.policyName),
|
||||
},
|
||||
{
|
||||
title: 'Last Success Time',
|
||||
dataIndex: 'lastSucceededTime',
|
||||
key: 'lastSucceededTime',
|
||||
render: data => {
|
||||
if (data) {
|
||||
return (
|
||||
<Tooltip title={new Date(data).toString()}>
|
||||
{moment(data).fromNow()}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return 'Not available';
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Attempts',
|
||||
dataIndex: 'attempts',
|
||||
key: 'attempts',
|
||||
},
|
||||
{
|
||||
title: 'Device Details',
|
||||
dataIndex: 'id',
|
||||
key: 'device_details',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: id => (
|
||||
<Button type="primary" size={'small'} icon="book">
|
||||
Device Details
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
class PolicyDevicesTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
config = this.props.context;
|
||||
TimeAgo.addLocale(en);
|
||||
this.state = {
|
||||
data: [],
|
||||
pagination: {},
|
||||
loading: false,
|
||||
selectedRows: [],
|
||||
paramsObj: {},
|
||||
};
|
||||
}
|
||||
|
||||
rowSelection = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
this.setState({
|
||||
selectedRows: selectedRows,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchData();
|
||||
}
|
||||
|
||||
// Rerender component when parameters change
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (
|
||||
prevProps.isCompliant !== this.props.isCompliant ||
|
||||
prevProps.policyReportData !== this.props.policyReportData
|
||||
) {
|
||||
this.fetchData();
|
||||
}
|
||||
}
|
||||
|
||||
// fetch data from api
|
||||
fetchData = (params = {}) => {
|
||||
// const policyReportData = this.props;
|
||||
this.setState({ loading: true });
|
||||
// get current page
|
||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||
|
||||
let extraParams;
|
||||
|
||||
if (this.props.policyReportData.policy) {
|
||||
extraParams = {
|
||||
policy: this.props.policyReportData.policy,
|
||||
from: this.props.policyReportData.from,
|
||||
to: this.props.policyReportData.to,
|
||||
offset: 10 * (currentPage - 1), // calculate the offset
|
||||
limit: 10,
|
||||
};
|
||||
} else {
|
||||
extraParams = {
|
||||
from: this.props.policyReportData.from,
|
||||
to: this.props.policyReportData.to,
|
||||
offset: 10 * (currentPage - 1), // calculate the offset
|
||||
limit: 10,
|
||||
};
|
||||
}
|
||||
|
||||
const encodedExtraParams = Object.keys(extraParams)
|
||||
.map(key => key + '=' + extraParams[key])
|
||||
.join('&');
|
||||
|
||||
let apiUrl;
|
||||
|
||||
if (this.props.isCompliant) {
|
||||
apiUrl =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices/compliance/true?' +
|
||||
encodedExtraParams;
|
||||
} else {
|
||||
apiUrl =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices/compliance/false?' +
|
||||
encodedExtraParams;
|
||||
}
|
||||
|
||||
// send request to the invoker
|
||||
axios
|
||||
.get(apiUrl)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
const pagination = { ...this.state.pagination };
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data.data,
|
||||
pagination,
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
handleApiError(error, 'Error occurred while trying to load devices.');
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
};
|
||||
|
||||
handleTableChange = (pagination, filters, sorter) => {
|
||||
const pager = { ...this.state.pagination };
|
||||
pager.current = pagination.current;
|
||||
this.setState({
|
||||
pagination: pager,
|
||||
});
|
||||
this.fetchData({
|
||||
results: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
...filters,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let { data, pagination, loading } = this.state;
|
||||
const { isCompliant } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={isCompliant ? columnsCompliant : columnsNonCompliant}
|
||||
rowKey={record => record.id}
|
||||
dataSource={data.complianceData}
|
||||
pagination={{
|
||||
...pagination,
|
||||
size: 'small',
|
||||
// position: "top",
|
||||
total: data.count,
|
||||
showTotal: (total, range) =>
|
||||
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||
// showQuickJumper: true
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(PolicyDevicesTable);
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 { Select, message, notification } from 'antd';
|
||||
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
import axios from 'axios';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class SelectPolicyDropDown extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
currentPage: 1,
|
||||
data: [],
|
||||
pagination: {},
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchPolicies();
|
||||
}
|
||||
|
||||
// fetch data from api
|
||||
fetchPolicies = (params = {}) => {
|
||||
const config = this.props.context;
|
||||
this.setState({ loading: true });
|
||||
|
||||
// send request to the invokerss
|
||||
axios
|
||||
.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/policies',
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: JSON.parse(res.data.data),
|
||||
});
|
||||
}
|
||||
})
|
||||
.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 policies.',
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
};
|
||||
|
||||
handleChange = value => {
|
||||
this.props.getPolicyId(value);
|
||||
};
|
||||
|
||||
render() {
|
||||
let item;
|
||||
if (this.state.data) {
|
||||
item = this.state.data.map(data => (
|
||||
<Select.Option value={data.id} key={data.id}>
|
||||
{data.profile.profileName}
|
||||
</Select.Option>
|
||||
));
|
||||
}
|
||||
|
||||
return (
|
||||
<Select
|
||||
defaultValue="all"
|
||||
style={{ width: 200 }}
|
||||
onChange={this.handleChange}
|
||||
>
|
||||
<Option value="all">All</Option>
|
||||
{item}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(SelectPolicyDropDown);
|
||||
@ -23,21 +23,14 @@ import App from './App';
|
||||
import Login from './pages/Login';
|
||||
import Dashboard from './pages/Dashboard/Dashboard';
|
||||
import './index.css';
|
||||
import Devices from './pages/Dashboard/Devices/Devices';
|
||||
import Reports from './pages/Dashboard/Reports/Reports';
|
||||
import Geo from './pages/Dashboard/Geo/Geo';
|
||||
import Groups from './pages/Dashboard/Groups/Groups';
|
||||
import Users from './pages/Dashboard/Users/Users';
|
||||
import Policies from './pages/Dashboard/Policies/Policies';
|
||||
import Roles from './pages/Dashboard/Roles/Roles';
|
||||
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';
|
||||
import PolicyReport from './components/Reports/Templates/PolicyReport';
|
||||
import DeviceStatusReport from './components/Reports/Templates/DeviceStatusReport';
|
||||
import PolicyReportHome from './pages/Dashboard/Reports/PolicyReportHome';
|
||||
import ReportDurationItemList from './pages/Dashboard/Reports/ReportDurationItemList';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -50,16 +43,16 @@ const routes = [
|
||||
exact: false,
|
||||
component: Dashboard,
|
||||
routes: [
|
||||
{
|
||||
path: '/entgra/devices',
|
||||
component: Devices,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/devices/enroll',
|
||||
component: DeviceEnroll,
|
||||
exact: true,
|
||||
},
|
||||
// {
|
||||
// path: '/entgra/devices',
|
||||
// component: Devices,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/devices/enroll',
|
||||
// component: DeviceEnroll,
|
||||
// exact: true,
|
||||
// },
|
||||
{
|
||||
path: '/entgra/geo',
|
||||
component: Geo,
|
||||
@ -70,58 +63,68 @@ const routes = [
|
||||
component: Reports,
|
||||
exact: true,
|
||||
},
|
||||
// {
|
||||
// path: '/entgra/groups',
|
||||
// component: Groups,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/users',
|
||||
// component: Users,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/policies',
|
||||
// component: Policies,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/policy/add',
|
||||
// component: AddNewPolicy,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/roles',
|
||||
// component: Roles,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/devicetypes',
|
||||
// component: DeviceTypes,
|
||||
// exact: true,
|
||||
// },
|
||||
// {
|
||||
// path: '/entgra/certificates',
|
||||
// component: Certificates,
|
||||
// exact: true,
|
||||
// },
|
||||
{
|
||||
path: '/entgra/groups',
|
||||
component: Groups,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/users',
|
||||
component: Users,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/policies',
|
||||
component: Policies,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/policy/add',
|
||||
component: AddNewPolicy,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/roles',
|
||||
component: Roles,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/devicetypes',
|
||||
component: DeviceTypes,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/certificates',
|
||||
component: Certificates,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/reportList',
|
||||
path: '/entgra/reports/list',
|
||||
component: ReportDurationItemList,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/enrollmentsvsunenrollments',
|
||||
path: '/entgra/reports/enrollments',
|
||||
component: EnrollmentsVsUnenrollmentsReport,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/enrollmenttype',
|
||||
path: '/entgra/reports/enrollment-type',
|
||||
component: EnrollmentTypeReport,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/devicestatus',
|
||||
path: '/entgra/reports/policy',
|
||||
component: PolicyReportHome,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/reports/policy/compliance',
|
||||
component: PolicyReport,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/reports/device-status',
|
||||
component: DeviceStatusReport,
|
||||
exact: true,
|
||||
},
|
||||
|
||||
45
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/js/Utils.js
vendored
Normal file
45
components/device-mgt/io.entgra.device.mgt.ui/react-app/src/js/Utils.js
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 { message, notification } from 'antd';
|
||||
|
||||
export const handleApiError = (
|
||||
error,
|
||||
errorMessage,
|
||||
isForbiddenMessageSilent = false,
|
||||
) => {
|
||||
if (error.hasOwnProperty('response') && error.response.status === 401) {
|
||||
message.error('You are not logged in');
|
||||
const redirectUrl = encodeURI(window.location.href);
|
||||
window.location.href =
|
||||
window.location.origin + `/entgra/login?redirect=${redirectUrl}`;
|
||||
// silence 403 forbidden message
|
||||
} else if (
|
||||
!(
|
||||
isForbiddenMessageSilent &&
|
||||
error.hasOwnProperty('response') &&
|
||||
error.response.status === 403
|
||||
)
|
||||
) {
|
||||
notification.error({
|
||||
message: 'There was a problem',
|
||||
duration: 10,
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -59,7 +59,7 @@ class Dashboard extends React.Component {
|
||||
<Layout>
|
||||
<Header style={{ background: '#fff', padding: 0 }}>
|
||||
<div className="logo-image">
|
||||
<Link to="/entgra/devices">
|
||||
<Link to="/entgra/reports">
|
||||
<img alt="logo" src={this.logo} />
|
||||
</Link>
|
||||
</div>
|
||||
@ -72,26 +72,26 @@ class Dashboard extends React.Component {
|
||||
marginRight: 110,
|
||||
}}
|
||||
>
|
||||
<SubMenu
|
||||
key="devices"
|
||||
title={
|
||||
<span>
|
||||
<Icon type="appstore" />
|
||||
<span>Devices</span>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Menu.Item key="devices">
|
||||
<Link to="/entgra/devices">
|
||||
<span>View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="deviceEnroll">
|
||||
<Link to="/entgra/devices/enroll">
|
||||
<span>Enroll</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
{/* <SubMenu*/}
|
||||
{/* key="devices"*/}
|
||||
{/* title={*/}
|
||||
{/* <span>*/}
|
||||
{/* <Icon type="appstore" />*/}
|
||||
{/* <span>Devices</span>*/}
|
||||
{/* </span>*/}
|
||||
{/* }*/}
|
||||
{/* >*/}
|
||||
{/* <Menu.Item key="devices">*/}
|
||||
{/* <Link to="/entgra/devices">*/}
|
||||
{/* <span>View</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <Menu.Item key="deviceEnroll">*/}
|
||||
{/* <Link to="/entgra/devices/enroll">*/}
|
||||
{/* <span>Enroll</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* </SubMenu>*/}
|
||||
<SubMenu
|
||||
key="geo"
|
||||
title={
|
||||
@ -118,65 +118,65 @@ class Dashboard extends React.Component {
|
||||
<span>Reports</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="groups">
|
||||
<Link to="/entgra/groups">
|
||||
<Icon type="deployment-unit" />
|
||||
<span>Groups</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="users">
|
||||
<Link to="/entgra/users">
|
||||
<Icon type="user" />
|
||||
<span>Users</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<SubMenu
|
||||
key="policies"
|
||||
title={
|
||||
<span>
|
||||
<Icon type="audit" />
|
||||
<span>Policies</span>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Menu.Item key="policiesList">
|
||||
<Link to="/entgra/policies">
|
||||
<span>View</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="addPolicy">
|
||||
<Link to="/entgra/policy/add">
|
||||
<span>Add New Policy</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="roles">
|
||||
<Link to="/entgra/roles">
|
||||
<Icon type="book" />
|
||||
<span>Roles</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="devicetypes">
|
||||
<Link to="/entgra/devicetypes">
|
||||
<Icon type="desktop" />
|
||||
<span>Device Types</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<SubMenu
|
||||
key="configurations"
|
||||
title={
|
||||
<span>
|
||||
<Icon type="setting" />
|
||||
<span>Configurations</span>
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<Menu.Item key="certificates">
|
||||
<Link to="/entgra/certificates">
|
||||
<span>Certificates</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</SubMenu>
|
||||
{/* <Menu.Item key="groups">*/}
|
||||
{/* <Link to="/entgra/groups">*/}
|
||||
{/* <Icon type="deployment-unit" />*/}
|
||||
{/* <span>Groups</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <Menu.Item key="users">*/}
|
||||
{/* <Link to="/entgra/users">*/}
|
||||
{/* <Icon type="user" />*/}
|
||||
{/* <span>Users</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <SubMenu*/}
|
||||
{/* key="policies"*/}
|
||||
{/* title={*/}
|
||||
{/* <span>*/}
|
||||
{/* <Icon type="audit" />*/}
|
||||
{/* <span>Policies</span>*/}
|
||||
{/* </span>*/}
|
||||
{/* }*/}
|
||||
{/* >*/}
|
||||
{/* <Menu.Item key="policiesList">*/}
|
||||
{/* <Link to="/entgra/policies">*/}
|
||||
{/* <span>View</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <Menu.Item key="addPolicy">*/}
|
||||
{/* <Link to="/entgra/policy/add">*/}
|
||||
{/* <span>Add New Policy</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* </SubMenu>*/}
|
||||
{/* <Menu.Item key="roles">*/}
|
||||
{/* <Link to="/entgra/roles">*/}
|
||||
{/* <Icon type="book" />*/}
|
||||
{/* <span>Roles</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <Menu.Item key="devicetypes">*/}
|
||||
{/* <Link to="/entgra/devicetypes">*/}
|
||||
{/* <Icon type="desktop" />*/}
|
||||
{/* <span>Device Types</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* <SubMenu*/}
|
||||
{/* key="configurations"*/}
|
||||
{/* title={*/}
|
||||
{/* <span>*/}
|
||||
{/* <Icon type="setting" />*/}
|
||||
{/* <span>Configurations</span>*/}
|
||||
{/* </span>*/}
|
||||
{/* }*/}
|
||||
{/* >*/}
|
||||
{/* <Menu.Item key="certificates">*/}
|
||||
{/* <Link to="/entgra/certificates">*/}
|
||||
{/* <span>Certificates</span>*/}
|
||||
{/* </Link>*/}
|
||||
{/* </Menu.Item>*/}
|
||||
{/* </SubMenu>*/}
|
||||
<Menu.Item key="trigger"></Menu.Item>
|
||||
<SubMenu
|
||||
className="profile"
|
||||
@ -192,9 +192,9 @@ class Dashboard extends React.Component {
|
||||
</Menu>
|
||||
</Header>
|
||||
|
||||
<Content style={{ marginTop: 10 }}>
|
||||
<Content>
|
||||
<Switch>
|
||||
<Redirect exact from="/entgra" to="/entgra/devices" />
|
||||
<Redirect exact from="/entgra/devices" to="/entgra/reports" />
|
||||
{this.state.routes.map(route => (
|
||||
<RouteWithSubRoutes key={route.path} {...route} />
|
||||
))}
|
||||
|
||||
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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, Card } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
class PolicyReportHome extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div style={{ borderRadius: 5 }}>
|
||||
<Row gutter={16}>
|
||||
<Col span={8}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/policy/compliance',
|
||||
data: {
|
||||
name: 'all_policy_compliance_report',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>Policy Compliance Report</b>
|
||||
</h2>
|
||||
<p>Policy compliance details of all enrolled devices</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/enrollments',
|
||||
data: {
|
||||
name: 'enrollments_vs_unenrollments_report',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>Enrollments vs Unenrollments</b>
|
||||
</h2>
|
||||
<p>Details on device enrollments vs unenrollments</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
|
||||
<Col span={8}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/device-status',
|
||||
data: {
|
||||
name: 'enrollment_status_report',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>Device Status Report</b>
|
||||
</h2>
|
||||
<p>Report based on device status</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
|
||||
<Col span={8}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/enrollment-type',
|
||||
data: {
|
||||
name: 'enrollemt_type_report',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>Device Type Report</b>
|
||||
</h2>
|
||||
<p>Report for all device types</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PolicyReportHome;
|
||||
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Icon, Col, Row, Card } from 'antd';
|
||||
import { Icon, Col, Row, Card, PageHeader, Breadcrumb } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
@ -32,10 +32,11 @@ class ReportDurationItemList extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
// Array for pre defined date durations
|
||||
durationItemArray = [
|
||||
{
|
||||
name: 'Daily Report',
|
||||
description: 'Enrollments of today',
|
||||
description: 'Report of today',
|
||||
duration: [
|
||||
moment().format('YYYY-MM-DD'),
|
||||
moment()
|
||||
@ -45,7 +46,7 @@ class ReportDurationItemList extends React.Component {
|
||||
},
|
||||
{
|
||||
name: 'Weekly Report',
|
||||
description: 'Enrollments of last 7 days',
|
||||
description: 'Report of last 7 days',
|
||||
duration: [
|
||||
moment()
|
||||
.subtract(6, 'days')
|
||||
@ -57,7 +58,7 @@ class ReportDurationItemList extends React.Component {
|
||||
},
|
||||
{
|
||||
name: 'Monthly Report',
|
||||
description: 'Enrollments of last month',
|
||||
description: 'Report of last month',
|
||||
duration: [
|
||||
moment()
|
||||
.subtract(29, 'days')
|
||||
@ -69,7 +70,104 @@ class ReportDurationItemList extends React.Component {
|
||||
},
|
||||
];
|
||||
|
||||
// Map durationItemArray and additional parameters to antd cards
|
||||
mapDurationCards = data => {
|
||||
return this.durationItemArray.map(item => (
|
||||
<Col key={item.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/policy',
|
||||
reportData: {
|
||||
duration: item.duration,
|
||||
data: data,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
key={item.name}
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>{item.name}</b>
|
||||
</h2>
|
||||
<p>{item.description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
));
|
||||
};
|
||||
|
||||
itemAllPolicyCompliance = this.durationItemArray.map(data => (
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/policyreport',
|
||||
reportData: {
|
||||
duration: data.duration,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
key={data.name}
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }} />
|
||||
<h2>
|
||||
<b>{data.name}</b>
|
||||
</h2>
|
||||
<p>{data.description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
));
|
||||
|
||||
itemPerPolicyCompliance = this.durationItemArray.map(data => (
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/policyreport',
|
||||
reportData: {
|
||||
duration: data.duration,
|
||||
policyId: 6,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
key={data.name}
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon type="desktop" style={{ fontSize: '25px', color: '#08c' }} />
|
||||
<h2>
|
||||
<b>{data.name}</b>
|
||||
</h2>
|
||||
<p>{data.description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
));
|
||||
|
||||
render() {
|
||||
const { data } = this.props.location;
|
||||
|
||||
let itemStatus = this.durationItemArray.map(data => (
|
||||
<Col key={data.name} span={6}>
|
||||
<Link
|
||||
@ -175,18 +273,53 @@ class ReportDurationItemList extends React.Component {
|
||||
</Link>
|
||||
</Col>
|
||||
));
|
||||
|
||||
let cardItem = this.itemAllPolicyCompliance;
|
||||
|
||||
switch (data.name) {
|
||||
case 'all_policy_compliance_report':
|
||||
cardItem = this.itemAllPolicyCompliance;
|
||||
// cardItem = this.mapDurationCards({});
|
||||
break;
|
||||
case 'per_policy_compliance_report':
|
||||
cardItem = this.itemPerPolicyCompliance;
|
||||
// cardItem = this.mapDurationCards({
|
||||
// policyId: 6,
|
||||
// });
|
||||
break;
|
||||
case 'enrollments_vs_unenrollments_report':
|
||||
cardItem = itemEnrollmentsVsUnenrollments;
|
||||
break;
|
||||
case 'enrollment_status_report':
|
||||
cardItem = itemStatus;
|
||||
break;
|
||||
case 'enrollemt_type_report':
|
||||
cardItem = itemEnrollmentType;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ borderRadius: 5 }}>
|
||||
<Row gutter={16}>{itemStatus}</Row>
|
||||
</div>
|
||||
|
||||
<div style={{ borderRadius: 5 }}>
|
||||
<Row gutter={16}>{itemEnrollmentsVsUnenrollments}</Row>
|
||||
</div>
|
||||
|
||||
<div style={{ borderRadius: 5 }}>
|
||||
<Row gutter={16}>{itemEnrollmentType}</Row>
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Reports</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap">
|
||||
<h3>Reports</h3>
|
||||
<div style={{ borderRadius: 5 }}>
|
||||
<Row gutter={16}>{cardItem}</Row>
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
import React from 'react';
|
||||
import { PageHeader, Breadcrumb, Icon } from 'antd';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ReportDurationItemList from './ReportDurationItemList';
|
||||
import PolicyReportHome from './PolicyReportHome';
|
||||
|
||||
class Reports extends React.Component {
|
||||
routes;
|
||||
@ -70,7 +70,7 @@ class Reports extends React.Component {
|
||||
</Breadcrumb>
|
||||
<div className="wrap">
|
||||
<h3>Reports</h3>
|
||||
<ReportDurationItemList />
|
||||
<PolicyReportHome />
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. 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 org.wso2.carbon.device.mgt.jaxrs.beans;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ComplianceDeviceList extends BasePaginatedResult{
|
||||
private List<ComplianceData> complianceData = new ArrayList<>();
|
||||
|
||||
@ApiModelProperty(value = "List of devices returned")
|
||||
@JsonProperty("devices")
|
||||
public List<ComplianceData> getList() {
|
||||
return complianceData;
|
||||
}
|
||||
|
||||
public void setList(List<ComplianceData> complianceData) {
|
||||
this.complianceData = complianceData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{\n");
|
||||
sb.append(" count: ").append(getCount()).append(",\n");
|
||||
sb.append(" devices: [").append(complianceData).append("\n");
|
||||
sb.append("]}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -1906,4 +1906,110 @@ public interface DeviceManagementService {
|
||||
@PathParam("status") String status,
|
||||
@ApiParam(name = "deviceList", value = "The payload containing the new name of the device.", required = true)
|
||||
@Valid List<String> deviceList);
|
||||
|
||||
@GET
|
||||
@Path("/compliance/{compliance-status}")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Policy Compliance Status of all devices",
|
||||
notes = "A policy is enforced on the devices that register with Entgra IoTS. " +
|
||||
"The server checks if the settings in the device comply with the policy that is enforced on the device using this REST API.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:compliance-data")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK",
|
||||
response = NonComplianceData.class),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid request or validation error.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Error occurred while getting the compliance data.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getPolicyCompliance(
|
||||
@ApiParam(
|
||||
name = "compliance-status",
|
||||
value = "Compliance status for devices. If true, devices which are compliant with policies. " +
|
||||
"If false, devices which are not compliant",
|
||||
required = true)
|
||||
@PathParam("compliance-status")
|
||||
boolean complianceStatus,
|
||||
@ApiParam(
|
||||
name = "policy",
|
||||
value = "Policy ID")
|
||||
@QueryParam("policy") String policyId,
|
||||
@ApiParam(
|
||||
name = "is-pending",
|
||||
value = "Check for devices in pending status")
|
||||
@QueryParam("pending") boolean isPending,
|
||||
@ApiParam(
|
||||
name = "fromDate",
|
||||
value = "Start date of the duration")
|
||||
@QueryParam("from") String fromDate,
|
||||
@ApiParam(
|
||||
name = "toDate",
|
||||
value = "end date of the duration")
|
||||
@QueryParam("to") String toDate,
|
||||
@ApiParam(
|
||||
name = "offset",
|
||||
value = "The starting pagination index for the complete list of qualified items.",
|
||||
defaultValue = "0")
|
||||
@QueryParam("offset")
|
||||
int offset,
|
||||
@ApiParam(
|
||||
name = "limit",
|
||||
value = "Provide how many device details you require from the starting pagination index/offset.",
|
||||
defaultValue = "5")
|
||||
@QueryParam("limit")
|
||||
int limit);
|
||||
|
||||
@GET
|
||||
@Path("/{id}/features")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Policy Compliance Status of all devices",
|
||||
notes = "A policy is enforced on the devices that register with Entgra IoTS. " +
|
||||
"The server checks if the settings in the device comply with the policy that is enforced on the device using this REST API.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:compliance-data")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK",
|
||||
response = NonComplianceData.class),
|
||||
@ApiResponse(
|
||||
code = 400,
|
||||
message = "Bad Request. \n Invalid request or validation error.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Error occurred while getting the compliance data.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getNoneComplianceFeatures(
|
||||
@ApiParam(
|
||||
name = "id",
|
||||
value = "The device identifier of the device you wish to get details.\n" +
|
||||
"INFO: Make sure to add the ID of a device that is already registered with Entgra IoTS.",
|
||||
required = true)
|
||||
@PathParam("id")
|
||||
int id);
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ public interface ReportManagementService {
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of Registered Devices",
|
||||
notes = "Provides details of all the devices enrolled with WSO2 IoT Server.",
|
||||
notes = "Provides details of all the devices enrolled with Entgra IoT Server.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ -161,12 +161,12 @@ public interface ReportManagementService {
|
||||
|
||||
|
||||
@GET
|
||||
@Path("/devices/count")
|
||||
@Path("/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.",
|
||||
notes = "Provides details of all the devices enrolled with Entgra IoT Server.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ -230,4 +230,83 @@ public interface ReportManagementService {
|
||||
value = "end date of the duration",
|
||||
required = true)
|
||||
@QueryParam("to") String toDate) 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 Entgra 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 = 500,
|
||||
message = "Internal Server Error. " +
|
||||
"\n Server error occurred while fetching the device list.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getCountOfDevicesByDuration(
|
||||
@ApiParam(
|
||||
name = "status",
|
||||
value = "Provide the device status details, such as active or inactive.")
|
||||
@QueryParam("status") List<String> 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,
|
||||
@ApiParam(
|
||||
name = "offset",
|
||||
value = "The starting pagination index for the complete list of qualified items.",
|
||||
defaultValue = "0")
|
||||
@QueryParam("offset")
|
||||
int offset,
|
||||
@ApiParam(
|
||||
name = "limit",
|
||||
value = "Provide how many device details you require from the starting pagination index/offset.")
|
||||
@QueryParam("limit")
|
||||
int limit) throws ReportManagementException;
|
||||
}
|
||||
|
||||
@ -66,6 +66,8 @@ import org.wso2.carbon.device.mgt.common.operation.mgt.Activity;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceFeature;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException;
|
||||
import org.wso2.carbon.device.mgt.common.search.PropertyMap;
|
||||
@ -84,6 +86,7 @@ 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.beans.OperationList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.OperationRequest;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ComplianceDeviceList;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.api.DeviceManagementService;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.InputValidationException;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
|
||||
@ -106,13 +109,12 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@ -1056,4 +1058,66 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||
}
|
||||
return Response.status(Response.Status.OK).build();
|
||||
}
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/compliance/{compliance-status}")
|
||||
public Response getPolicyCompliance(
|
||||
@PathParam("compliance-status") boolean complianceStatus,
|
||||
@QueryParam("policy") String policyId,
|
||||
@DefaultValue("false")
|
||||
@QueryParam("pending") boolean isPending,
|
||||
@QueryParam("from") String fromDate,
|
||||
@QueryParam("to") String toDate,
|
||||
@DefaultValue("0")
|
||||
@QueryParam("offset") int offset,
|
||||
@DefaultValue("10")
|
||||
@QueryParam("limit") int limit) {
|
||||
|
||||
PaginationRequest request = new PaginationRequest(offset, limit);
|
||||
ComplianceDeviceList complianceDeviceList = new ComplianceDeviceList();
|
||||
PaginationResult paginationResult;
|
||||
try {
|
||||
|
||||
PolicyManagerService policyManagerService = DeviceMgtAPIUtils.getPolicyManagementService();
|
||||
paginationResult = policyManagerService.getPolicyCompliance(request, policyId, complianceStatus, isPending, fromDate, toDate);
|
||||
|
||||
if (paginationResult.getData().isEmpty()) {
|
||||
return Response.status(Response.Status.OK)
|
||||
.entity("No policy compliance or non compliance devices are available").build();
|
||||
} else {
|
||||
complianceDeviceList.setList((List<ComplianceData>) paginationResult.getData());
|
||||
complianceDeviceList.setCount(paginationResult.getRecordsTotal());
|
||||
return Response.status(Response.Status.OK).entity(complianceDeviceList).build();
|
||||
}
|
||||
} catch (PolicyComplianceException e) {
|
||||
String msg = "Error occurred while retrieving compliance data";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/{id}/features")
|
||||
public Response getNoneComplianceFeatures(
|
||||
@PathParam("id") int id) {
|
||||
List<ComplianceFeature> complianceFeatureList;
|
||||
try {
|
||||
PolicyManagerService policyManagerService = DeviceMgtAPIUtils.getPolicyManagementService();
|
||||
complianceFeatureList = policyManagerService.getNoneComplianceFeatures(id);
|
||||
|
||||
if (complianceFeatureList.isEmpty()) {
|
||||
return Response.status(Response.Status.OK).entity("No non compliance features are available").build();
|
||||
} else {
|
||||
return Response.status(Response.Status.OK).entity(complianceFeatureList).build();
|
||||
}
|
||||
} catch (PolicyComplianceException e) {
|
||||
String msg = "Error occurred while retrieving non compliance features";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,9 +169,14 @@ public class PolicyManagementServiceImpl implements PolicyManagementService {
|
||||
try {
|
||||
PolicyAdministratorPoint policyAdministratorPoint = policyManagementService.getPAP();
|
||||
policies = policyAdministratorPoint.getPolicies();
|
||||
targetPolicies.setCount(policies.size());
|
||||
filteredPolicies = FilteringUtil.getFilteredList(policies, offset, limit);
|
||||
targetPolicies.setList(filteredPolicies);
|
||||
if(offset == 0 && limit == 0){
|
||||
return Response.status(Response.Status.OK).entity(policies).build();
|
||||
}else{
|
||||
targetPolicies.setCount(policies.size());
|
||||
filteredPolicies = FilteringUtil.getFilteredList(policies, offset, limit);
|
||||
targetPolicies.setList(filteredPolicies);
|
||||
return Response.status(Response.Status.OK).entity(targetPolicies).build();
|
||||
}
|
||||
} catch (PolicyManagementException e) {
|
||||
String msg = "Error occurred while retrieving all available policies";
|
||||
log.error(msg, e);
|
||||
@ -179,7 +184,7 @@ public class PolicyManagementServiceImpl implements PolicyManagementService {
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
|
||||
return Response.status(Response.Status.OK).entity(targetPolicies).build();
|
||||
|
||||
}
|
||||
|
||||
@GET
|
||||
|
||||
@ -15,15 +15,16 @@
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.device.mgt.jaxrs.service.impl;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
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;
|
||||
@ -103,7 +104,8 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
@QueryParam("to") String toDate) {
|
||||
int deviceCount;
|
||||
try {
|
||||
deviceCount = DeviceMgtAPIUtils.getReportManagementService().getDevicesByDurationCount(status, ownership, fromDate, toDate);
|
||||
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.";
|
||||
@ -112,4 +114,39 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(errorMessage).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/count")
|
||||
@Override
|
||||
public Response getCountOfDevicesByDuration(
|
||||
@QueryParam("status") List<String> status,
|
||||
@QueryParam("ownership") String ownership,
|
||||
@QueryParam("from") String fromDate,
|
||||
@QueryParam("to") String toDate,
|
||||
@DefaultValue("0")
|
||||
@QueryParam("offset") int offset,
|
||||
@QueryParam("limit") int limit) {
|
||||
try {
|
||||
RequestValidationUtil.validatePaginationParameters(offset, limit);
|
||||
PaginationRequest request = new PaginationRequest(offset, limit);
|
||||
|
||||
if (!StringUtils.isBlank(ownership)) {
|
||||
request.setOwnership(ownership);
|
||||
}
|
||||
|
||||
JsonObject countList = DeviceMgtAPIUtils.getReportManagementService()
|
||||
.getCountOfDevicesByDuration(request, status, fromDate, toDate);
|
||||
if (countList.isJsonNull()) {
|
||||
return Response.status(Response.Status.OK)
|
||||
.entity("No devices have been enrolled between the given date range").build();
|
||||
} else {
|
||||
return Response.status(Response.Status.OK).entity(countList).build();
|
||||
}
|
||||
} catch (ReportManagementException e) {
|
||||
String msg = "Error occurred while retrieving device list";
|
||||
log.error(msg, e);
|
||||
return Response.serverError().entity(
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.device.mgt.common;
|
||||
|
||||
public class Count {
|
||||
private String date;
|
||||
private int count;
|
||||
|
||||
public Count(String date, int count) {
|
||||
this.date = date;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(String date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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.
|
||||
*/
|
||||
|
||||
package org.wso2.carbon.device.mgt.common.policy.mgt.monitor;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.List;
|
||||
|
||||
public class ComplianceData {
|
||||
|
||||
private int id;
|
||||
private int deviceId;
|
||||
private String deviceName;
|
||||
private String deviceType;
|
||||
private String owner;
|
||||
private int enrolmentId;
|
||||
private int policyId;
|
||||
private String policyName;
|
||||
List<ComplianceFeature> complianceFeatures;
|
||||
private boolean status;
|
||||
private Timestamp lastRequestedTime;
|
||||
private Timestamp lastSucceededTime;
|
||||
private Timestamp lastFailedTime;
|
||||
private int attempts;
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* This parameter is to inform the policy core, weather related device type plugins does need the full policy or
|
||||
* the part which is none compliance.
|
||||
*/
|
||||
private boolean completePolicy;
|
||||
private Policy policy;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getEnrolmentId() {
|
||||
return enrolmentId;
|
||||
}
|
||||
|
||||
public void setEnrolmentId(int enrolmentId) {
|
||||
this.enrolmentId = enrolmentId;
|
||||
}
|
||||
|
||||
public Timestamp getLastRequestedTime() {
|
||||
return lastRequestedTime;
|
||||
}
|
||||
|
||||
public void setLastRequestedTime(Timestamp lastRequestedTime) {
|
||||
this.lastRequestedTime = lastRequestedTime;
|
||||
}
|
||||
|
||||
public Timestamp getLastSucceededTime() {
|
||||
return lastSucceededTime;
|
||||
}
|
||||
|
||||
public void setLastSucceededTime(Timestamp lastSucceededTime) {
|
||||
this.lastSucceededTime = lastSucceededTime;
|
||||
}
|
||||
|
||||
public Timestamp getLastFailedTime() {
|
||||
return lastFailedTime;
|
||||
}
|
||||
|
||||
public void setLastFailedTime(Timestamp lastFailedTime) {
|
||||
this.lastFailedTime = lastFailedTime;
|
||||
}
|
||||
|
||||
public int getAttempts() {
|
||||
return attempts;
|
||||
}
|
||||
|
||||
public void setAttempts(int attempts) {
|
||||
this.attempts = attempts;
|
||||
}
|
||||
|
||||
public int getDeviceId() {
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
public void setDeviceId(int deviceId) {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public int getPolicyId() {
|
||||
return policyId;
|
||||
}
|
||||
|
||||
public void setPolicyId(int policyId) {
|
||||
this.policyId = policyId;
|
||||
}
|
||||
|
||||
public List<ComplianceFeature> getComplianceFeatures() {
|
||||
return complianceFeatures;
|
||||
}
|
||||
|
||||
public void setComplianceFeatures(List<ComplianceFeature> complianceFeatures) {
|
||||
this.complianceFeatures = complianceFeatures;
|
||||
}
|
||||
|
||||
public boolean isStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(boolean status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public boolean isCompletePolicy() {
|
||||
return completePolicy;
|
||||
}
|
||||
|
||||
public void setCompletePolicy(boolean completePolicy) {
|
||||
this.completePolicy = completePolicy;
|
||||
}
|
||||
|
||||
public Policy getPolicy() {
|
||||
return policy;
|
||||
}
|
||||
|
||||
public void setPolicy(Policy policy) {
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
public String getDeviceName() {
|
||||
return deviceName;
|
||||
}
|
||||
|
||||
public void setDeviceName(String deviceName) {
|
||||
this.deviceName = deviceName;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getPolicyName() {
|
||||
return policyName;
|
||||
}
|
||||
|
||||
public void setPolicyName(String policyName) {
|
||||
this.policyName = policyName;
|
||||
}
|
||||
|
||||
public String getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public void setDeviceType(String deviceType) {
|
||||
this.deviceType = deviceType;
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.common.report.mgt;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
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;
|
||||
@ -43,4 +44,7 @@ public interface ReportManagementService {
|
||||
|
||||
int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate)
|
||||
throws ReportManagementException;
|
||||
|
||||
JsonObject getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, String fromDate, String toDate)
|
||||
throws ReportManagementException;
|
||||
}
|
||||
|
||||
@ -35,11 +35,8 @@
|
||||
|
||||
package org.wso2.carbon.device.mgt.core.dao;
|
||||
|
||||
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.*;
|
||||
import org.wso2.carbon.device.mgt.common.EnrolmentInfo.Status;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceLocationHistory;
|
||||
import org.wso2.carbon.device.mgt.common.configuration.mgt.DevicePropertyInfo;
|
||||
import org.wso2.carbon.device.mgt.common.device.details.DeviceData;
|
||||
@ -561,6 +558,23 @@ public interface DeviceDAO {
|
||||
List<String> statusList, String ownership, String fromDate, String toDate, int tenantId)
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* This method is used to get the device count to generate the report graph within a specific time periode
|
||||
*
|
||||
* @param request Pagination request to get paginated result
|
||||
* @param statusList Status list to filter data
|
||||
* @param tenantId ID of the current tenant
|
||||
* @param fromDate Start date to filter devices(YYYY-MM-DD)
|
||||
* @param toDate End date to filter devices(YYYY-MM-DD)
|
||||
* @return returns a list of Count objects
|
||||
* @throws DeviceManagementDAOException
|
||||
*/
|
||||
List<Count> getCountOfDevicesByDuration(PaginationRequest request,
|
||||
List<String> statusList,
|
||||
int tenantId,
|
||||
String fromDate,
|
||||
String toDate) throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* Retrieve device location information
|
||||
* @param deviceIdentifier Device Identifier object
|
||||
|
||||
@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Count;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
@ -529,7 +530,7 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
@Override
|
||||
public int getDevicesByDurationCount(List<String> statusList, String ownership, String fromDate, String toDate, int tenantId) throws DeviceManagementDAOException {
|
||||
int deviceCount = 0;
|
||||
boolean isStatusProvided = false;
|
||||
boolean isStatusProvided;
|
||||
|
||||
String sql = "SELECT " +
|
||||
"COUNT(d.ID) AS DEVICE_COUNT " +
|
||||
@ -576,6 +577,70 @@ public class GenericDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return deviceCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Count> getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Count> countList = new ArrayList<>();
|
||||
String ownership = request.getOwnership();
|
||||
boolean isStatusProvided;
|
||||
|
||||
String sql =
|
||||
"SELECT " +
|
||||
"SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) AS ENROLMENT_DATE, " +
|
||||
"COUNT(SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10)) AS ENROLMENT_COUNT " +
|
||||
"FROM DM_DEVICE AS d " +
|
||||
"INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
|
||||
"INNER JOIN DM_DEVICE_TYPE AS t ON 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 = ?";
|
||||
}
|
||||
|
||||
sql = sql + " GROUP BY SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) LIMIT ?,?";
|
||||
|
||||
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);
|
||||
}
|
||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||
stmt.setInt(paramIdx, request.getRowCount());
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
Count count = new Count(
|
||||
rs.getString("ENROLMENT_DATE"),
|
||||
rs.getInt("ENROLMENT_COUNT")
|
||||
);
|
||||
countList.add(count);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId + " between " + fromDate + " to " + toDate;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return countList;
|
||||
}
|
||||
|
||||
protected boolean buildStatusQuery(List<String> statusList, StringBuilder sqlBuilder) {
|
||||
if (statusList != null && !statusList.isEmpty() && !statusList.get(0).isEmpty()) {
|
||||
sqlBuilder.append(" AND e.STATUS IN(");
|
||||
|
||||
@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Count;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
@ -527,6 +528,85 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Count> getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Count> countList = new ArrayList<>();
|
||||
String ownership = request.getOwnership();
|
||||
boolean isStatusProvided;
|
||||
|
||||
String sql =
|
||||
"SELECT " +
|
||||
"SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) AS ENROLMENT_DATE, " +
|
||||
"COUNT(SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10)) AS ENROLMENT_COUNT " +
|
||||
"FROM DM_DEVICE AS d " +
|
||||
"INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
|
||||
"INNER JOIN DM_DEVICE_TYPE AS t ON 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 = ?";
|
||||
}
|
||||
|
||||
sql = sql + " GROUP BY SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||
|
||||
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);
|
||||
}
|
||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||
stmt.setInt(paramIdx, request.getRowCount());
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
Count count = new Count(
|
||||
rs.getString("ENROLMENT_DATE"),
|
||||
rs.getInt("ENROLMENT_COUNT")
|
||||
);
|
||||
countList.add(count);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId + " between " + fromDate + " to " + toDate;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return countList;
|
||||
}
|
||||
|
||||
protected boolean buildStatusQuery(List<String> 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.
|
||||
*
|
||||
@ -715,4 +795,4 @@ public class OracleDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
private Connection getConnection() throws SQLException {
|
||||
return DeviceManagementDAOFactory.getConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Count;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
@ -506,6 +507,86 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Count> getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Count> countList = new ArrayList<>();
|
||||
String ownership = request.getOwnership();
|
||||
boolean isStatusProvided;
|
||||
|
||||
String sql =
|
||||
"SELECT " +
|
||||
"SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) AS ENROLMENT_DATE, " +
|
||||
"COUNT(SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10)) AS ENROLMENT_COUNT " +
|
||||
"FROM DM_DEVICE AS d " +
|
||||
"INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
|
||||
"INNER JOIN DM_DEVICE_TYPE AS t ON 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 = ?";
|
||||
}
|
||||
|
||||
sql = sql + " GROUP BY SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) LIMIT ? OFFSET ?";
|
||||
|
||||
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);
|
||||
}
|
||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||
stmt.setInt(paramIdx, request.getRowCount());
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
Count count = new Count(
|
||||
rs.getString("ENROLMENT_DATE"),
|
||||
rs.getInt("ENROLMENT_COUNT")
|
||||
);
|
||||
countList.add(count);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId + " between " + fromDate + " to " + toDate;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return countList;
|
||||
}
|
||||
|
||||
protected boolean buildStatusQuery(List<String> 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.
|
||||
*
|
||||
@ -572,7 +653,7 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Device> getSubscribedDevices(int offsetValue, int limitValue,
|
||||
List<Integer> deviceIds, int tenantId, String status)
|
||||
@ -695,4 +776,4 @@ public class PostgreSQLDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
private Connection getConnection() throws SQLException {
|
||||
return DeviceManagementDAOFactory.getConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl.device;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Count;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
@ -671,6 +672,85 @@ public class SQLServerDeviceDAOImpl extends AbstractDeviceDAOImpl {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Count> getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, int tenantId,
|
||||
String fromDate, String toDate)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Count> countList = new ArrayList<>();
|
||||
String ownership = request.getOwnership();
|
||||
boolean isStatusProvided;
|
||||
|
||||
String sql =
|
||||
"SELECT " +
|
||||
"SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) AS ENROLMENT_DATE, " +
|
||||
"COUNT(SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10)) AS ENROLMENT_COUNT " +
|
||||
"FROM DM_DEVICE AS d " +
|
||||
"INNER JOIN DM_ENROLMENT AS e ON d.ID = e.DEVICE_ID " +
|
||||
"INNER JOIN DM_DEVICE_TYPE AS t ON 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 = ?";
|
||||
}
|
||||
|
||||
sql = sql + " GROUP BY SUBSTRING(e.DATE_OF_ENROLMENT, 1, 10) OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
|
||||
|
||||
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);
|
||||
}
|
||||
stmt.setInt(paramIdx++, request.getStartIndex());
|
||||
stmt.setInt(paramIdx, request.getRowCount());
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
Count count = new Count(
|
||||
rs.getString("ENROLMENT_DATE"),
|
||||
rs.getInt("ENROLMENT_COUNT")
|
||||
);
|
||||
countList.add(count);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId + " between " + fromDate + " to " + toDate;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return countList;
|
||||
}
|
||||
|
||||
protected boolean buildStatusQuery(List<String> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSubscribedDeviceCount(List<Integer> deviceIds, int tenantId, String status)
|
||||
throws DeviceManagementDAOException {
|
||||
|
||||
@ -17,8 +17,10 @@
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.core.report.mgt;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Count;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
@ -32,7 +34,13 @@ import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
|
||||
import org.wso2.carbon.device.mgt.core.util.DeviceManagerUtil;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Calendar;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* This is the service class for reports which calls dao classes and its method which are used for
|
||||
@ -92,7 +100,8 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
throws ReportManagementException {
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
return deviceDAO.getDevicesByDurationCount(statusList, ownership, fromDate, toDate, DeviceManagementDAOUtil.getTenantId());
|
||||
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);
|
||||
@ -105,4 +114,98 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObject getCountOfDevicesByDuration(PaginationRequest request, List<String> statusList, String fromDate,
|
||||
String toDate)
|
||||
throws ReportManagementException {
|
||||
try {
|
||||
request = DeviceManagerUtil.validateDeviceListPageSize(request);
|
||||
} catch (DeviceManagementException e) {
|
||||
String msg = "Error occurred while validating device list page size";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
}
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
List<Count> dateList = deviceDAO.getCountOfDevicesByDuration(
|
||||
request,
|
||||
statusList,
|
||||
DeviceManagementDAOUtil.getTenantId(),
|
||||
fromDate,
|
||||
toDate
|
||||
);
|
||||
return buildCount(fromDate, toDate, dateList);
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection " +
|
||||
"to the data source";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred while retrieving Tenant ID between " + fromDate + " to " + toDate;
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} catch (ParseException e) {
|
||||
String msg = "Error occurred while building count";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} finally {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: This is just a temporary method for retrieving device counts
|
||||
public JsonObject buildCount(String start, String end, List<Count> countList) throws ParseException {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||
int prevDateAmount = 0;
|
||||
boolean isDaily = false;
|
||||
|
||||
Date startDate = dateFormat.parse(start);
|
||||
Date endDate = dateFormat.parse(end);
|
||||
|
||||
//Check duration between two given dates
|
||||
long gap = endDate.getTime() - startDate.getTime();
|
||||
long diffInDays = TimeUnit.MILLISECONDS.toDays(gap);
|
||||
|
||||
if (diffInDays < 7) {
|
||||
isDaily = true;
|
||||
} else if (diffInDays < 30) {
|
||||
prevDateAmount = -7;
|
||||
} else {
|
||||
prevDateAmount = -30;
|
||||
}
|
||||
JsonObject resultObject = new JsonObject();
|
||||
if (!isDaily) {
|
||||
//Divide date duration into week or month blocks
|
||||
while (endDate.after(startDate)) {
|
||||
int sum = 0;
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(endDate);
|
||||
calendar.add(Calendar.DAY_OF_YEAR, prevDateAmount);
|
||||
Date previousDate = calendar.getTime();
|
||||
if (startDate.after(previousDate)) {
|
||||
previousDate = startDate;
|
||||
}
|
||||
//Loop count list which came from database to add them into week or month blocks
|
||||
for (Count count : countList) {
|
||||
if (dateFormat.parse(
|
||||
count.getDate()).after(previousDate) &&
|
||||
dateFormat.parse(count.getDate()).before(endDate
|
||||
)) {
|
||||
sum = sum + count.getCount();
|
||||
}
|
||||
}
|
||||
//Map date blocks and counts
|
||||
resultObject.addProperty(
|
||||
dateFormat.format(endDate) + " - " + dateFormat.format(previousDate), sum);
|
||||
endDate = previousDate;
|
||||
|
||||
}
|
||||
} else {
|
||||
for (Count count : countList) {
|
||||
resultObject.addProperty(count.getDate(), count.getCount());
|
||||
}
|
||||
}
|
||||
return resultObject;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,8 @@ package org.wso2.carbon.policy.mgt.core;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
import org.wso2.carbon.device.mgt.common.Feature;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.Profile;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.ProfileFeature;
|
||||
@ -81,4 +83,10 @@ public interface PolicyManagerService {
|
||||
NonComplianceData getDeviceCompliance(DeviceIdentifier deviceIdentifier) throws PolicyComplianceException;
|
||||
|
||||
boolean isCompliant(DeviceIdentifier deviceIdentifier) throws PolicyComplianceException;
|
||||
|
||||
PaginationResult getPolicyCompliance(
|
||||
PaginationRequest paginationRequest, String policyId, boolean complianceStatus, boolean isPending, String fromDate, String toDate)
|
||||
throws PolicyComplianceException;
|
||||
|
||||
List<ComplianceFeature> getNoneComplianceFeatures(int complianceStatusId) throws PolicyComplianceException;
|
||||
}
|
||||
|
||||
@ -39,6 +39,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
import org.wso2.carbon.device.mgt.common.Feature;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.InvalidDeviceException;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
|
||||
@ -248,4 +250,16 @@ public class PolicyManagerServiceImpl implements PolicyManagerService {
|
||||
public boolean isCompliant(DeviceIdentifier deviceIdentifier) throws PolicyComplianceException {
|
||||
return monitoringManager.isCompliant(deviceIdentifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginationResult getPolicyCompliance(
|
||||
PaginationRequest paginationRequest, String policyId, boolean complianceStatus, boolean isPending, String fromDate, String toDate)
|
||||
throws PolicyComplianceException {
|
||||
return monitoringManager.getPolicyCompliance(paginationRequest, policyId, complianceStatus, isPending, fromDate, toDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ComplianceFeature> getNoneComplianceFeatures(int complianceStatusId) throws PolicyComplianceException {
|
||||
return monitoringManager.getNoneComplianceFeatures(complianceStatusId);
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,8 @@
|
||||
|
||||
package org.wso2.carbon.policy.mgt.core.dao;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceFeature;
|
||||
import org.wso2.carbon.policy.mgt.common.monitor.PolicyDeviceWrapper;
|
||||
@ -55,6 +57,10 @@ public interface MonitoringDAO {
|
||||
|
||||
List<NonComplianceData> getCompliance() throws MonitoringDAOException;
|
||||
|
||||
List<ComplianceData> getAllComplianceDevices(
|
||||
PaginationRequest paginationRequest, String policyId, boolean complianceStatus, boolean isPending, String fromDate, String toDate)
|
||||
throws MonitoringDAOException;
|
||||
|
||||
List<ComplianceFeature> getNoneComplianceFeatures(int policyComplianceStatusId) throws MonitoringDAOException;
|
||||
|
||||
void deleteNoneComplianceData(int policyComplianceStatusId) throws MonitoringDAOException;
|
||||
|
||||
@ -22,6 +22,8 @@ package org.wso2.carbon.policy.mgt.core.dao.impl;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.context.PrivilegedCarbonContext;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceFeature;
|
||||
import org.wso2.carbon.policy.mgt.common.monitor.PolicyDeviceWrapper;
|
||||
@ -347,6 +349,97 @@ public class MonitoringDAOImpl implements MonitoringDAO {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ComplianceData> getAllComplianceDevices(
|
||||
PaginationRequest paginationRequest,
|
||||
String policyId,
|
||||
boolean complianceStatus,
|
||||
boolean isPending,
|
||||
String fromDate,
|
||||
String toDate)
|
||||
throws MonitoringDAOException {
|
||||
List<ComplianceData> complianceDataList = new ArrayList<>();
|
||||
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
|
||||
|
||||
String query =
|
||||
"SELECT " +
|
||||
"DEVICE.NAME, " +
|
||||
"DM_DEVICE_TYPE.NAME AS DEVICE_TYPE, " +
|
||||
"ENROLLMENT.OWNER, " +
|
||||
"DM_POLICY.NAME AS POLICY_NAME, " +
|
||||
"POLICY.* " +
|
||||
"FROM DM_POLICY_COMPLIANCE_STATUS AS POLICY, DM_DEVICE AS DEVICE, " +
|
||||
"DM_ENROLMENT AS ENROLLMENT, DM_POLICY, DM_DEVICE_TYPE " +
|
||||
"WHERE DEVICE.ID=POLICY.DEVICE_ID " +
|
||||
"AND DEVICE.ID=ENROLLMENT.DEVICE_ID " +
|
||||
"AND POLICY.POLICY_ID=DM_POLICY.ID " +
|
||||
"AND DEVICE.DEVICE_TYPE_ID=DM_DEVICE_TYPE.ID " +
|
||||
"AND POLICY.TENANT_ID = ? AND POLICY.STATUS = ?";
|
||||
|
||||
if (isPending) {
|
||||
query = query + " AND POLICY.LAST_SUCCESS_TIME IS NULL " +
|
||||
"AND POLICY.LAST_FAILED_TIME IS NULL";
|
||||
} else {
|
||||
query = query + " AND (POLICY.LAST_SUCCESS_TIME IS NOT NULL " +
|
||||
"OR POLICY.LAST_FAILED_TIME IS NOT NULL)";
|
||||
}
|
||||
|
||||
if (policyId != null) {
|
||||
query = query + " AND POLICY.POLICY_ID = ?";
|
||||
}
|
||||
|
||||
if (fromDate != null && toDate != null) {
|
||||
if (!complianceStatus) {
|
||||
query = query + " AND POLICY.LAST_FAILED_TIME BETWEEN ? AND ?";
|
||||
} else {
|
||||
query = query + " AND POLICY.LAST_SUCCESS_TIME BETWEEN ? AND ?";
|
||||
}
|
||||
}
|
||||
|
||||
query = query + " LIMIT ?,?";
|
||||
|
||||
try (Connection conn = this.getConnection();
|
||||
PreparedStatement stmt = conn.prepareStatement(query);) {
|
||||
int paramIdx = 1;
|
||||
stmt.setInt(paramIdx++, tenantId);
|
||||
stmt.setBoolean(paramIdx++, complianceStatus);
|
||||
if (policyId != null) {
|
||||
stmt.setInt(paramIdx++, Integer.parseInt(policyId));
|
||||
}
|
||||
if (fromDate != null && toDate != null) {
|
||||
stmt.setString(paramIdx++, fromDate);
|
||||
stmt.setString(paramIdx++, toDate);
|
||||
}
|
||||
stmt.setInt(paramIdx++, paginationRequest.getStartIndex());
|
||||
stmt.setInt(paramIdx, paginationRequest.getRowCount());
|
||||
|
||||
try (ResultSet resultSet = stmt.executeQuery()) {
|
||||
while (resultSet.next()) {
|
||||
ComplianceData complianceData = new ComplianceData();
|
||||
complianceData.setId(resultSet.getInt("ID"));
|
||||
complianceData.setDeviceId(resultSet.getInt("DEVICE_ID"));
|
||||
complianceData.setDeviceName(resultSet.getString("NAME"));
|
||||
complianceData.setDeviceType(resultSet.getString("DEVICE_TYPE"));
|
||||
complianceData.setOwner(resultSet.getString("OWNER"));
|
||||
complianceData.setEnrolmentId(resultSet.getInt("ENROLMENT_ID"));
|
||||
complianceData.setPolicyId(resultSet.getInt("POLICY_ID"));
|
||||
complianceData.setPolicyName(resultSet.getString("POLICY_NAME"));
|
||||
complianceData.setStatus(resultSet.getBoolean("STATUS"));
|
||||
complianceData.setAttempts(resultSet.getInt("ATTEMPTS"));
|
||||
complianceData.setLastRequestedTime(resultSet.getTimestamp("LAST_REQUESTED_TIME"));
|
||||
complianceData.setLastFailedTime(resultSet.getTimestamp("LAST_FAILED_TIME"));
|
||||
complianceData.setLastSucceededTime(resultSet.getTimestamp("LAST_SUCCESS_TIME"));
|
||||
complianceDataList.add(complianceData);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Unable to retrieve compliance data from database.";
|
||||
log.error(msg, e);
|
||||
throw new MonitoringDAOException(msg, e);
|
||||
}
|
||||
return complianceDataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ComplianceFeature> getNoneComplianceFeatures(int policyComplianceStatusId) throws
|
||||
MonitoringDAOException {
|
||||
|
||||
@ -21,6 +21,8 @@ package org.wso2.carbon.policy.mgt.core.mgt;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceFeature;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException;
|
||||
@ -41,4 +43,11 @@ public interface MonitoringManager {
|
||||
|
||||
List<String> getDeviceTypes() throws PolicyComplianceException;
|
||||
|
||||
PaginationResult getPolicyCompliance(
|
||||
PaginationRequest paginationRequest, String policyId, boolean complianceStatus, boolean isPending, String fromDate, String toDate)
|
||||
throws PolicyComplianceException;
|
||||
|
||||
List<ComplianceFeature> getNoneComplianceFeatures(int complianceStatusId)
|
||||
throws PolicyComplianceException;
|
||||
|
||||
}
|
||||
|
||||
@ -22,11 +22,14 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.Device;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceIdentifier;
|
||||
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.InvalidDeviceException;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.Operation;
|
||||
import org.wso2.carbon.device.mgt.common.operation.mgt.OperationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.PolicyMonitoringManager;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.ComplianceFeature;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.PolicyComplianceException;
|
||||
@ -371,6 +374,52 @@ public class MonitoringManagerImpl implements MonitoringManager {
|
||||
return deviceTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginationResult getPolicyCompliance(
|
||||
PaginationRequest paginationRequest, String policyId,
|
||||
boolean complianceStatus, boolean isPending, String fromDate, String toDate)
|
||||
throws PolicyComplianceException {
|
||||
PaginationResult paginationResult = new PaginationResult();
|
||||
try {
|
||||
PolicyManagementDAOFactory.openConnection();
|
||||
List<ComplianceData> complianceDataList = monitoringDAO
|
||||
.getAllComplianceDevices(paginationRequest, policyId, complianceStatus, isPending, fromDate, toDate);
|
||||
paginationResult.setData(complianceDataList);
|
||||
paginationResult.setRecordsTotal(complianceDataList.size());
|
||||
} catch (MonitoringDAOException e) {
|
||||
String msg = "Unable to retrieve compliance data";
|
||||
log.error(msg, e);
|
||||
throw new PolicyComplianceException(msg, e);
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection to the data source";
|
||||
log.error(msg, e);
|
||||
throw new PolicyComplianceException(msg, e);
|
||||
} finally {
|
||||
PolicyManagementDAOFactory.closeConnection();
|
||||
}
|
||||
return paginationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ComplianceFeature> getNoneComplianceFeatures(int complianceStatusId) throws PolicyComplianceException {
|
||||
List<ComplianceFeature> complianceFeatureList;
|
||||
try {
|
||||
PolicyManagementDAOFactory.openConnection();
|
||||
complianceFeatureList = monitoringDAO.getNoneComplianceFeatures(complianceStatusId);
|
||||
} catch (MonitoringDAOException e) {
|
||||
String msg = "Unable to retrieve non compliance features";
|
||||
log.error(msg, e);
|
||||
throw new PolicyComplianceException(msg, e);
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection to the data source";
|
||||
log.error(msg, e);
|
||||
throw new PolicyComplianceException(msg, e);
|
||||
} finally {
|
||||
PolicyManagementDAOFactory.closeConnection();
|
||||
}
|
||||
return complianceFeatureList;
|
||||
}
|
||||
|
||||
private void addMonitoringOperationsToDatabase(List<Device> devices)
|
||||
throws PolicyComplianceException, OperationManagementException, InvalidDeviceException {
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user