diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json index 9d78b67906..e6c00f0849 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/public/conf/config.json @@ -6,6 +6,7 @@ }, "serverConfig": { "invoker": { + "contextPath" : "/publisher-ui-request-handler", "uri": "/publisher-ui-request-handler/invoke", "publisher": "/application-mgt-publisher/v1.0", "store": "/application-mgt-store/v1.0", diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js index 177d362c3e..78a387b656 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/App.js @@ -106,37 +106,24 @@ class App extends React.Component { checkUserLoggedIn = config => { axios .post( - window.location.origin + '/publisher-ui-request-handler/user', - 'platform=publisher', + window.location.origin + + config.serverConfig.invoker.contextPath + + '/user', ) .then(res => { - config.user = res.data.data; + config.user = { + username: res.data.data, + }; const pageURL = window.location.pathname; const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1); if (lastURLSegment === 'login') { window.location.href = window.location.origin + '/publisher/'; } else { - this.getAndroidEnterpriseToken(config); + this.getUserPermissions(config); } }) .catch(error => { - if (error.hasOwnProperty('response') && error.response.status === 401) { - const redirectUrl = encodeURI(window.location.href); - const pageURL = window.location.pathname; - const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1); - if (lastURLSegment !== 'login') { - window.location.href = - window.location.origin + - `/publisher/login?redirect=${redirectUrl}`; - } else { - this.getAndroidEnterpriseToken(config); - } - } else { - this.setState({ - loading: false, - error: true, - }); - } + this.handleApiError(error, config); }); }; @@ -152,6 +139,42 @@ class App extends React.Component { document.getElementsByTagName('head')[0].appendChild(link); }; + getUserPermissions = config => { + axios + .get( + window.location.origin + + config.serverConfig.invoker.uri + + config.serverConfig.invoker.deviceMgt + + '/users/current-user/permissions', + ) + .then(res => { + config.user.permissions = res.data.data.permissions; + this.getAndroidEnterpriseToken(config); + }) + .catch(error => { + this.handleApiError(error, config); + }); + }; + + handleApiError = (error, config) => { + if (error.hasOwnProperty('response') && error.response.status === 401) { + const redirectUrl = encodeURI(window.location.href); + const pageURL = window.location.pathname; + const lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1); + if (lastURLSegment !== 'login') { + window.location.href = + window.location.origin + `/publisher/login?redirect=${redirectUrl}`; + } else { + this.getAndroidEnterpriseToken(config); + } + } else { + this.setState({ + loading: false, + error: true, + }); + } + }; + render() { const { loading, error } = this.state; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/Authorized/Authorized.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/Authorized/Authorized.js new file mode 100644 index 0000000000..7f06a0403c --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/components/Authorized/Authorized.js @@ -0,0 +1,39 @@ +/* + * 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 { withConfigContext } from '../ConfigContext'; +import { isAuthorized } from '../../services/utils/authorizationHandler'; + +class Authorized extends react.Component { + constructor(props) { + super(props); + } + + render() { + return isAuthorized(this.props.context.user, this.props.permission) + ? this.props.yes + : this.props.no; + } +} + +Authorized.defaultProps = { + yes: null, + no: null, +}; +export default withConfigContext(Authorized); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/index.js index c21ade6196..983e74c07b 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/index.js @@ -24,6 +24,7 @@ import { Redirect } from 'react-router'; import './styles.css'; import { withConfigContext } from '../../components/ConfigContext'; import Logout from './components/Logout'; +import { isAuthorized } from '../../services/utils/authorizationHandler'; const { Header, Content, Footer } = Layout; const { SubMenu } = Menu; @@ -84,33 +85,36 @@ class Dashboard extends React.Component { Apps - - - - Add New App - - } - > - - Public App - - - - Enterprise App - - - - Web Clip - - - - Custom App - - - - + {isAuthorized( + this.props.context.user, + '/permission/admin/app-mgt/publisher/application/update', + ) && ( + + + Add New App + + } + > + + Public App + + + + Enterprise App + + + + Web Clip + + + + Custom App + + + + )} @@ -139,7 +143,7 @@ class Dashboard extends React.Component { title={ - {this.config.user} + {this.config.username} } > diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppDetailsForm/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppDetailsForm/index.js index f4e4bababa..c5f6c5389d 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppDetailsForm/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppDetailsForm/index.js @@ -22,6 +22,7 @@ import axios from 'axios'; import { withConfigContext } from '../../../../../../../../components/ConfigContext'; import { handleApiError } from '../../../../../../../../services/utils/errorHandler'; import debounce from 'lodash.debounce'; +import Authorized from '../../../../../../../../components/Authorized/Authorized'; const formItemLayout = { labelCol: { @@ -46,12 +47,6 @@ class NewAppDetailsForm extends React.Component { fetching: false, roleSearchValue: [], unrestrictedRoles: [], - forbiddenErrors: { - categories: false, - tags: false, - deviceTypes: false, - roles: false, - }, }; this.lastFetchId = 0; this.fetchRoles = debounce(this.fetchRoles, 800); @@ -127,18 +122,9 @@ class NewAppDetailsForm extends React.Component { 'Error occurred while trying to load categories.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.categories = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; @@ -166,18 +152,9 @@ class NewAppDetailsForm extends React.Component { 'Error occurred while trying to load tags.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.tags = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; @@ -279,18 +256,9 @@ class NewAppDetailsForm extends React.Component { 'Error occurred while trying to load roles.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.roles = true; - this.setState({ - forbiddenErrors, - fetching: false, - }); - } else { - this.setState({ - fetching: false, - }); - } + this.setState({ + fetching: false, + }); }); }; @@ -310,7 +278,6 @@ class NewAppDetailsForm extends React.Component { deviceTypes, fetching, unrestrictedRoles, - forbiddenErrors, } = this.state; const { getFieldDecorator } = this.props.form; @@ -326,14 +293,17 @@ class NewAppDetailsForm extends React.Component { > {formConfig.installationType !== 'WEB_CLIP' && ( - {forbiddenErrors.deviceTypes && ( - - )} + + } + /> {getFieldDecorator('deviceType', { rules: [ @@ -387,14 +357,16 @@ class NewAppDetailsForm extends React.Component { {/* Unrestricted Roles*/} - {forbiddenErrors.roles && ( - - )} + + } + /> {getFieldDecorator('unrestrictedRoles', { rules: [], @@ -417,14 +389,6 @@ class NewAppDetailsForm extends React.Component { , )} - {forbiddenErrors.categories && ( - - )} {getFieldDecorator('categories', { rules: [ @@ -450,14 +414,6 @@ class NewAppDetailsForm extends React.Component { , )} - {forbiddenErrors.tags && ( - - )} {getFieldDecorator('tags', { rules: [ diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppUploadForm/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppUploadForm/index.js index 6e1f0ec7de..1073adbd78 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppUploadForm/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/components/AddNewAppForm/components/NewAppUploadForm/index.js @@ -31,6 +31,7 @@ import { Alert, } from 'antd'; import '@babel/polyfill'; +import Authorized from '../../../../../../../../components/Authorized/Authorized'; const { Text } = Typography; @@ -466,14 +467,16 @@ class NewAppUploadForm extends React.Component { {formConfig.installationType !== 'WEB_CLIP' && formConfig.installationType !== 'CUSTOM' && ( - {this.props.forbiddenErrors.supportedOsVersions && ( - - )} + + } + /> - + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Enterprise/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Enterprise/index.js index e870daa7a1..0e199439d8 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Enterprise/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Enterprise/index.js @@ -17,9 +17,10 @@ */ import React from 'react'; -import { PageHeader, Typography, Breadcrumb, Icon } from 'antd'; +import { PageHeader, Typography, Breadcrumb, Icon, Result } from 'antd'; import AddNewAppForm from '../../components/AddNewAppForm'; import { Link } from 'react-router-dom'; +import Authorized from '../../../../../../components/Authorized/Authorized'; const { Paragraph } = Typography; @@ -64,7 +65,17 @@ class AddNewEnterpriseApp extends React.Component { - + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Public/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Public/index.js index 349089fba7..987da9a2ce 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Public/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/Public/index.js @@ -17,9 +17,10 @@ */ import React from 'react'; -import { Icon, PageHeader, Typography, Breadcrumb } from 'antd'; +import { Icon, PageHeader, Typography, Breadcrumb, Result } from 'antd'; import AddNewAppForm from '../../components/AddNewAppForm'; import { Link } from 'react-router-dom'; +import Authorized from '../../../../../../components/Authorized/Authorized'; const { Paragraph } = Typography; @@ -72,7 +73,17 @@ class AddNewPublicApp extends React.Component { - + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/WebClip/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/WebClip/index.js index 388d6a4d14..c002c68756 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/WebClip/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/AddNewApp/scenes/WebClip/index.js @@ -17,9 +17,10 @@ */ import React from 'react'; -import { Icon, PageHeader, Typography, Breadcrumb } from 'antd'; +import { Icon, PageHeader, Typography, Breadcrumb, Result } from 'antd'; import AddNewAppForm from '../../components/AddNewAppForm'; import { Link } from 'react-router-dom'; +import Authorized from '../../../../../../components/Authorized/Authorized'; const { Paragraph } = Typography; @@ -65,7 +66,17 @@ class AddNewEnterpriseApp extends React.Component { - + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/ApssTable/AppDetailsDrawer/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/ApssTable/AppDetailsDrawer/index.js index 41fc9f10d9..277b5ada8a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/ApssTable/AppDetailsDrawer/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/ApssTable/AppDetailsDrawer/index.js @@ -44,6 +44,8 @@ import pSBC from 'shade-blend-color'; import { withConfigContext } from '../../../../../../../../../components/ConfigContext'; import ManagedConfigurationsIframe from './components/ManagedConfigurationsIframe'; import { handleApiError } from '../../../../../../../../../services/utils/errorHandler'; +import Authorized from '../../../../../../../../../components/Authorized/Authorized'; +import { isAuthorized } from '../../../../../../../../../services/utils/authorizationHandler'; const { Meta } = Card; const { Text, Title } = Typography; @@ -100,7 +102,15 @@ class AppDetailsDrawer extends React.Component { } componentDidMount() { - this.getCategories(); + if ( + isAuthorized( + this.props.context.user, + '/permission/admin/app-mgt/publisher/application/update', + ) + ) { + this.getCategories(); + this.getTags(); + } } componentDidUpdate(prevProps, prevState, snapshot) { @@ -130,7 +140,6 @@ class AppDetailsDrawer extends React.Component { .then(res => { if (res.status === 200) { const categories = JSON.parse(res.data.data); - this.getTags(); const globalCategories = categories.map(category => { return ( @@ -520,36 +529,48 @@ class AppDetailsDrawer extends React.Component { {avatar} - - {name} - + + {name} + + } + no={{name}} + /> {/* display manage config button only if the app is public android app*/} {app.isAndroidEnterpriseApp && config.androidEnterpriseToken !== null && ( - - - Set up managed configurations - - - - If you are developing apps for the enterprise market, you - may need to satisfy particular requirements set by a - organization's policies. Managed configurations, - previously known as application restrictions, allow the - organization's IT admin to remotely specify settings - for apps. This capability is particularly useful for - organization-approved apps deployed to a work profile. - - - - - - + + + Set up managed configurations + + + + If you are developing apps for the enterprise market, + you may need to satisfy particular requirements set by + a organization's policies. Managed + configurations, previously known as application + restrictions, allow the organization's IT admin + to remotely specify settings for apps. This capability + is particularly useful for organization-approved apps + deployed to a work profile. + + + + + + + } + /> )} Releases @@ -640,34 +661,44 @@ class AppDetailsDrawer extends React.Component { {/* display add new release only if app type is enterprise*/} {app.type === 'ENTERPRISE' && ( - - - - Add new release for the application - - - - Add - - - + + + + Add new release for the application + + + + Add + + + + } + /> )} Description - {!isDescriptionEditEnabled && ( - - - - )} + + + + ) + } + /> {!isDescriptionEditEnabled && ( {ReactHtmlParser(description)} @@ -708,14 +739,22 @@ class AppDetailsDrawer extends React.Component { Categories - {!isCategoriesEditEnabled && ( - - - - )} + + + + ) + } + /> {isCategoriesEditEnabled && ( @@ -767,14 +806,22 @@ class AppDetailsDrawer extends React.Component { Tags - {!isTagsEditEnabled && ( - - - - )} + + + + ) + } + /> {isTagsEditEnabled && ( @@ -819,17 +866,22 @@ class AppDetailsDrawer extends React.Component { })} )} - - - - - {app.applicationReleases.length > 0 && ( - - )} - + + + + {app.applicationReleases.length > 0 && ( + + )} + + + } + /> diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/Filters/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/Filters/index.js index f81721f6a0..8ddbb6e0c4 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/Filters/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/components/AppList/components/Filters/index.js @@ -26,11 +26,11 @@ import { Select, Button, Form, - Alert, } from 'antd'; import axios from 'axios'; import { withConfigContext } from '../../../../../../../../components/ConfigContext'; import { handleApiError } from '../../../../../../../../services/utils/errorHandler'; +import Authorized from '../../../../../../../../components/Authorized/Authorized'; const { Option } = Select; const { Title } = Typography; @@ -42,11 +42,6 @@ class FiltersForm extends React.Component { categories: [], tags: [], deviceTypes: [], - forbiddenErrors: { - categories: false, - tags: false, - deviceTypes: false, - }, }; } @@ -101,18 +96,9 @@ class FiltersForm extends React.Component { 'Error occurred while trying to load categories.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.categories = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; @@ -140,18 +126,9 @@ class FiltersForm extends React.Component { 'Error occurred while trying to load tags.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.tags = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; @@ -179,23 +156,14 @@ class FiltersForm extends React.Component { 'Error occurred while trying to load device types.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.deviceTypes = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; render() { - const { categories, tags, deviceTypes, forbiddenErrors } = this.state; + const { categories, tags, deviceTypes } = this.state; const { getFieldDecorator } = this.props.form; return ( @@ -224,99 +192,85 @@ class FiltersForm extends React.Component { - {forbiddenErrors.categories && ( - - )} - - {getFieldDecorator('categories', { - rules: [ - { - required: false, - message: 'Please select categories', - }, - ], - })( - - {categories.map(category => { - return ( - - {category.categoryName} - - ); - })} - , - )} - - - {forbiddenErrors.deviceTypes && ( - - )} - - {getFieldDecorator('deviceType', { - rules: [ - { - required: false, - message: 'Please select device types', - }, - ], - })( - - {deviceTypes.map(deviceType => { - return ( - {deviceType.name} - ); - })} - All - , - )} - - {forbiddenErrors.tags && ( - - )} - - {getFieldDecorator('tags', { - rules: [ - { - required: false, - message: 'Please select tags', - }, - ], - })( - - {tags.map(tag => { - return {tag.tagName}; - })} - , - )} - - + + + {getFieldDecorator('categories', { + rules: [ + { + required: false, + message: 'Please select categories', + }, + ], + })( + + {categories.map(category => { + return ( + + {category.categoryName} + + ); + })} + , + )} + + + {getFieldDecorator('tags', { + rules: [ + { + required: false, + message: 'Please select tags', + }, + ], + })( + + {tags.map(tag => { + return {tag.tagName}; + })} + , + )} + + + } + /> + + {getFieldDecorator('deviceType', { + rules: [ + { + required: false, + message: 'Please select device types', + }, + ], + })( + + {deviceTypes.map(deviceType => { + return ( + {deviceType.name} + ); + })} + All + , + )} + + } + /> {getFieldDecorator('appType', {})( diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/index.js index 55c58e88f4..716676be3d 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/index.js @@ -18,6 +18,8 @@ import React from 'react'; import AppList from './components/AppList'; +import Authorized from '../../../../components/Authorized/Authorized'; +import { Result } from 'antd'; class Apps extends React.Component { routes; @@ -30,7 +32,17 @@ class Apps extends React.Component { return ( - + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/components/ReleaseView/components/EditRelease/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/components/ReleaseView/components/EditRelease/index.js index efcc2d0c7d..a4f7788223 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/components/ReleaseView/components/EditRelease/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/components/ReleaseView/components/EditRelease/index.js @@ -36,6 +36,7 @@ import { import axios from 'axios'; import '@babel/polyfill'; import { withConfigContext } from '../../../../../../../../../../components/ConfigContext'; +import Authorized from '../../../../../../../../../../components/Authorized/Authorized'; const { TextArea } = Input; const InputGroup = Input.Group; @@ -549,14 +550,16 @@ class EditReleaseModal extends React.Component { {config.deviceTypes.mobileTypes.includes(deviceType) && ( - {this.props.forbiddenErrors.supportedOsVersions && ( - - )} + + } + /> - {this.state.forbiddenErrors.reviews && ( - - )} Version : {release.version} - - + } /> - + { + window.open( + window.location.origin + + '/store/' + + app.deviceType + + '/apps/' + + release.uuid, + ); + }} + > + Open in store + + } - > - { - window.open( - window.location.origin + - '/store/' + - app.deviceType + - '/apps/' + - release.uuid, - ); - }} - > - Open in store - - + /> @@ -173,12 +188,27 @@ class ReleaseView extends React.Component { REVIEWS - - - - - - + + + + + + + + + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/index.js index 72d1b8abf2..7fb6cdb70e 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Apps/scenes/Release/index.js @@ -24,6 +24,8 @@ import ReleaseView from './components/ReleaseView'; import LifeCycle from './components/LifeCycle'; import { withConfigContext } from '../../../../../../components/ConfigContext'; import { handleApiError } from '../../../../../../services/utils/errorHandler'; +import Authorized from '../../../../../../components/Authorized/Authorized'; +import { isAuthorized } from '../../../../../../services/utils/authorizationHandler'; const { Title } = Typography; @@ -41,17 +43,20 @@ class Release extends React.Component { currentLifecycleStatus: null, lifecycle: null, supportedOsVersions: [], - forbiddenErrors: { - supportedOsVersions: false, - lifeCycle: false, - }, }; } componentDidMount() { const { uuid } = this.props.match.params; this.fetchData(uuid); - this.getLifecycle(); + if ( + isAuthorized( + this.props.context.user, + '/permission/admin/app-mgt/publisher/application/update', + ) + ) { + this.getLifecycle(); + } } changeCurrentLifecycleStatus = status => { @@ -92,7 +97,16 @@ class Release extends React.Component { uuid: uuid, }); if (config.deviceTypes.mobileTypes.includes(app.deviceType)) { - this.getSupportedOsVersions(app.deviceType); + if ( + isAuthorized( + config.user, + '/permission/admin/device-mgt/admin/device-type', + ) + ) { + this.getSupportedOsVersions(app.deviceType); + } else { + this.setState({ loading: false }); + } } } }) @@ -128,13 +142,6 @@ class Release extends React.Component { 'Error occurred while trying to load lifecycle configuration.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.lifeCycle = true; - this.setState({ - forbiddenErrors, - }); - } }); }; @@ -161,18 +168,9 @@ class Release extends React.Component { 'Error occurred while trying to load supported OS versions.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.supportedOsVersions = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); }; @@ -193,7 +191,6 @@ class Release extends React.Component { ); } - // todo remove uppercase return ( @@ -221,22 +218,27 @@ class Release extends React.Component { - - - - {release !== null && ( - - )} - - - + + + + {release !== null && ( + + )} + + + + } + /> diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Categories/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Categories/index.js index 930f115a38..1251709cd1 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Categories/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Categories/index.js @@ -40,6 +40,7 @@ import { TweenOneGroup } from 'rc-tween-one'; import pSBC from 'shade-blend-color'; import { withConfigContext } from '../../../../../../components/ConfigContext'; import { handleApiError } from '../../../../../../services/utils/errorHandler'; +import { isAuthorized } from '../../../../../../services/utils/authorizationHandler'; const { Title } = Typography; @@ -62,6 +63,10 @@ class ManageCategories extends React.Component { componentDidMount() { const config = this.props.context; + this.hasPermissionToManage = isAuthorized( + config.user, + '/permission/admin/app-mgt/publisher/admin/application/update', + ); axios .get( window.location.origin + @@ -84,18 +89,9 @@ class ManageCategories extends React.Component { 'Error occured while trying to load categories', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.categories = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); } @@ -157,36 +153,40 @@ class ManageCategories extends React.Component { style={{ marginTop: 8 }} > {categoryName} - - - { - this.openEditModal(categoryName); - }} - type="edit" - /> - - - - { - if (category.isCategoryDeletable) { - this.deleteCategory(categoryName); - } else { - notification.error({ - message: 'Cannot delete "' + categoryName + '"', - description: - 'This category is currently used. Please unassign the category from apps.', - }); - } - }} - okText="Yes" - cancelText="No" - > - - - + {this.hasPermissionToManage && ( + <> + + + { + this.openEditModal(categoryName); + }} + type="edit" + /> + + + + { + if (category.isCategoryDeletable) { + this.deleteCategory(categoryName); + } else { + notification.error({ + message: 'Cannot delete "' + categoryName + '"', + description: + 'This category is currently used. Please unassign the category from apps.', + }); + } + }} + okText="Yes" + cancelText="No" + > + + + + > + )} ); return ( @@ -377,18 +377,16 @@ class ManageCategories extends React.Component { inputValue, tempElements, isAddNewVisible, - forbiddenErrors, } = this.state; const categoriesElements = categories.map(this.renderElement); const temporaryElements = tempElements.map(this.renderTempElement); return ( - {forbiddenErrors.categories && ( + {!this.hasPermissionToManage && ( )} @@ -414,6 +412,7 @@ class ManageCategories extends React.Component { ); }} htmlType="button" + disabled={!this.hasPermissionToManage} > Add diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Tags/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Tags/index.js index 59a4702bc6..7acd6f9049 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Tags/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/components/Tags/index.js @@ -39,6 +39,7 @@ import axios from 'axios'; import { TweenOneGroup } from 'rc-tween-one'; import { withConfigContext } from '../../../../../../components/ConfigContext'; import { handleApiError } from '../../../../../../services/utils/errorHandler'; +import { isAuthorized } from '../../../../../../services/utils/authorizationHandler'; const { Title } = Typography; @@ -61,6 +62,10 @@ class ManageTags extends React.Component { componentDidMount() { const config = this.props.context; + this.hasPermissionToManage = isAuthorized( + config.user, + '/permission/admin/app-mgt/publisher/admin/application/update', + ); axios .get( window.location.origin + @@ -83,18 +88,9 @@ class ManageTags extends React.Component { 'Error occurred while trying to load tags.', true, ); - if (error.hasOwnProperty('response') && error.response.status === 403) { - const { forbiddenErrors } = this.state; - forbiddenErrors.tags = true; - this.setState({ - forbiddenErrors, - loading: false, - }); - } else { - this.setState({ - loading: false, - }); - } + this.setState({ + loading: false, + }); }); } @@ -151,36 +147,40 @@ class ManageTags extends React.Component { const tagElem = ( {tagName} - - - { - this.openEditModal(tagName); - }} - type="edit" - /> - - - - { - if (tag.isTagDeletable) { - this.deleteTag(tagName); - } else { - notification.error({ - message: 'Cannot delete "' + tagName + '"', - description: - 'This tag is currently used. Please unassign the tag from apps.', - }); - } - }} - okText="Yes" - cancelText="No" - > - - - + {this.hasPermissionToManage && ( + <> + + + { + this.openEditModal(tagName); + }} + type="edit" + /> + + + + { + if (tag.isTagDeletable) { + this.deleteTag(tagName); + } else { + notification.error({ + message: 'Cannot delete "' + tagName + '"', + description: + 'This tag is currently used. Please unassign the tag from apps.', + }); + } + }} + okText="Yes" + cancelText="No" + > + + + + > + )} ); return ( @@ -368,18 +368,16 @@ class ManageTags extends React.Component { inputValue, tempElements, isAddNewVisible, - forbiddenErrors, } = this.state; const tagsElements = tags.map(this.renderElement); const temporaryElements = tempElements.map(this.renderTempElement); return ( - {forbiddenErrors.tags && ( + {!this.hasPermissionToManage && ( )} @@ -405,6 +403,7 @@ class ManageTags extends React.Component { ); }} htmlType="button" + disabled={!this.hasPermissionToManage} > Add diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/index.js index d6e406760e..f0e4bc45af 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/index.js @@ -21,6 +21,7 @@ import { PageHeader, Typography, Breadcrumb, Row, Col, Icon } from 'antd'; import ManageCategories from './components/Categories'; import ManageTags from './components/Tags'; import { Link } from 'react-router-dom'; +import Authorized from '../../../../components/Authorized/Authorized'; const { Paragraph } = Typography; @@ -54,12 +55,19 @@ class Manage extends React.Component { - - - - - - + + + + + + + + > + } + /> diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/components/Pages/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/components/Pages/index.js index a8b2c9ef37..597fcc63c2 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/components/Pages/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/components/Pages/index.js @@ -34,6 +34,7 @@ import './styles.css'; import { Link } from 'react-router-dom'; import AddNewPage from './components/AddNewPage'; import { handleApiError } from '../../../../../../../../services/utils/errorHandler'; +import { isAuthorized } from '../../../../../../../../services/utils/authorizationHandler'; const { Text, Title } = Typography; @@ -47,6 +48,10 @@ class Pages extends React.Component { selectedRows: [], homePageId: null, }; + this.hasPermissionToManage = isAuthorized( + this.props.config.user, + '/device-mgt/enterprise/user/view', + ); } rowSelection = { @@ -226,34 +231,38 @@ class Pages extends React.Component { key: 'actions', render: (name, page) => ( - - { - this.updateHomePage(page.id); - }} - > - set as homepage - - - - { - this.deletePage(page.id); - }} - > - - - delete - - - + {this.hasPermissionToManage && ( + <> + + { + this.updateHomePage(page.id); + }} + > + set as homepage + + + + { + this.deletePage(page.id); + }} + > + + + delete + + + + > + )} ), }, diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/index.js index cf5608ba1c..09b57429e5 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/index.js @@ -17,12 +17,13 @@ */ import React from 'react'; -import { PageHeader, Breadcrumb, Divider, Icon } from 'antd'; +import { PageHeader, Breadcrumb, Divider, Icon, Result } from 'antd'; import { Link } from 'react-router-dom'; import SyncAndroidApps from './components/SyncAndroidApps'; import { withConfigContext } from '../../../../../../components/ConfigContext'; import GooglePlayIframe from './components/GooglePlayIframe'; import Pages from './components/Pages'; +import Authorized from '../../../../../../components/Authorized/Authorized'; class ManageAndroidEnterprise extends React.Component { routes; @@ -52,10 +53,27 @@ class ManageAndroidEnterprise extends React.Component { - - - - + + + } + /> + + + > + } + no={ + + } + /> ); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/scenes/Page/components/Cluster/index.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/scenes/Page/components/Cluster/index.js index 2a38e0ff6f..ea26c0c608 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/scenes/Page/components/Cluster/index.js +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/scenes/Home/scenes/Manage/scenes/AndroidEnterprise/scenes/Page/components/Cluster/index.js @@ -295,44 +295,50 @@ class Cluster extends React.Component { } return ( - - { - this.swapProduct(index, index - 1); - }} - > - - - + {this.props.hasPermissionToManage && ( + + { + this.swapProduct(index, index - 1); + }} + > + + + + )} {packageId} - - { - this.swapProduct(index, index + 1); - }} - className="btn btn-right" - > - - - - - { - this.removeProduct(index); - }} - > - - - + {this.props.hasPermissionToManage && ( + <> + + { + this.swapProduct(index, index + 1); + }} + className="btn btn-right" + > + + + + + { + this.removeProduct(index); + }} + > + + + + > + )} ); }; @@ -347,7 +353,7 @@ class Cluster extends React.Component { - {!isTemporary && ( + {!isTemporary && this.props.hasPermissionToManage && ( - + {this.props.hasPermissionToManage && ( + + )} {products.map((product, index) => { return ( Lorem ipsum*/} - - - - - - {pageName} - - - - - - Links - {links.map(link => { - if (this.pageNames.hasOwnProperty(link.toString())) { - return ( - - {this.pageNames[link.toString()]} - - ); - } - return null; - })} - - - {/* */} - - {/* */} - - - - Clusters - - - { - this.toggleAddNewClusterVisibility(true); - }} + + - Add new cluster - - - - - - - {clusters.map((cluster, index) => { - return ( - + + + {pageName} + + + + + + Links + {links.map(link => { + if (this.pageNames.hasOwnProperty(link.toString())) { + return ( + + {this.pageNames[link.toString()]} + + ); + } + return null; + })} + + } + /> + + {/* */} + + {/* */} + + + + Clusters + + { + this.toggleAddNewClusterVisibility(true); + }} + > + Add new cluster + + + } /> - ); - })} - - + + + + + {clusters.map((cluster, index) => { + return ( + + ); + })} + + + } + no={ + + } + /> ); } diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/authorizationHandler.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/authorizationHandler.js new file mode 100644 index 0000000000..4e939e42d1 --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/react-app/src/services/utils/authorizationHandler.js @@ -0,0 +1,24 @@ +/* + * 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. + */ + +export const isAuthorized = (user, permission) => { + if (!user || !permission) { + return false; + } + return user.permissions.includes(permission); +};