mirror of
https://repository.entgra.net/community/device-mgt-core.git
synced 2025-10-06 02:01:45 +00:00
Merge branch 'reporting-new' into 'master'
Create a report to get application not installed devices Closes product-iots#322 See merge request entgra/carbon-device-mgt!438
This commit is contained in:
commit
1e1d2acd01
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 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, Button } from 'antd';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
import AppListDropDown from '../Widgets/AppListDropDown';
|
||||
import ReportDevicesTable from '../Widgets/ReportDevicesTable';
|
||||
import AppVersionDropDown from '../Widgets/AppVersionDropDown';
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let config = null;
|
||||
let url;
|
||||
let packageName;
|
||||
let version;
|
||||
|
||||
class AppNotInstalledDevicesReport extends React.Component {
|
||||
routes;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.routes = props.routes;
|
||||
config = this.props.context;
|
||||
this.state = {
|
||||
apiUrl: null,
|
||||
visible: false,
|
||||
packageName: null,
|
||||
version: 'all',
|
||||
};
|
||||
}
|
||||
|
||||
getAppList = appPackageName => {
|
||||
packageName = appPackageName;
|
||||
this.setState({ packageName });
|
||||
};
|
||||
|
||||
getVersion = appVersion => {
|
||||
version = appVersion;
|
||||
this.setState({ version });
|
||||
};
|
||||
|
||||
onClickGenerateButton = () => {
|
||||
const { packageName, version } = this.state;
|
||||
if (version === 'all') {
|
||||
url =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/devices/android/' +
|
||||
packageName +
|
||||
'/not-installed?';
|
||||
} else {
|
||||
url =
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/reports/devices/android/' +
|
||||
packageName +
|
||||
'/not-installed?app-version=' +
|
||||
version +
|
||||
'&';
|
||||
}
|
||||
this.setState({ apiUrl: url });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { apiUrl, packageName } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<PageHeader style={{ paddingTop: 0 }}>
|
||||
<Breadcrumb style={{ paddingBottom: 16 }}>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra">
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra/reports">Reports</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>App NOT Installed Devices Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Policy Report</h3>
|
||||
|
||||
<div style={{ display: 'flex', marginBottom: '10px' }}>
|
||||
<div>
|
||||
<AppListDropDown getAppList={this.getAppList} />
|
||||
</div>
|
||||
|
||||
<div style={{ marginLeft: '10px' }}>
|
||||
<AppVersionDropDown
|
||||
getVersion={this.getVersion}
|
||||
packageName={packageName}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={this.onClickGenerateButton}
|
||||
style={{ marginLeft: '10px' }}
|
||||
>
|
||||
Generate Report
|
||||
</Button>
|
||||
</div>
|
||||
<div style={{ backgroundColor: '#ffffff', borderRadius: 5 }}>
|
||||
<ReportDevicesTable apiUrl={apiUrl} />
|
||||
</div>
|
||||
</div>
|
||||
</PageHeader>
|
||||
<div
|
||||
style={{ background: '#f0f2f5', padding: 24, minHeight: 720 }}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(AppNotInstalledDevicesReport);
|
||||
@ -188,7 +188,10 @@ class DeviceStatusReport extends React.Component {
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra/reports">Reports</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Device Status Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Device Status Report</h3>
|
||||
|
||||
@ -177,7 +177,10 @@ class EnrollmentTypeReport extends React.Component {
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra/reports">Reports</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Device Enrollment Type Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Device Enrollment Type Report</h3>
|
||||
|
||||
@ -177,7 +177,12 @@ class EnrollmentsVsUnenrollmentsReport extends React.Component {
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra/reports">Reports</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
Enrollments vs Unenrollments Report
|
||||
</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Enrollments vs Unenrollments Report</h3>
|
||||
|
||||
@ -132,7 +132,10 @@ class PolicyReport extends React.Component {
|
||||
<Icon type="home" /> Home
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Report</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/entgra/reports">Reports</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Policy Compliance Report</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
<div className="wrap" style={{ marginBottom: '10px' }}>
|
||||
<h3>Policy Report</h3>
|
||||
|
||||
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 { message, notification, Select } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class AppListDropDown extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectItem: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.fetchFullAppList();
|
||||
}
|
||||
|
||||
fetchFullAppList = () => {
|
||||
const config = this.props.context;
|
||||
axios
|
||||
.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices/android/applications?offset=0&limit=-1',
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
let selectItem;
|
||||
selectItem = res.data.data.applicationList.map(data => (
|
||||
<Option value={data.id} key={data.applicationIdentifier}>
|
||||
{data.name.replace('%', ' ')}
|
||||
</Option>
|
||||
));
|
||||
this.setState({ selectItem });
|
||||
}
|
||||
})
|
||||
.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 application list.',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onChange = (value, data) => {
|
||||
this.props.getAppList(data.key);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { selectItem } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
placeholder="Select an app"
|
||||
optionFilterProp="children"
|
||||
onChange={this.onChange}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
|
||||
0
|
||||
}
|
||||
>
|
||||
{selectItem}
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(AppListDropDown);
|
||||
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 { message, notification, Select } from 'antd';
|
||||
import axios from 'axios';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
class AppVersionDropDown extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectItem: [],
|
||||
loading: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.packageName) {
|
||||
this.fetchVersionList();
|
||||
}
|
||||
}
|
||||
|
||||
// Rerender component when parameters change
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (prevProps.packageName !== this.props.packageName) {
|
||||
this.fetchVersionList();
|
||||
}
|
||||
}
|
||||
|
||||
fetchVersionList = () => {
|
||||
const config = this.props.context;
|
||||
this.setState({ loading: true });
|
||||
axios
|
||||
.get(
|
||||
window.location.origin +
|
||||
config.serverConfig.invoker.uri +
|
||||
config.serverConfig.invoker.deviceMgt +
|
||||
'/devices/application/' +
|
||||
this.props.packageName +
|
||||
'/versions',
|
||||
)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
let selectItem;
|
||||
selectItem = JSON.parse(res.data.data).map(data => (
|
||||
<Option value={data} key={data}>
|
||||
{data}
|
||||
</Option>
|
||||
));
|
||||
this.setState({ selectItem, loading: false });
|
||||
}
|
||||
})
|
||||
.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 application list.',
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onChange = value => {
|
||||
this.props.getVersion(value);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { selectItem, loading } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
defaultValue={'all'}
|
||||
showSearch
|
||||
style={{ width: 200 }}
|
||||
placeholder="Select app version"
|
||||
optionFilterProp="children"
|
||||
onChange={this.onChange}
|
||||
loading={loading}
|
||||
filterOption={(input, option) =>
|
||||
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >=
|
||||
0
|
||||
}
|
||||
>
|
||||
<Option value={'all'} key={'all'}>
|
||||
All
|
||||
</Option>
|
||||
{selectItem}
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(AppVersionDropDown);
|
||||
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 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 { Icon, message, notification, Table, Tag, Tooltip } from 'antd';
|
||||
import TimeAgo from 'javascript-time-ago';
|
||||
// Load locale-specific relative date/time formatting rules.
|
||||
import en from 'javascript-time-ago/locale/en';
|
||||
import { withConfigContext } from '../../../context/ConfigContext';
|
||||
|
||||
let config = null;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Device',
|
||||
dataIndex: 'name',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Type',
|
||||
dataIndex: 'type',
|
||||
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>
|
||||
);
|
||||
},
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Owner',
|
||||
dataIndex: 'enrolmentInfo',
|
||||
key: 'owner',
|
||||
render: enrolmentInfo => enrolmentInfo.owner,
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Ownership',
|
||||
dataIndex: 'enrolmentInfo',
|
||||
key: 'ownership',
|
||||
render: enrolmentInfo => enrolmentInfo.ownership,
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Status',
|
||||
dataIndex: 'enrolmentInfo',
|
||||
key: 'status',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: enrolmentInfo => {
|
||||
const status = enrolmentInfo.status.toLowerCase();
|
||||
let color = '#f9ca24';
|
||||
switch (status) {
|
||||
case 'active':
|
||||
color = '#badc58';
|
||||
break;
|
||||
case 'created':
|
||||
color = '#6ab04c';
|
||||
break;
|
||||
case 'removed':
|
||||
color = '#ff7979';
|
||||
break;
|
||||
case 'inactive':
|
||||
color = '#f9ca24';
|
||||
break;
|
||||
case 'blocked':
|
||||
color = '#636e72';
|
||||
break;
|
||||
}
|
||||
return <Tag color={color}>{status}</Tag>;
|
||||
},
|
||||
// todo add filtering options
|
||||
},
|
||||
{
|
||||
title: 'Last Updated',
|
||||
dataIndex: 'enrolmentInfo',
|
||||
key: 'dateOfLastUpdate',
|
||||
// eslint-disable-next-line react/display-name
|
||||
render: data => {
|
||||
const { dateOfLastUpdate } = data;
|
||||
const timeAgoString = getTimeAgo(dateOfLastUpdate);
|
||||
return (
|
||||
<Tooltip title={new Date(dateOfLastUpdate).toString()}>
|
||||
{timeAgoString}
|
||||
</Tooltip>
|
||||
);
|
||||
},
|
||||
// todo add filtering options
|
||||
},
|
||||
];
|
||||
|
||||
const getTimeAgo = time => {
|
||||
const timeAgo = new TimeAgo('en-US');
|
||||
return timeAgo.format(time);
|
||||
};
|
||||
|
||||
class ReportDeviceTable 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() {
|
||||
if (this.props.apiUrl) {
|
||||
this.fetch();
|
||||
}
|
||||
}
|
||||
|
||||
// Rerender component when parameters change
|
||||
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||
if (prevProps.apiUrl !== this.props.apiUrl) {
|
||||
this.fetch();
|
||||
}
|
||||
}
|
||||
|
||||
// fetch data from api
|
||||
fetch = (params = {}) => {
|
||||
this.setState({ loading: true });
|
||||
// get current page
|
||||
const currentPage = params.hasOwnProperty('page') ? params.page : 1;
|
||||
|
||||
const extraParams = {
|
||||
offset: 10 * (currentPage - 1), // calculate the offset
|
||||
limit: 10,
|
||||
};
|
||||
|
||||
const encodedExtraParams = Object.keys(extraParams)
|
||||
.map(key => key + '=' + extraParams[key])
|
||||
.join('&');
|
||||
|
||||
// send request to the invokerss
|
||||
axios
|
||||
.get(this.props.apiUrl + encodedExtraParams)
|
||||
.then(res => {
|
||||
if (res.status === 200) {
|
||||
const pagination = { ...this.state.pagination };
|
||||
this.setState({
|
||||
loading: false,
|
||||
data: res.data.data,
|
||||
pagination,
|
||||
});
|
||||
}
|
||||
})
|
||||
.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 devices.',
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({ loading: false });
|
||||
});
|
||||
};
|
||||
|
||||
handleTableChange = (pagination, filters, sorter) => {
|
||||
const pager = { ...this.state.pagination };
|
||||
pager.current = pagination.current;
|
||||
this.setState({
|
||||
pagination: pager,
|
||||
});
|
||||
this.fetch({
|
||||
results: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
sortField: sorter.field,
|
||||
sortOrder: sorter.order,
|
||||
...filters,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { data, pagination, loading } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey={record =>
|
||||
record.deviceIdentifier +
|
||||
record.enrolmentInfo.owner +
|
||||
record.enrolmentInfo.ownership
|
||||
}
|
||||
dataSource={data.devices}
|
||||
pagination={{
|
||||
...pagination,
|
||||
size: 'small',
|
||||
total: data.count,
|
||||
showTotal: (total, range) =>
|
||||
`showing ${range[0]}-${range[1]} of ${total} devices`,
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={this.handleTableChange}
|
||||
rowSelection={this.rowSelection}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withConfigContext(ReportDeviceTable);
|
||||
@ -31,6 +31,7 @@ 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';
|
||||
import AppNotInstalledDevicesReport from './components/Reports/Templates/AppNotInstalledDevicesReport';
|
||||
|
||||
const routes = [
|
||||
{
|
||||
@ -128,6 +129,11 @@ const routes = [
|
||||
component: DeviceStatusReport,
|
||||
exact: true,
|
||||
},
|
||||
{
|
||||
path: '/entgra/reports/app-not-installed',
|
||||
component: AppNotInstalledDevicesReport,
|
||||
exact: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@ -146,6 +146,35 @@ class PolicyReportHome extends React.Component {
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
|
||||
<Col span={8}>
|
||||
<Link
|
||||
to={{
|
||||
// Path to respective report page
|
||||
pathname: '/entgra/reports/app-not-installed',
|
||||
data: {
|
||||
name: 'app_not_installed_devices_report',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Card
|
||||
bordered={true}
|
||||
hoverable={true}
|
||||
style={{ borderRadius: 10, marginBottom: 16 }}
|
||||
>
|
||||
<div align="center">
|
||||
<Icon
|
||||
type="desktop"
|
||||
style={{ fontSize: '25px', color: '#08c' }}
|
||||
/>
|
||||
<h2>
|
||||
<b>App NOT Installed Devices Report</b>
|
||||
</h2>
|
||||
<p>Report for all device types</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.jaxrs.beans;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ApplicationList extends BasePaginatedResult{
|
||||
|
||||
private List<Application> applicationList = new ArrayList<>();
|
||||
|
||||
@ApiModelProperty(value = "List of applications returned")
|
||||
@JsonProperty("applications")
|
||||
public List<Application> getList() {
|
||||
return applicationList;
|
||||
}
|
||||
|
||||
public void setList(List<Application> applicationList) {
|
||||
this.applicationList = applicationList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{\n");
|
||||
sb.append(" count: ").append(getCount()).append(",\n");
|
||||
sb.append(" applications: [").append(applicationList).append("\n");
|
||||
sb.append("]}\n");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -60,6 +60,7 @@ import org.wso2.carbon.device.mgt.common.policy.mgt.Policy;
|
||||
import org.wso2.carbon.device.mgt.common.policy.mgt.monitor.NonComplianceData;
|
||||
import org.wso2.carbon.device.mgt.common.search.PropertyMap;
|
||||
import org.wso2.carbon.device.mgt.common.search.SearchContext;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.beans.ApplicationList;
|
||||
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.OperationRequest;
|
||||
@ -80,7 +81,6 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Device related REST-API. This can be used to manipulated device related details.
|
||||
@ -2028,4 +2028,111 @@ public interface DeviceManagementService {
|
||||
required = true)
|
||||
@PathParam("id")
|
||||
int id);
|
||||
|
||||
@GET
|
||||
@Path("/{device-type}/applications")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of Applications",
|
||||
notes = "Provides details of installed applications in all the devices enrolled with Entgra IoT Server.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:applications")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully fetched the list of applications.",
|
||||
response = ApplicationList.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 = 404,
|
||||
message = "Not Found. \n There are no applications.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Error occurred while getting the application data.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getApplications(
|
||||
@ApiParam(
|
||||
name = "device-type",
|
||||
value = "Device type (platform) of the application",
|
||||
required = true)
|
||||
@PathParam("device-type")
|
||||
String deviceType,
|
||||
@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 = "10")
|
||||
@QueryParam("limit")
|
||||
int limit);
|
||||
|
||||
@GET
|
||||
@Path("/application/{package-name}/versions")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting versions of a given application",
|
||||
notes = "Provides versions of a given application installed in devices of Entgra IoT Server.",
|
||||
tags = "Device Management",
|
||||
extensions = {
|
||||
@Extension(properties = {
|
||||
@ExtensionProperty(name = Constants.SCOPE, value = "perm:devices:applications")
|
||||
})
|
||||
}
|
||||
)
|
||||
@ApiResponses(
|
||||
value = {
|
||||
@ApiResponse(
|
||||
code = 200,
|
||||
message = "OK. \n Successfully fetched the list of app versions.",
|
||||
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 = 500,
|
||||
message = "Error occurred while getting the version data.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getAppVersions(
|
||||
@ApiParam(
|
||||
name = "package-name",
|
||||
value = "The package name of the app.",
|
||||
required = true)
|
||||
@PathParam("package-name")
|
||||
String packageName);
|
||||
}
|
||||
|
||||
@ -35,6 +35,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.util.Constants;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
@ -369,4 +370,77 @@ public interface ReportManagementService {
|
||||
defaultValue = "5")
|
||||
@QueryParam("limit")
|
||||
int limit);
|
||||
|
||||
@GET
|
||||
@Path("/devices/{device-type}/{package-name}/not-installed")
|
||||
@ApiOperation(
|
||||
produces = MediaType.APPLICATION_JSON,
|
||||
httpMethod = "GET",
|
||||
value = "Getting Details of Application Not Installed 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 = 404,
|
||||
message = "Not Found. \n There are no devices.",
|
||||
response = ErrorResponse.class),
|
||||
@ApiResponse(
|
||||
code = 500,
|
||||
message = "Internal Server Error. " +
|
||||
"\n Server error occurred while fetching the device list.",
|
||||
response = ErrorResponse.class)
|
||||
})
|
||||
Response getAppNotInstalledDevices(
|
||||
@ApiParam(
|
||||
name = "device-type",
|
||||
value = "The device type name, such as ios, android, windows, or fire-alarm.",
|
||||
required = true)
|
||||
@PathParam("device-type")
|
||||
String deviceType,
|
||||
@ApiParam(
|
||||
name = "package-name",
|
||||
value = "The package name of the app.",
|
||||
required = true)
|
||||
@PathParam("package-name")
|
||||
String packageName,
|
||||
@ApiParam(
|
||||
name = "app-version",
|
||||
value = "Version of the app")
|
||||
@QueryParam("app-version") String version,
|
||||
@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);
|
||||
}
|
||||
|
||||
@ -87,6 +87,7 @@ 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.beans.ApplicationList;
|
||||
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;
|
||||
@ -108,7 +109,6 @@ import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
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;
|
||||
@ -1106,4 +1106,58 @@ public class DeviceManagementServiceImpl implements DeviceManagementService {
|
||||
new ErrorResponse.ErrorResponseBuilder().setMessage(msg).build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Override
|
||||
@Path("/{device-type}/applications")
|
||||
public Response getApplications(
|
||||
@PathParam("device-type") String deviceType,
|
||||
@DefaultValue("0")
|
||||
@QueryParam("offset") int offset,
|
||||
@DefaultValue("10")
|
||||
@QueryParam("limit") int limit) {
|
||||
PaginationRequest request = new PaginationRequest(offset, limit);
|
||||
ApplicationList applicationList = new ApplicationList();
|
||||
request.setDeviceType(deviceType);
|
||||
try {
|
||||
PaginationResult paginationResult = DeviceMgtAPIUtils
|
||||
.getDeviceManagementService()
|
||||
.getApplications(request);
|
||||
|
||||
if (paginationResult.getData().isEmpty()) {
|
||||
return Response.status(Response.Status.OK)
|
||||
.entity("No applications are available under " + deviceType + " platform.").build();
|
||||
} else {
|
||||
applicationList.setList((List<Application>) paginationResult.getData());
|
||||
applicationList.setCount(paginationResult.getRecordsTotal());
|
||||
return Response.status(Response.Status.OK).entity(applicationList).build();
|
||||
}
|
||||
} catch (DeviceTypeNotFoundException e) {
|
||||
String msg = "Error occurred while retrieving application list." +
|
||||
" Device type (Application Platform): " + deviceType +
|
||||
"is not valid";
|
||||
log.error(msg);
|
||||
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
|
||||
} catch (ApplicationManagementException e) {
|
||||
String msg = "Error occurred while retrieving application list";
|
||||
log.error(msg, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/application/{package-name}/versions")
|
||||
@Override
|
||||
public Response getAppVersions(
|
||||
@PathParam("package-name") String packageName) {
|
||||
try {
|
||||
List<String> versions = DeviceMgtAPIUtils.getDeviceManagementService()
|
||||
.getAppVersions(packageName);
|
||||
return Response.status(Response.Status.OK).entity(versions).build();
|
||||
} catch (ApplicationManagementException e) {
|
||||
String msg = "Error occurred while retrieving version list for app with package name " + packageName;
|
||||
log.error(msg, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,7 @@ import org.wso2.carbon.device.mgt.jaxrs.service.api.ReportManagementService;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.service.impl.util.RequestValidationUtil;
|
||||
import org.wso2.carbon.device.mgt.jaxrs.util.DeviceMgtAPIUtils;
|
||||
|
||||
import javax.validation.constraints.Size;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DefaultValue;
|
||||
import javax.ws.rs.GET;
|
||||
@ -197,4 +198,44 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/devices/{device-type}/{package-name}/not-installed")
|
||||
@Override
|
||||
public Response getAppNotInstalledDevices(
|
||||
@PathParam("device-type") String deviceType,
|
||||
@PathParam("package-name") String packageName,
|
||||
@QueryParam("app-version") String version,
|
||||
@DefaultValue("0")
|
||||
@QueryParam("offset") int offset,
|
||||
@DefaultValue("10")
|
||||
@QueryParam("limit") int limit) {
|
||||
try {
|
||||
RequestValidationUtil.validatePaginationParameters(offset, limit);
|
||||
PaginationRequest request = new PaginationRequest(offset, limit);
|
||||
DeviceList devices = new DeviceList();
|
||||
request.setDeviceType(deviceType);
|
||||
|
||||
PaginationResult result = DeviceMgtAPIUtils.getReportManagementService()
|
||||
.getAppNotInstalledDevices(request, packageName, version);
|
||||
if (result.getData().isEmpty()) {
|
||||
return Response.status(Response.Status.OK)
|
||||
.entity("App with package name " + packageName +
|
||||
" is installed in all enrolled devices").build();
|
||||
} else {
|
||||
devices.setList((List<Device>) result.getData());
|
||||
devices.setCount(result.getRecordsTotal());
|
||||
return Response.status(Response.Status.OK).entity(devices).build();
|
||||
}
|
||||
} catch (DeviceTypeNotFoundException e) {
|
||||
String msg = "Error occurred while retrieving devices list. Device type: " + deviceType +
|
||||
"is not valid";
|
||||
log.error(msg);
|
||||
return Response.status(Response.Status.NOT_FOUND).entity(msg).build();
|
||||
} catch (ReportManagementException e) {
|
||||
String msg = "Error occurred while retrieving device list";
|
||||
log.error(msg, e);
|
||||
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(msg).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,6 +20,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.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
|
||||
@ -59,4 +60,17 @@ public interface ReportManagementService {
|
||||
*/
|
||||
PaginationResult getDevicesExpiredByOSVersion(PaginationRequest request)
|
||||
throws ReportManagementException, DeviceTypeNotFoundException;
|
||||
|
||||
/**
|
||||
* This method is used to get devices which have not installed the app with the given package name
|
||||
*
|
||||
* @param request Request object with device type
|
||||
* @param packageName Package name of the application
|
||||
* @param version Version of the application
|
||||
* @return {@link PaginationResult}
|
||||
* @throws ReportManagementException
|
||||
* @throws DeviceTypeNotFoundException
|
||||
*/
|
||||
PaginationResult getAppNotInstalledDevices(PaginationRequest request, String packageName, String version)
|
||||
throws ReportManagementException, DeviceTypeNotFoundException;
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.wso2.carbon.device.mgt.core.dao;
|
||||
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
|
||||
|
||||
import java.util.List;
|
||||
@ -38,4 +40,25 @@ public interface ApplicationDAO {
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
List<Application> getInstalledApplications(int deviceId, int enrolmentId) throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* This method is used to get a list of applications installed in all enrolled devices
|
||||
*
|
||||
* @param request Request object with limit and offset
|
||||
* @param tenantId ID of the current tenant
|
||||
* @return List of {@link Application} objects
|
||||
* @throws DeviceManagementDAOException If any database error occured
|
||||
*/
|
||||
List<Application> getApplications(PaginationRequest request, int tenantId)
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* This method is used to get a list of app versions when app package name is given.
|
||||
*
|
||||
* @param tenantId ID of the current tenant
|
||||
* @param packageName Package name of the application
|
||||
* @return String list of app versions
|
||||
* @throws DeviceManagementDAOException If any database error occured
|
||||
*/
|
||||
List<String> getAppVersions(int tenantId, String packageName) throws DeviceManagementDAOException;
|
||||
}
|
||||
|
||||
@ -634,4 +634,34 @@ public interface DeviceDAO {
|
||||
*/
|
||||
int getCountOfDeviceExpiredByOSVersion(String deviceType, long osBuildDate, int tenantId)
|
||||
throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* This method is used to get devices which have not installed the app with the given package name
|
||||
*
|
||||
* @param request Request object with device type
|
||||
* @param tenantId ID of the current tenant
|
||||
* @param packageName Package name of the application
|
||||
* @param version Version of the application
|
||||
* @return A list of device objects
|
||||
* @throws DeviceManagementDAOException Thrown if error occurs while database transactions
|
||||
*/
|
||||
List<Device> getAppNotInstalledDevices(PaginationRequest request,
|
||||
int tenantId,
|
||||
String packageName,
|
||||
String version) throws DeviceManagementDAOException;
|
||||
|
||||
/**
|
||||
* This method is used to get count if devices which have not installed the app with the given package name
|
||||
*
|
||||
* @param request Request object with device type
|
||||
* @param tenantId ID of the current tenant
|
||||
* @param packageName Package name of the application
|
||||
* @param version Version of the application
|
||||
* @return Device count
|
||||
* @throws DeviceManagementDAOException Thrown if error occurs while database transactions
|
||||
*/
|
||||
int getCountOfAppNotInstalledDevices(PaginationRequest request,
|
||||
int tenantId,
|
||||
String packageName,
|
||||
String version) throws DeviceManagementDAOException;
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ package org.wso2.carbon.device.mgt.core.dao.impl;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.Application;
|
||||
import org.wso2.carbon.device.mgt.core.dao.ApplicationDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
@ -271,6 +272,81 @@ public abstract class AbstractApplicationDAOImpl implements ApplicationDAO {
|
||||
return applications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Application> getApplications(PaginationRequest request, int tenantId)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Application> applications = new ArrayList<>();
|
||||
Application application;
|
||||
String sql = "Select " +
|
||||
"ID," +
|
||||
" NAME, " +
|
||||
"APP_IDENTIFIER, " +
|
||||
"PLATFORM, " +
|
||||
"CATEGORY, " +
|
||||
"VERSION, " +
|
||||
"TYPE, " +
|
||||
"LOCATION_URL, " +
|
||||
"IMAGE_URL, " +
|
||||
"APP_PROPERTIES, " +
|
||||
"MEMORY_USAGE, " +
|
||||
"IS_ACTIVE, " +
|
||||
"TENANT_ID " +
|
||||
"From DM_APPLICATION " +
|
||||
"WHERE PLATFORM = ? " +
|
||||
"AND TENANT_ID = ? LIMIT ? OFFSET ?";
|
||||
try {
|
||||
Connection conn = this.getConnection();
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
stmt.setString(1, request.getDeviceType());
|
||||
stmt.setInt(2, tenantId);
|
||||
stmt.setInt(3, request.getRowCount());
|
||||
stmt.setInt(4, request.getStartIndex());
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
application = loadApplication(rs);
|
||||
applications.add(application);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "SQL Error occurred while retrieving the list of Applications " +
|
||||
"installed in all enrolled devices for device type " + request.getDeviceType() +
|
||||
" under tenant id " + tenantId;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
return applications;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAppVersions(int tenantId, String packageName) throws DeviceManagementDAOException {
|
||||
String sql = "SELECT " +
|
||||
"VERSION " +
|
||||
"FROM DM_APPLICATION " +
|
||||
"WHERE TENANT_ID=? " +
|
||||
"AND APP_IDENTIFIER=?";
|
||||
try {
|
||||
Connection conn = this.getConnection();
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
stmt.setInt(1, tenantId);
|
||||
stmt.setString(2, packageName);
|
||||
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
List<String> versions = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
versions.add(rs.getString("VERSION"));
|
||||
}
|
||||
return versions;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered apps under tenant id " + tenantId;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
private Application loadApplication(ResultSet rs) throws DeviceManagementDAOException {
|
||||
ByteArrayInputStream bais;
|
||||
ObjectInputStream ois;
|
||||
|
||||
@ -1894,6 +1894,123 @@ public abstract class AbstractDeviceDAOImpl implements DeviceDAO {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Device> getAppNotInstalledDevices(
|
||||
PaginationRequest request, int tenantId, String packageName, String version)
|
||||
throws DeviceManagementDAOException {
|
||||
List<Device> devices;
|
||||
String deviceType = request.getDeviceType();
|
||||
boolean isVersionProvided = false;
|
||||
|
||||
String sql = "SELECT " +
|
||||
"d.ID AS DEVICE_ID, " +
|
||||
"d.DESCRIPTION,d.NAME AS DEVICE_NAME, " +
|
||||
"t.NAME AS DEVICE_TYPE, " +
|
||||
"d.DEVICE_IDENTIFICATION, " +
|
||||
"e.OWNER, " +
|
||||
"e.OWNERSHIP, " +
|
||||
"e.STATUS, " +
|
||||
"e.DATE_OF_LAST_UPDATE, " +
|
||||
"e.DATE_OF_ENROLMENT, " +
|
||||
"e.ID AS ENROLMENT_ID " +
|
||||
"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 " +
|
||||
"WHERE t.NAME = ? AND e.TENANT_ID = ? AND d.ID " +
|
||||
"NOT IN (SELECT m.DEVICE_ID " +
|
||||
"FROM DM_DEVICE_APPLICATION_MAPPING AS m " +
|
||||
"INNER JOIN DM_APPLICATION AS a ON m.APPLICATION_ID=a.ID " +
|
||||
"WHERE a.APP_IDENTIFIER = ?";
|
||||
|
||||
if (!StringUtils.isBlank(version)) {
|
||||
sql = sql + " AND a.VERSION = ? ";
|
||||
isVersionProvided = true;
|
||||
}
|
||||
|
||||
sql = sql + ") LIMIT ? OFFSET ?";
|
||||
|
||||
try {
|
||||
Connection conn = this.getConnection();
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
int paramIdx = 1;
|
||||
stmt.setString(paramIdx++, deviceType);
|
||||
stmt.setInt(paramIdx++, tenantId);
|
||||
stmt.setString(paramIdx++, packageName);
|
||||
if (isVersionProvided) {
|
||||
stmt.setString(paramIdx++, version);
|
||||
}
|
||||
stmt.setInt(paramIdx++, request.getRowCount());
|
||||
stmt.setInt(paramIdx, request.getStartIndex());
|
||||
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
devices = new ArrayList<>();
|
||||
while (rs.next()) {
|
||||
Device device = DeviceManagementDAOUtil.loadDevice(rs);
|
||||
devices.add(device);
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCountOfAppNotInstalledDevices(
|
||||
PaginationRequest request, int tenantId, String packageName, String version)
|
||||
throws DeviceManagementDAOException {
|
||||
String deviceType = request.getDeviceType();
|
||||
boolean isVersionProvided = false;
|
||||
|
||||
String sql = "SELECT " +
|
||||
"COUNT(d.ID) AS DEVICE_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 " +
|
||||
"WHERE t.NAME = ? AND e.TENANT_ID = ? AND d.ID " +
|
||||
"NOT IN " +
|
||||
"(SELECT m.DEVICE_ID " +
|
||||
"FROM DM_DEVICE_APPLICATION_MAPPING AS m " +
|
||||
"INNER JOIN DM_APPLICATION AS a ON m.APPLICATION_ID=a.ID " +
|
||||
"WHERE a.APP_IDENTIFIER = ?";
|
||||
|
||||
if (!StringUtils.isBlank(version)) {
|
||||
sql = sql + " AND a.VERSION = ? ";
|
||||
isVersionProvided = true;
|
||||
}
|
||||
|
||||
sql = sql + ")";
|
||||
|
||||
try {
|
||||
Connection conn = this.getConnection();
|
||||
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
||||
int paramIdx = 1;
|
||||
stmt.setString(paramIdx++, deviceType);
|
||||
stmt.setInt(paramIdx++, tenantId);
|
||||
stmt.setString(paramIdx++, packageName);
|
||||
if (isVersionProvided) {
|
||||
stmt.setString(paramIdx, version);
|
||||
}
|
||||
try (ResultSet rs = stmt.executeQuery()) {
|
||||
int deviceCount = 0;
|
||||
if (rs.next()) {
|
||||
deviceCount = rs.getInt("DEVICE_COUNT");
|
||||
}
|
||||
return deviceCount;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while retrieving information of all " +
|
||||
"registered devices under tenant id " + tenantId;
|
||||
log.error(msg, e);
|
||||
throw new DeviceManagementDAOException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* This method removes records of a given list of devices from the DM_DEVICE_DETAIL table
|
||||
* @param conn Connection object
|
||||
|
||||
@ -23,12 +23,15 @@ 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.app.mgt.Application;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationRequest;
|
||||
import org.wso2.carbon.device.mgt.common.PaginationResult;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.ReportManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.report.mgt.ReportManagementService;
|
||||
import org.wso2.carbon.device.mgt.core.dao.ApplicationDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||
@ -39,7 +42,6 @@ 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;
|
||||
@ -54,9 +56,11 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
private static final Log log = LogFactory.getLog(ReportManagementServiceImpl.class);
|
||||
|
||||
private DeviceDAO deviceDAO;
|
||||
private ApplicationDAO applicationDAO;
|
||||
|
||||
public ReportManagementServiceImpl() {
|
||||
this.deviceDAO = DeviceManagementDAOFactory.getDeviceDAO();
|
||||
this.applicationDAO = DeviceManagementDAOFactory.getApplicationDAO();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -270,4 +274,62 @@ public class ReportManagementServiceImpl implements ReportManagementService {
|
||||
}
|
||||
return resultObject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginationResult getAppNotInstalledDevices(PaginationRequest request, String packageName, String version)
|
||||
throws ReportManagementException, DeviceTypeNotFoundException {
|
||||
PaginationResult paginationResult = new PaginationResult();
|
||||
if(StringUtils.isBlank(packageName)){
|
||||
String msg = "Error, application package name is not given";
|
||||
log.error(msg);
|
||||
throw new ReportManagementException(msg);
|
||||
}
|
||||
try {
|
||||
int tenantId = DeviceManagementDAOUtil.getTenantId();
|
||||
request = DeviceManagerUtil.validateDeviceListPageSize(request);
|
||||
|
||||
String deviceType = request.getDeviceType();
|
||||
DeviceType deviceTypeObj = DeviceManagerUtil.getDeviceType(
|
||||
deviceType, tenantId);
|
||||
if (deviceTypeObj == null) {
|
||||
String msg = "Error, device of type: " + deviceType + " does not exist";
|
||||
log.error(msg);
|
||||
throw new DeviceTypeNotFoundException(msg);
|
||||
}
|
||||
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
List<Device> devices = deviceDAO.getAppNotInstalledDevices(
|
||||
request,
|
||||
tenantId,
|
||||
packageName,
|
||||
version
|
||||
);
|
||||
paginationResult.setData(devices);
|
||||
int deviceCount = deviceDAO.getCountOfAppNotInstalledDevices(
|
||||
request,
|
||||
tenantId,
|
||||
packageName,
|
||||
version);
|
||||
paginationResult.setRecordsTotal(deviceCount);
|
||||
return paginationResult;
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection " +
|
||||
"to the data source";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} finally {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
|
||||
} catch (DeviceManagementException e) {
|
||||
String msg = "Error occurred while validating device list page size";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred while retrieving Tenant ID";
|
||||
log.error(msg, e);
|
||||
throw new ReportManagementException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
|
||||
import org.wso2.carbon.device.mgt.common.MonitoringOperation;
|
||||
import org.wso2.carbon.device.mgt.common.StartupOperationConfig;
|
||||
import org.wso2.carbon.device.mgt.common.OperationMonitoringTaskConfig;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
@ -855,4 +856,23 @@ public interface DeviceManagementProviderService {
|
||||
*/
|
||||
PaginationResult getAppSubscribedDevices(int offsetValue, int limitValue,
|
||||
List<Integer> devicesIds, String status) throws DeviceManagementException;
|
||||
|
||||
/**
|
||||
* This method is used to get a list of applications installed in all enrolled devices
|
||||
*
|
||||
* @param request Request object with limit and offset
|
||||
* @return {@link PaginationResult}
|
||||
* @throws ApplicationManagementException if any service level or DAO level error occurs.
|
||||
*/
|
||||
PaginationResult getApplications(PaginationRequest request)
|
||||
throws ApplicationManagementException, DeviceTypeNotFoundException;
|
||||
|
||||
/**
|
||||
* This method is used to get a list of app versions when app package name is given.
|
||||
*
|
||||
* @param packageName Package name of the application
|
||||
* @return String list of app versions
|
||||
* @throws ApplicationManagementException if any service level or DAO level error occurs.
|
||||
*/
|
||||
List<String> getAppVersions(String packageName) throws ApplicationManagementException;
|
||||
}
|
||||
|
||||
@ -63,6 +63,7 @@ import org.wso2.carbon.device.mgt.common.DeviceTransferRequest;
|
||||
import org.wso2.carbon.device.mgt.common.DevicePropertyNotification;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceEnrollmentInfoNotification;
|
||||
import org.wso2.carbon.device.mgt.common.DeviceNotification;
|
||||
import org.wso2.carbon.device.mgt.common.app.mgt.ApplicationManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceManagementException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceNotFoundException;
|
||||
import org.wso2.carbon.device.mgt.common.exceptions.DeviceTypeNotFoundException;
|
||||
@ -114,6 +115,7 @@ import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
|
||||
import org.wso2.carbon.device.mgt.core.dao.DeviceTypeDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.EnrollmentDAO;
|
||||
import org.wso2.carbon.device.mgt.core.dao.util.DeviceManagementDAOUtil;
|
||||
import org.wso2.carbon.device.mgt.core.device.details.mgt.DeviceInformationManager;
|
||||
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsDAO;
|
||||
import org.wso2.carbon.device.mgt.core.device.details.mgt.dao.DeviceDetailsMgtDAOException;
|
||||
@ -3967,6 +3969,76 @@ public class DeviceManagementProviderServiceImpl implements DeviceManagementProv
|
||||
return paginationResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaginationResult getApplications(PaginationRequest request)
|
||||
throws ApplicationManagementException, DeviceTypeNotFoundException {
|
||||
PaginationResult paginationResult = new PaginationResult();
|
||||
try {
|
||||
int tenantId = DeviceManagementDAOUtil.getTenantId();
|
||||
request = DeviceManagerUtil.validateDeviceListPageSize(request);
|
||||
|
||||
String deviceType = request.getDeviceType();
|
||||
DeviceType deviceTypeObj = DeviceManagerUtil.getDeviceType(
|
||||
deviceType, tenantId);
|
||||
if (deviceTypeObj == null) {
|
||||
String msg = "Error, device of type (application platform): " + deviceType + " does not exist";
|
||||
log.error(msg);
|
||||
throw new DeviceTypeNotFoundException(msg);
|
||||
}
|
||||
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
List<Application> applicationList = applicationDAO.getApplications(
|
||||
request,
|
||||
tenantId
|
||||
);
|
||||
paginationResult.setData(applicationList);
|
||||
paginationResult.setRecordsTotal(applicationList.size());
|
||||
return paginationResult;
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection " +
|
||||
"to the data source";
|
||||
log.error(msg, e);
|
||||
throw new ApplicationManagementException(msg, e);
|
||||
} finally {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
|
||||
} catch (DeviceManagementException e) {
|
||||
String msg = "Error occurred while validating device list page size";
|
||||
log.error(msg, e);
|
||||
throw new ApplicationManagementException(msg, e);
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred while retrieving Tenant ID";
|
||||
log.error(msg, e);
|
||||
throw new ApplicationManagementException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getAppVersions(String packageName)
|
||||
throws ApplicationManagementException {
|
||||
try {
|
||||
DeviceManagementDAOFactory.openConnection();
|
||||
List<String> versions = applicationDAO.getAppVersions(
|
||||
DeviceManagementDAOUtil.getTenantId(),
|
||||
packageName
|
||||
);
|
||||
return versions;
|
||||
} catch (SQLException e) {
|
||||
String msg = "Error occurred while opening a connection " +
|
||||
"to the data source";
|
||||
log.error(msg, e);
|
||||
throw new ApplicationManagementException(msg, e);
|
||||
} catch (DeviceManagementDAOException e) {
|
||||
String msg = "Error occurred while retrieving Tenant ID";
|
||||
log.error(msg, e);
|
||||
throw new ApplicationManagementException(msg, e);
|
||||
} finally {
|
||||
DeviceManagementDAOFactory.closeConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the device configuration data into DeviceConfiguration bean
|
||||
* @param device Device queried using the properties
|
||||
|
||||
Loading…
Reference in New Issue
Block a user