#254 show error when user attempts to save stale version of project, refactor error modals to one component
This commit is contained in:
parent
c8253dd923
commit
a9ee70e033
16 changed files with 123 additions and 156 deletions
|
@ -29,7 +29,7 @@ function Nav(props) {
|
||||||
if (props.user.authenticated) {
|
if (props.user.authenticated) {
|
||||||
props.saveProject();
|
props.saveProject();
|
||||||
} else {
|
} else {
|
||||||
props.openForceAuthentication();
|
props.showErrorModal('forceAuthentication');
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -168,7 +168,7 @@ Nav.propTypes = {
|
||||||
logoutUser: PropTypes.func.isRequired,
|
logoutUser: PropTypes.func.isRequired,
|
||||||
stopSketch: PropTypes.func.isRequired,
|
stopSketch: PropTypes.func.isRequired,
|
||||||
showShareModal: PropTypes.func.isRequired,
|
showShareModal: PropTypes.func.isRequired,
|
||||||
openForceAuthentication: PropTypes.func.isRequired
|
showErrorModal: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Nav;
|
export default Nav;
|
||||||
|
|
|
@ -106,7 +106,5 @@ export const RESET_JUST_OPENED_PROJECT = 'RESET_JUST_OPENED_PROJECT';
|
||||||
export const SET_PROJECT_SAVED_TIME = 'SET_PROJECT_SAVED_TIME';
|
export const SET_PROJECT_SAVED_TIME = 'SET_PROJECT_SAVED_TIME';
|
||||||
export const RESET_PROJECT_SAVED_TIME = 'RESET_PROJECT_SAVED_TIME';
|
export const RESET_PROJECT_SAVED_TIME = 'RESET_PROJECT_SAVED_TIME';
|
||||||
export const SET_PREVIOUS_PATH = 'SET_PREVIOUS_PATH';
|
export const SET_PREVIOUS_PATH = 'SET_PREVIOUS_PATH';
|
||||||
export const OPEN_FORCE_AUTHENTICATION = 'OPEN_FORCE_AUTHENTICATION';
|
export const SHOW_ERROR_MODAL = 'SHOW_ERROR_MODAL';
|
||||||
export const CLOSE_FORCE_AUTHENTICATION = 'CLOSE_FORCE_AUTHENTICATION';
|
export const HIDE_ERROR_MODAL = 'HIDE_ERROR_MODAL';
|
||||||
export const SHOW_AUTHENTICATION_ERROR = 'SHOW_AUTHENTICATION_ERROR';
|
|
||||||
export const HIDE_AUTHENTICATION_ERROR = 'HIDE_AUTHENTICATION_ERROR';
|
|
||||||
|
|
|
@ -221,26 +221,15 @@ export function setPreviousPath(path) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openForceAuthentication() {
|
export function showErrorModal(modalType) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.OPEN_FORCE_AUTHENTICATION
|
type: ActionTypes.SHOW_ERROR_MODAL,
|
||||||
|
modalType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function closeForceAuthentication() {
|
export function hideErrorModal() {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.CLOSE_FORCE_AUTHENTICATION
|
type: ActionTypes.HIDE_ERROR_MODAL
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function showAuthenticationError() {
|
|
||||||
return {
|
|
||||||
type: ActionTypes.SHOW_AUTHENTICATION_ERROR
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function hideAuthenticationError() {
|
|
||||||
return {
|
|
||||||
type: ActionTypes.HIDE_AUTHENTICATION_ERROR
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { setUnsavedChanges,
|
||||||
resetJustOpenedProject,
|
resetJustOpenedProject,
|
||||||
setProjectSavedTime,
|
setProjectSavedTime,
|
||||||
resetProjectSavedTime,
|
resetProjectSavedTime,
|
||||||
showAuthenticationError } from './ide';
|
showErrorModal } from './ide';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
||||||
|
@ -21,7 +21,6 @@ export function getProject(id) {
|
||||||
}
|
}
|
||||||
axios.get(`${ROOT_URL}/projects/${id}`, { withCredentials: true })
|
axios.get(`${ROOT_URL}/projects/${id}`, { withCredentials: true })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
// browserHistory.push(`/projects/${id}`);
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.SET_PROJECT,
|
type: ActionTypes.SET_PROJECT,
|
||||||
project: response.data,
|
project: response.data,
|
||||||
|
@ -74,7 +73,9 @@ export function saveProject(autosave = false) {
|
||||||
})
|
})
|
||||||
.catch((response) => {
|
.catch((response) => {
|
||||||
if (response.status === 403) {
|
if (response.status === 403) {
|
||||||
dispatch(showAuthenticationError());
|
dispatch(showErrorModal('staleSession'));
|
||||||
|
} else if (response.status === 409) {
|
||||||
|
dispatch(showErrorModal('staleProject'));
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.PROJECT_SAVE_FAIL,
|
type: ActionTypes.PROJECT_SAVE_FAIL,
|
||||||
|
@ -90,8 +91,7 @@ export function saveProject(autosave = false) {
|
||||||
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.NEW_PROJECT,
|
type: ActionTypes.NEW_PROJECT,
|
||||||
name: response.data.name,
|
project: response.data,
|
||||||
id: response.data.id,
|
|
||||||
owner: response.data.user,
|
owner: response.data.user,
|
||||||
files: response.data.files
|
files: response.data.files
|
||||||
});
|
});
|
||||||
|
@ -109,7 +109,7 @@ export function saveProject(autosave = false) {
|
||||||
})
|
})
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
if (response.status === 403) {
|
if (response.status === 403) {
|
||||||
dispatch(showAuthenticationError());
|
dispatch(showErrorModal('staleSession'));
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.PROJECT_SAVE_FAIL,
|
type: ActionTypes.PROJECT_SAVE_FAIL,
|
||||||
|
@ -134,8 +134,7 @@ export function createProject() {
|
||||||
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.NEW_PROJECT,
|
type: ActionTypes.NEW_PROJECT,
|
||||||
name: response.data.name,
|
project: response.data,
|
||||||
id: response.data.id,
|
|
||||||
owner: response.data.user,
|
owner: response.data.user,
|
||||||
files: response.data.files
|
files: response.data.files
|
||||||
});
|
});
|
||||||
|
@ -176,10 +175,8 @@ export function cloneProject() {
|
||||||
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.NEW_PROJECT,
|
type: ActionTypes.NEW_PROJECT,
|
||||||
name: response.data.name,
|
project: response.data,
|
||||||
id: response.data.id,
|
|
||||||
owner: response.data.user,
|
owner: response.data.user,
|
||||||
selectedFile: response.data.selectedFile,
|
|
||||||
files: response.data.files
|
files: response.data.files
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { showAuthenticationError, setPreviousPath } from './ide';
|
import { showErrorModal, setPreviousPath } from './ide';
|
||||||
import { resetProject } from './project';
|
import { resetProject } from './project';
|
||||||
|
|
||||||
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
||||||
|
@ -43,7 +43,7 @@ export function deleteProject(id) {
|
||||||
})
|
})
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
if (response.status === 403) {
|
if (response.status === 403) {
|
||||||
dispatch(showAuthenticationError());
|
dispatch(showErrorModal('staleSession'));
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.ERROR,
|
type: ActionTypes.ERROR,
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
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
|
|
||||||
<Link to="/login" onClick={props.closeModal}>log in</Link>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
AuthenticationError.propTypes = {
|
|
||||||
closeModal: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AuthenticationError;
|
|
70
client/modules/IDE/components/ErrorModal.jsx
Normal file
70
client/modules/IDE/components/ErrorModal.jsx
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import React, { PropTypes } from 'react';
|
||||||
|
import InlineSVG from 'react-inlinesvg';
|
||||||
|
const exitUrl = require('../../../images/exit.svg');
|
||||||
|
import { Link } from 'react-router';
|
||||||
|
|
||||||
|
class ErrorModal extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
this.refs.modal.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
forceAuthentication() {
|
||||||
|
return (
|
||||||
|
<p>
|
||||||
|
In order to save sketches, you must be logged in. Please
|
||||||
|
<Link to="/login" onClick={this.props.closeModal}>Login</Link>
|
||||||
|
or
|
||||||
|
<Link to="/signup" onClick={this.props.closeModal}>Sign Up</Link>.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
staleSession() {
|
||||||
|
return (
|
||||||
|
<p>
|
||||||
|
It looks like you've been logged out. Please
|
||||||
|
<Link to="/login" onClick={this.props.closeModal}>log in</Link>.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
staleProject() {
|
||||||
|
return (
|
||||||
|
<p>
|
||||||
|
The project you have attempted to save is out of date. Please refresh the page.
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<section className="error-modal" ref="modal" tabIndex="0">
|
||||||
|
<header className="error-modal__header">
|
||||||
|
<h2 className="error-modal__title">Error</h2>
|
||||||
|
<button className="error-modal__exit-button" onClick={this.props.closeModal}>
|
||||||
|
<InlineSVG src={exitUrl} alt="Close Error Modal" />
|
||||||
|
</button>
|
||||||
|
</header>
|
||||||
|
<div className="error-modal__content">
|
||||||
|
{(() => { // eslint-disable-line
|
||||||
|
if (this.props.type === 'forceAuthentication') {
|
||||||
|
return this.forceAuthentication();
|
||||||
|
} else if (this.props.type === 'staleSession') {
|
||||||
|
return this.staleSession();
|
||||||
|
} else if (this.props.type === 'staleProject') {
|
||||||
|
return this.staleProject();
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorModal.propTypes = {
|
||||||
|
type: PropTypes.string,
|
||||||
|
closeModal: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ErrorModal;
|
|
@ -1,36 +0,0 @@
|
||||||
import React, { PropTypes } from 'react';
|
|
||||||
import InlineSVG from 'react-inlinesvg';
|
|
||||||
const exitUrl = require('../../../images/exit.svg');
|
|
||||||
import { Link } from 'react-router';
|
|
||||||
|
|
||||||
class ForceAuthentication extends React.Component {
|
|
||||||
componentDidMount() {
|
|
||||||
this.refs.forceAuthentication.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<section className="force-authentication" ref="forceAuthentication" tabIndex="0">
|
|
||||||
<header className="force-authentication__header">
|
|
||||||
<button className="force-authentication__exit-button" onClick={this.props.closeModal}>
|
|
||||||
<InlineSVG src={exitUrl} alt="Close About Overlay" />
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
<div className="force-authentication__copy">
|
|
||||||
<p>
|
|
||||||
In order to save sketches, you must be logged in. Please
|
|
||||||
<Link to="/login" onClick={this.props.closeModal}>Login</Link>
|
|
||||||
or
|
|
||||||
<Link to="/signup" onClick={this.props.closeModal}>Sign Up</Link>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ForceAuthentication.propTypes = {
|
|
||||||
closeModal: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ForceAuthentication;
|
|
|
@ -9,8 +9,7 @@ import NewFileModal from '../components/NewFileModal';
|
||||||
import NewFolderModal from '../components/NewFolderModal';
|
import NewFolderModal from '../components/NewFolderModal';
|
||||||
import ShareModal from '../components/ShareModal';
|
import ShareModal from '../components/ShareModal';
|
||||||
import KeyboardShortcutModal from '../components/KeyboardShortcutModal';
|
import KeyboardShortcutModal from '../components/KeyboardShortcutModal';
|
||||||
import ForceAuthentication from '../components/ForceAuthentication';
|
import ErrorModal from '../components/ErrorModal';
|
||||||
import AuthenticationError from '../components/AuthenticationError';
|
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
import Console from '../components/Console';
|
import Console from '../components/Console';
|
||||||
import Toast from '../components/Toast';
|
import Toast from '../components/Toast';
|
||||||
|
@ -195,7 +194,7 @@ class IDEView extends React.Component {
|
||||||
logoutUser={this.props.logoutUser}
|
logoutUser={this.props.logoutUser}
|
||||||
stopSketch={this.props.stopSketch}
|
stopSketch={this.props.stopSketch}
|
||||||
showShareModal={this.props.showShareModal}
|
showShareModal={this.props.showShareModal}
|
||||||
openForceAuthentication={this.props.openForceAuthentication}
|
showErrorModal={this.props.showErrorModal}
|
||||||
unsavedChanges={this.props.ide.unsavedChanges}
|
unsavedChanges={this.props.ide.unsavedChanges}
|
||||||
warnIfUnsavedChanges={this.warnIfUnsavedChanges}
|
warnIfUnsavedChanges={this.warnIfUnsavedChanges}
|
||||||
/>
|
/>
|
||||||
|
@ -425,22 +424,12 @@ class IDEView extends React.Component {
|
||||||
}
|
}
|
||||||
})()}
|
})()}
|
||||||
{(() => { // eslint-disable-line
|
{(() => { // eslint-disable-line
|
||||||
if (this.props.ide.forceAuthenticationVisible) {
|
if (this.props.ide.errorType) {
|
||||||
return (
|
return (
|
||||||
<Overlay>
|
<Overlay>
|
||||||
<ForceAuthentication
|
<ErrorModal
|
||||||
closeModal={this.props.closeForceAuthentication}
|
type={this.props.ide.errorType}
|
||||||
/>
|
closeModal={this.props.hideErrorModal}
|
||||||
</Overlay>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
{(() => { // eslint-disable-line
|
|
||||||
if (this.props.ide.authenticationError) {
|
|
||||||
return (
|
|
||||||
<Overlay>
|
|
||||||
<AuthenticationError
|
|
||||||
closeModal={this.props.hideAuthenticationError}
|
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
);
|
);
|
||||||
|
@ -488,9 +477,8 @@ IDEView.propTypes = {
|
||||||
infiniteLoopMessage: PropTypes.string.isRequired,
|
infiniteLoopMessage: PropTypes.string.isRequired,
|
||||||
projectSavedTime: PropTypes.string.isRequired,
|
projectSavedTime: PropTypes.string.isRequired,
|
||||||
previousPath: PropTypes.string.isRequired,
|
previousPath: PropTypes.string.isRequired,
|
||||||
forceAuthenticationVisible: PropTypes.bool.isRequired,
|
justOpenedProject: PropTypes.bool.isRequired,
|
||||||
authenticationError: PropTypes.bool.isRequired,
|
errorType: PropTypes.string
|
||||||
justOpenedProject: PropTypes.bool.isRequired
|
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
startSketch: PropTypes.func.isRequired,
|
startSketch: PropTypes.func.isRequired,
|
||||||
stopSketch: PropTypes.func.isRequired,
|
stopSketch: PropTypes.func.isRequired,
|
||||||
|
@ -590,11 +578,10 @@ IDEView.propTypes = {
|
||||||
setBlobUrl: PropTypes.func.isRequired,
|
setBlobUrl: PropTypes.func.isRequired,
|
||||||
setPreviousPath: PropTypes.func.isRequired,
|
setPreviousPath: PropTypes.func.isRequired,
|
||||||
resetProject: PropTypes.func.isRequired,
|
resetProject: PropTypes.func.isRequired,
|
||||||
closeForceAuthentication: PropTypes.func.isRequired,
|
|
||||||
openForceAuthentication: PropTypes.func.isRequired,
|
|
||||||
console: PropTypes.array.isRequired,
|
console: PropTypes.array.isRequired,
|
||||||
clearConsole: PropTypes.func.isRequired,
|
clearConsole: PropTypes.func.isRequired,
|
||||||
hideAuthenticationError: PropTypes.func.isRequired
|
showErrorModal: PropTypes.func.isRequired,
|
||||||
|
hideErrorModal: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
|
|
|
@ -19,8 +19,7 @@ const initialState = {
|
||||||
justOpenedProject: false,
|
justOpenedProject: false,
|
||||||
projectSavedTime: '',
|
projectSavedTime: '',
|
||||||
previousPath: '/',
|
previousPath: '/',
|
||||||
forceAuthenticationVisible: false,
|
errorType: undefined
|
||||||
authenticationError: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ide = (state = initialState, action) => {
|
const ide = (state = initialState, action) => {
|
||||||
|
@ -93,14 +92,10 @@ const ide = (state = initialState, action) => {
|
||||||
return Object.assign({}, state, { projectSavedTime: '' });
|
return Object.assign({}, state, { projectSavedTime: '' });
|
||||||
case ActionTypes.SET_PREVIOUS_PATH:
|
case ActionTypes.SET_PREVIOUS_PATH:
|
||||||
return Object.assign({}, state, { previousPath: action.path });
|
return Object.assign({}, state, { previousPath: action.path });
|
||||||
case ActionTypes.OPEN_FORCE_AUTHENTICATION:
|
case ActionTypes.SHOW_ERROR_MODAL:
|
||||||
return Object.assign({}, state, { forceAuthenticationVisible: true });
|
return Object.assign({}, state, { errorType: action.modalType });
|
||||||
case ActionTypes.CLOSE_FORCE_AUTHENTICATION:
|
case ActionTypes.HIDE_ERROR_MODAL:
|
||||||
return Object.assign({}, state, { forceAuthenticationVisible: false });
|
return Object.assign({}, state, { errorType: undefined });
|
||||||
case ActionTypes.SHOW_AUTHENTICATION_ERROR:
|
|
||||||
return Object.assign({}, state, { authenticationError: true });
|
|
||||||
case ActionTypes.HIDE_AUTHENTICATION_ERROR:
|
|
||||||
return Object.assign({}, state, { authenticationError: false });
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,16 @@ const project = (state, action) => {
|
||||||
return Object.assign({}, { ...state }, { name: action.name });
|
return Object.assign({}, { ...state }, { name: action.name });
|
||||||
case ActionTypes.NEW_PROJECT:
|
case ActionTypes.NEW_PROJECT:
|
||||||
return {
|
return {
|
||||||
id: action.id,
|
id: action.project.id,
|
||||||
name: action.name,
|
name: action.project.name,
|
||||||
|
updatedAt: action.project.updatedAt,
|
||||||
owner: action.owner
|
owner: action.owner
|
||||||
};
|
};
|
||||||
case ActionTypes.SET_PROJECT:
|
case ActionTypes.SET_PROJECT:
|
||||||
return {
|
return {
|
||||||
id: action.project.id,
|
id: action.project.id,
|
||||||
name: action.project.name,
|
name: action.project.name,
|
||||||
|
updatedAt: action.project.updatedAt,
|
||||||
owner: action.owner
|
owner: action.owner
|
||||||
};
|
};
|
||||||
case ActionTypes.RESET_PROJECT:
|
case ActionTypes.RESET_PROJECT:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as ActionTypes from '../../constants';
|
import * as ActionTypes from '../../constants';
|
||||||
import { browserHistory } from 'react-router';
|
import { browserHistory } from 'react-router';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { showAuthenticationError, justOpenedProject } from '../IDE/actions/ide';
|
import { showErrorModal, justOpenedProject } from '../IDE/actions/ide';
|
||||||
|
|
||||||
|
|
||||||
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
const ROOT_URL = location.href.indexOf('localhost') > 0 ? 'http://localhost:8000/api' : '/api';
|
||||||
|
@ -91,12 +91,12 @@ export function validateSession() {
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
if (state.user.username !== response.data.username) {
|
if (state.user.username !== response.data.username) {
|
||||||
dispatch(showAuthenticationError());
|
dispatch(showErrorModal('staleSession'));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(response => {
|
.catch(response => {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
dispatch(showAuthenticationError());
|
dispatch(showErrorModal('staleSession'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
.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;
|
|
||||||
}
|
|
|
@ -1,24 +1,24 @@
|
||||||
.force-authentication {
|
.error-modal {
|
||||||
@extend %modal;
|
@extend %modal;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-authentication__header {
|
.error-modal__header {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: space-between;
|
||||||
padding: #{20 / $base-font-size}rem;
|
padding: #{20 / $base-font-size}rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-authentication__exit-button {
|
.error-modal__exit-button {
|
||||||
@include themify() {
|
@include themify() {
|
||||||
@extend %icon;
|
@extend %icon;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.force-authentication__copy {
|
.error-modal__content {
|
||||||
padding: #{20 / $base-font-size}rem;
|
padding: #{20 / $base-font-size}rem;
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
padding-bottom: #{60 / $base-font-size}rem;
|
padding-bottom: #{60 / $base-font-size}rem;
|
||||||
}
|
}
|
|
@ -30,10 +30,8 @@
|
||||||
@import 'components/forms';
|
@import 'components/forms';
|
||||||
@import 'components/toast';
|
@import 'components/toast';
|
||||||
@import 'components/timer';
|
@import 'components/timer';
|
||||||
@import 'components/force-authentication';
|
|
||||||
@import 'components/form-container';
|
@import 'components/form-container';
|
||||||
@import 'components/uploader';
|
@import 'components/error-modal';
|
||||||
@import 'components/authentication-error';
|
|
||||||
|
|
||||||
@import 'layout/ide';
|
@import 'layout/ide';
|
||||||
@import 'layout/fullscreen';
|
@import 'layout/fullscreen';
|
||||||
|
|
|
@ -2,6 +2,7 @@ import Project from '../models/project';
|
||||||
import User from '../models/user';
|
import User from '../models/user';
|
||||||
import archiver from 'archiver';
|
import archiver from 'archiver';
|
||||||
import request from 'request';
|
import request from 'request';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
|
||||||
export function createProject(req, res) {
|
export function createProject(req, res) {
|
||||||
|
@ -29,7 +30,10 @@ export function createProject(req, res) {
|
||||||
export function updateProject(req, res) {
|
export function updateProject(req, res) {
|
||||||
Project.findById(req.params.project_id, (err, project) => {
|
Project.findById(req.params.project_id, (err, project) => {
|
||||||
if (!req.user || !project.user.equals(req.user._id)) {
|
if (!req.user || !project.user.equals(req.user._id)) {
|
||||||
return res.status(403).send({ success: false, message: 'Session does not match owner of project.'});
|
return res.status(403).send({ success: false, message: 'Session does not match owner of project.' });
|
||||||
|
}
|
||||||
|
if (req.body.updatedAt && moment(req.body.updatedAt) < moment(project.updatedAt)) {
|
||||||
|
return res.status(409).send({ success: false, message: 'Attempted to save stale version of project.' })
|
||||||
}
|
}
|
||||||
Project.findByIdAndUpdate(req.params.project_id,
|
Project.findByIdAndUpdate(req.params.project_id,
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue