add authentcation error component, return 403 error from server when trying to save a project where the user doesn't match the owner

This commit is contained in:
Cassie Tarakajian 2017-01-13 17:17:31 -05:00
parent b018aa645c
commit 65592cbf9e
9 changed files with 130 additions and 38 deletions

View file

@ -108,3 +108,5 @@ export const RESET_PROJECT_SAVED_TIME = 'RESET_PROJECT_SAVED_TIME';
export const SET_PREVIOUS_PATH = 'SET_PREVIOUS_PATH';
export const OPEN_FORCE_AUTHENTICATION = 'OPEN_FORCE_AUTHENTICATION';
export const CLOSE_FORCE_AUTHENTICATION = 'CLOSE_FORCE_AUTHENTICATION';
export const SHOW_AUTHENTICATION_ERROR = 'SHOW_AUTHENTICATION_ERROR';
export const HIDE_AUTHENTICATION_ERROR = 'HIDE_AUTHENTICATION_ERROR';

View file

@ -232,3 +232,15 @@ export function closeForceAuthentication() {
type: ActionTypes.CLOSE_FORCE_AUTHENTICATION
};
}
export function showAuthenticationError() {
return {
type: ActionTypes.SHOW_AUTHENTICATION_ERROR
};
}
export function hideAuthenticationError() {
return {
type: ActionTypes.HIDE_AUTHENTICATION_ERROR
};
}

View file

@ -2,7 +2,12 @@ import * as ActionTypes from '../../../constants';
import { browserHistory } from 'react-router';
import axios from 'axios';
import { showToast, setToastText } from './toast';
import { setUnsavedChanges, justOpenedProject, resetJustOpenedProject, setProjectSavedTime, resetProjectSavedTime } from './ide';
import { setUnsavedChanges,
justOpenedProject,
resetJustOpenedProject,
setProjectSavedTime,
resetProjectSavedTime,
showAuthenticationError } from './ide';
import moment from 'moment';
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
@ -67,10 +72,16 @@ export function saveProject(autosave = false) {
}
}
})
.catch((response) => dispatch({
.catch((response) => {
if (response.status === 403) {
dispatch(showAuthenticationError());
} else {
dispatch({
type: ActionTypes.PROJECT_SAVE_FAIL,
error: response.data
}));
});
}
});
} else {
axios.post(`${ROOT_URL}/projects`, formParams, { withCredentials: true })
.then(response => {

View file

@ -0,0 +1,24 @@
import React, { PropTypes } from 'react';
import { Link } from 'react-router';
function AuthenticationError(props) {
return (
<section className="authentication-error" tabIndex="0">
<header className="authentication-error__header">
<h2 className="authentication-error__title">Error</h2>
</header>
<div className="authentication-error__copy">
<p>
It looks like you've been logged out. Please&nbsp;
<Link to="/login" onClick={props.closeModal}>log in</Link>.
</p>
</div>
</section>
);
}
AuthenticationError.propTypes = {
closeModal: PropTypes.func.isRequired
};
export default AuthenticationError;

View file

@ -10,6 +10,7 @@ import NewFolderModal from '../components/NewFolderModal';
import ShareModal from '../components/ShareModal';
import KeyboardShortcutModal from '../components/KeyboardShortcutModal';
import ForceAuthentication from '../components/ForceAuthentication';
import AuthenticationError from '../components/AuthenticationError';
import Nav from '../../../components/Nav';
import Console from '../components/Console';
import Toast from '../components/Toast';
@ -446,6 +447,17 @@ class IDEView extends React.Component {
);
}
})()}
{(() => { // eslint-disable-line
if (this.props.ide.authenticationError) {
return (
<Overlay>
<AuthenticationError
closeModal={this.props.hideAuthenticationError}
/>
</Overlay>
);
}
})()}
</div>
);
@ -488,7 +500,8 @@ IDEView.propTypes = {
infiniteLoopMessage: PropTypes.string.isRequired,
projectSavedTime: PropTypes.string.isRequired,
previousPath: PropTypes.string.isRequired,
forceAuthenticationVisible: PropTypes.bool.isRequired
forceAuthenticationVisible: PropTypes.bool.isRequired,
authenticationError: PropTypes.bool.isRequired
}).isRequired,
startSketch: PropTypes.func.isRequired,
stopSketch: PropTypes.func.isRequired,
@ -591,7 +604,8 @@ IDEView.propTypes = {
closeForceAuthentication: PropTypes.func.isRequired,
openForceAuthentication: PropTypes.func.isRequired,
console: PropTypes.array.isRequired,
clearConsole: PropTypes.func.isRequired
clearConsole: PropTypes.func.isRequired,
hideAuthenticationError: PropTypes.func.isRequired
};
function mapStateToProps(state) {

View file

@ -20,6 +20,7 @@ const initialState = {
projectSavedTime: '',
previousPath: '/',
forceAuthenticationVisible: false,
authenticationError: false
};
const ide = (state = initialState, action) => {
@ -96,6 +97,10 @@ const ide = (state = initialState, action) => {
return Object.assign({}, state, { forceAuthenticationVisible: true });
case ActionTypes.CLOSE_FORCE_AUTHENTICATION:
return Object.assign({}, state, { forceAuthenticationVisible: false });
case ActionTypes.SHOW_AUTHENTICATION_ERROR:
return Object.assign({}, state, { authenticationError: true });
case ActionTypes.HIDE_AUTHENTICATION_ERROR:
return Object.assign({}, state, { authenticationError: false });
default:
return state;
}

View file

@ -0,0 +1,13 @@
.authentication-error {
@extend %modal;
}
.authentication-error__header {
padding: #{20 / $base-font-size}rem;
}
.authentication-error__copy {
padding: #{20 / $base-font-size}rem;
padding-top: 0;
padding-bottom: #{60 / $base-font-size}rem;
}

View file

@ -33,6 +33,7 @@
@import 'components/force-authentication';
@import 'components/form-container';
@import 'components/uploader';
@import 'components/authentication-error';
@import 'layout/ide';
@import 'layout/fullscreen';

View file

@ -23,6 +23,10 @@ export function createProject(req, res) {
}
export function updateProject(req, res) {
Project.findById(req.params.project_id, (err, project) => {
if (!req.user || !project.user.equals(req.user._id)) {
return res.status(403).send({ success: false, message: 'Session does not match owner of project.'});
}
Project.findByIdAndUpdate(req.params.project_id,
{
$set: req.body
@ -50,6 +54,7 @@ export function updateProject(req, res) {
}
return res.json(updatedProject);
});
});
}
export function getProject(req, res) {
@ -64,12 +69,17 @@ export function getProject(req, res) {
}
export function deleteProject(req, res) {
Project.findById(req.params.project_id, (err, project) => {
if (!req.user || !project.user.equals(req.user._id)) {
return res.status(403).json({ success: false, message: 'Session does not match owner of project.'});
}
Project.remove({ _id: req.params.project_id }, (err) => {
if (err) {
return res.status(404).send({ message: 'Project with that id does not exist' });
}
return res.json({ success: true });
});
});
}
export function getProjects(req, res) {