Skip to content

Commit

Permalink
Merge pull request #29 from SubstraFoundation/handle_403
Browse files Browse the repository at this point in the history
Handle 403 errors in descriptions and openers
  • Loading branch information
jmorel authored Jan 27, 2020
2 parents 6661903 + 85780d8 commit c4e1b17
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 67 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
import {RoundedButton} from '@substrafoundation/substra-ui';
import {spacingNormal} from '../../../../../../../assets/css/variables/spacing';

const Span = styled('span')`
margin-right: ${spacingNormal};
`;

class ForbiddenResource extends Component {
handleClick = () => {
const {setTabIndex, permissionsTabIndex} = this.props;
setTabIndex(permissionsTabIndex);
}

render() {
const {model, resource} = this.props;
return (
<>
<Span>
{`You do not have enough permissions to see this ${model}'s ${resource}.`}
</Span>
<RoundedButton onClick={this.handleClick}>
Learn more
</RoundedButton>
</>
);
}
}

ForbiddenResource.propTypes = {
resource: PropTypes.string.isRequired,
model: PropTypes.string.isRequired,
setTabIndex: PropTypes.func.isRequired,
permissionsTabIndex: PropTypes.number.isRequired,
};

export default ForbiddenResource;
4 changes: 4 additions & 0 deletions src/app/business/common/reducers/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export const initialState = {
init: false,
loading: false,
descLoading: false,
descForbidden: false,
error: null,
results: [],
tabIndex: 0,
Expand Down Expand Up @@ -36,6 +37,7 @@ export default (actionTypes) => (state = initialState, {type, payload}) => {
return {
...state,
descLoading: true,
descForbidden: false,
};
case actionTypes.item.description.SUCCESS:
return {
Expand All @@ -46,11 +48,13 @@ export default (actionTypes) => (state = initialState, {type, payload}) => {
...(c.pkhash === payload.id ? [{...c, description: {...c.description, content: payload.desc}}] : [c]),
], []),
descLoading: false,
descForbidden: false,
};
case actionTypes.item.description.FAILURE:
return {
...state,
descLoading: false,
descForbidden: payload.status === 403,
};
case actionTypes.item.tabIndex.SET:
return {
Expand Down
20 changes: 20 additions & 0 deletions src/app/business/common/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {replace} from 'redux-first-router';
import {omit} from 'lodash';
import cookie from 'cookie-parse';

import {fetchRaw} from '../../../entities/fetchEntities';
import {fetchRefresh} from '../../user/api';
import {refresh as refreshActions, signOut} from '../../user/actions';

Expand Down Expand Up @@ -114,11 +115,30 @@ export const setOrderSaga = function* setOrderSaga({payload}) {
replace(newUrl);
};

export const fetchItemDescriptionSaga = (actions) => function* fetchItemDescription({payload: {pkhash, url}}) {
let jwt = getJWTFromCookie();
if (!jwt) {
jwt = yield tryRefreshToken(actions.description.failure);
}

if (jwt) {
const {res, error, status} = yield call(fetchRaw, url, jwt);
if (res && status === 200) {
yield put(actions.item.description.success({pkhash, desc: res}));
}
else {
console.error(error, status);
yield put(actions.item.description.failure({pkhash, status}));
}
}
};

export default {
fetchListSaga,
fetchPersistentSaga,
fetchItemSaga,
setOrderSaga,
getJWTFromCookie,
tryRefreshToken,
fetchItemDescriptionSaga,
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ import Tab from '../../../../../../common/components/detail/components/tabs';
import Description from '../../../../../../common/components/detail/components/description';
import {spacingNormal} from '../../../../../../../../../assets/css/variables/spacing';
import PermissionsTabPanelContent from '../../../../../../common/components/detail/components/permissionsTabPanelContent';
import ForbiddenResource from '../../../../../../common/components/detail/components/forbiddenResource';

const Span = styled('span')`
margin-right: ${spacingNormal};
`;

const AlgoTabs = ({
descLoading, item, tabIndex, setTabIndex, downloadFile,
descLoading, descForbidden, item, tabIndex, setTabIndex, downloadFile,
}) => (
<Tabs
selectedIndex={tabIndex}
Expand All @@ -35,7 +36,15 @@ descLoading, item, tabIndex, setTabIndex, downloadFile,
</TabList>
<TabPanel>
{descLoading && <PulseLoader size={6} />}
{!descLoading && <Description item={item} />}
{!descLoading && descForbidden && (
<ForbiddenResource
resource="description"
model="algo"
permissionsTabIndex={2}
setTabIndex={setTabIndex}
/>
)}
{!descLoading && !descForbidden && <Description item={item} />}
</TabPanel>
<TabPanel>
<Span>The algorithm's source code and Dockerfile are packaged within a zip or tar.gz file.</Span>
Expand All @@ -57,6 +66,7 @@ descLoading, item, tabIndex, setTabIndex, downloadFile,
AlgoTabs.propTypes = {
item: PropTypes.shape(),
descLoading: PropTypes.bool,
descForbidden: PropTypes.bool,
tabIndex: PropTypes.number,
setTabIndex: PropTypes.func,
downloadFile: PropTypes.func.isRequired,
Expand All @@ -65,6 +75,7 @@ AlgoTabs.propTypes = {
AlgoTabs.defaultProps = {
item: null,
descLoading: false,
descForbidden: false,
tabIndex: 0,
setTabIndex: noop,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ import actions from '../../../../actions';
const mapStateToProps = (state, {model}) => ({
item: getItem(state, model),
descLoading: state[model].item.descLoading,
descForbidden: state[model].item.descForbidden,
tabIndex: state[model].item.tabIndex,
});

const mapDispatchToProps = (dispatch) => bindActionCreators({
setTabIndex: actions.item.tabIndex.set,
}, dispatch);

export default connect(mapStateToProps, mapDispatchToProps)(onlyUpdateForKeys(['item', 'descLoading', 'tabIndex'])(Tabs));
export default connect(mapStateToProps, mapDispatchToProps)(onlyUpdateForKeys(['item', 'descLoading', 'descForbidden', 'tabIndex'])(Tabs));
20 changes: 2 additions & 18 deletions src/app/business/routes/algo/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ import {
fetchListApi, fetchStandardAlgoApi, fetchCompositeAlgoApi, fetchAggregateAlgoApi,
} from '../api';
import {
fetchItemSaga, setOrderSaga, tryRefreshToken, getJWTFromCookie,
fetchItemSaga, setOrderSaga, tryRefreshToken, getJWTFromCookie, fetchItemDescriptionSaga,
} from '../../../common/sagas';
import {fetchRaw} from '../../../../entities/fetchEntities';
import {getItem} from '../../../common/selector';

import {signOut} from '../../../user/actions';
Expand Down Expand Up @@ -176,21 +175,6 @@ function* setTabIndexSaga({payload}) {
yield manageTabs(payload);
}

function* fetchItemDescriptionSaga({payload: {pkhash, url}}) {
let jwt = getJWTFromCookie();
if (!jwt) {
jwt = yield tryRefreshToken(actions.description.failure);
}

if (jwt) {
const {res, status} = yield call(fetchRaw, url, jwt);

if (res && status === 200) {
yield put(actions.item.description.success({pkhash, desc: res}));
}
}
}

function* downloadItemSaga({payload: {url}}) {
let status;
let filename;
Expand Down Expand Up @@ -232,7 +216,7 @@ const sagas = function* sagas() {

takeEvery(actionTypes.item.REQUEST, fetchItem),

takeLatest(actionTypes.item.description.REQUEST, fetchItemDescriptionSaga),
takeLatest(actionTypes.item.description.REQUEST, fetchItemDescriptionSaga(actions)),

takeEvery(actionTypes.item.download.REQUEST, downloadItemSaga),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {fontNormalMonospace, monospaceFamily} from '../../../../../../../../../a
import {ice} from '../../../../../../../../../assets/css/variables/colors';
import Description from '../../../../../../common/components/detail/components/description';
import PermissionsTabPanelContent from '../../../../../../common/components/detail/components/permissionsTabPanelContent';
import ForbiddenResource from '../../../../../../common/components/detail/components/forbiddenResource';

const Code = styled('code')`
font-family: ${monospaceFamily};
Expand All @@ -30,7 +31,7 @@ const Code = styled('code')`
`;

const DatasetTabs = ({
descLoading, item, tabIndex, openerLoading, setTabIndex, addNotification,
loading, descLoading, descForbidden, item, tabIndex, openerLoading, openerForbidden, setTabIndex, addNotification,
}) => (
<Tabs
selectedIndex={tabIndex}
Expand All @@ -45,11 +46,27 @@ descLoading, item, tabIndex, openerLoading, setTabIndex, addNotification,
</TabList>
<TabPanel>
{descLoading && <PulseLoader size={6} />}
{!descLoading && <Description item={item} />}
{!descLoading && descForbidden && (
<ForbiddenResource
resource="description"
model="dataset"
permissionsTabIndex={4}
setTabIndex={setTabIndex}
/>
)}
{!descLoading && !descForbidden && <Description item={item} />}
</TabPanel>
<TabPanel>
{openerLoading && <PulseLoader size={6} />}
{!openerLoading && item && item.opener && item.opener.content && (
{!openerLoading && openerForbidden && (
<ForbiddenResource
resource="opener"
model="dataset"
permissionsTabIndex={4}
setTabIndex={setTabIndex}
/>
)}
{!openerLoading && !openerForbidden && item && item.opener && item.opener.content && (
<CodeSample
filename="opener.py"
language="python"
Expand All @@ -58,11 +75,11 @@ descLoading, item, tabIndex, openerLoading, setTabIndex, addNotification,
)}
</TabPanel>
<TabPanel>
{descLoading && <PulseLoader size={6} />}
{!descLoading && item && item.trainDataSampleKeys && !!item.trainDataSampleKeys.length && (
{loading && <PulseLoader size={6} />}
{!loading && item && item.trainDataSampleKeys && !!item.trainDataSampleKeys.length && (
<DataKeysTable dataKeys={item.trainDataSampleKeys} addNotification={addNotification} />
)}
{!descLoading && item && item.trainDataSampleKeys && !item.trainDataSampleKeys.length && (
{!loading && item && (!item.trainDataSampleKeys || (item.trainDataSampleKeys && !item.trainDataSampleKeys.length)) && (
<>
<p>
No train data samples setup yet.
Expand All @@ -83,11 +100,11 @@ descLoading, item, tabIndex, openerLoading, setTabIndex, addNotification,
)}
</TabPanel>
<TabPanel>
{descLoading && <PulseLoader size={6} />}
{!descLoading && item && item.testDataSampleKeys && !!item.testDataSampleKeys.length && (
{loading && <PulseLoader size={6} />}
{!loading && item && item.testDataSampleKeys && !!item.testDataSampleKeys.length && (
<DataKeysTable dataKeys={item.testDataSampleKeys} addNotification={addNotification} />
)}
{!descLoading && item && item.testDataSampleKeys && !item.testDataSampleKeys.length && (
{!loading && item && (!item.testDataSampleKeys || (item.testDataSampleKeys && !item.testDataSampleKeys.length)) && (
<>
<p>
No test data samples setup yet.
Expand Down Expand Up @@ -120,18 +137,24 @@ descLoading, item, tabIndex, openerLoading, setTabIndex, addNotification,

DatasetTabs.propTypes = {
item: PropTypes.shape(),
loading: PropTypes.bool,
descLoading: PropTypes.bool,
descForbidden: PropTypes.bool,
tabIndex: PropTypes.number,
openerLoading: PropTypes.bool,
openerForbidden: PropTypes.bool,
setTabIndex: PropTypes.func,
addNotification: PropTypes.func.isRequired,
};

DatasetTabs.defaultProps = {
item: null,
loading: false,
descLoading: false,
descForbidden: false,
tabIndex: 0,
openerLoading: false,
openerForbidden: false,
setTabIndex: noop,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import actions from '../../../../actions';

const mapStateToProps = (state, {model, addNotification}) => ({
item: getItem(state, model),
loading: state[model].item.loading,
descLoading: state[model].item.descLoading,
descForbidden: state[model].item.descForbidden,
openerLoading: state[model].item.openerLoading,
openerForbidden: state[model].item.openerForbidden,
tabIndex: state[model].item.tabIndex,
addNotification,
});
Expand All @@ -20,4 +23,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({
}, dispatch);


export default connect(mapStateToProps, mapDispatchToProps)(onlyUpdateForKeys(['item', 'descLoading', 'openerLoading', 'tabIndex'])(Tabs));
export default connect(mapStateToProps, mapDispatchToProps)(onlyUpdateForKeys(['item', 'loading', 'descLoading', 'descForbidden', 'openerLoading', 'openerForbidden', 'tabIndex'])(Tabs));
4 changes: 4 additions & 0 deletions src/app/business/routes/dataset/reducers/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import baseReducerBuilder, {initialState as baseInitialState} from '../../../com
const initialState = {
...baseInitialState,
openerLoading: false,
openerForbidden: false,
};

export default (actionTypes) => {
Expand Down Expand Up @@ -59,6 +60,7 @@ export default (actionTypes) => {
return {
...state,
openerLoading: true,
openerForbidden: false,
};
case actionTypes.item.opener.SUCCESS:
return {
Expand All @@ -77,11 +79,13 @@ export default (actionTypes) => {
}] : [c]),
], []),
openerLoading: false,
openerForbidden: false,
};
case actionTypes.item.opener.FAILURE:
return {
...state,
openerLoading: false,
openerForbidden: payload.status === 403,
};
default:
return reducedState;
Expand Down
Loading

0 comments on commit c4e1b17

Please sign in to comment.