diff --git a/app/components/Layout/Layout.js b/app/components/Layout/Layout.js index f01f7212..268e2b71 100644 --- a/app/components/Layout/Layout.js +++ b/app/components/Layout/Layout.js @@ -1,6 +1,6 @@ // @flow import React from 'react'; -import { Switch, Route, withRouter } from 'react-router-dom'; +import { Switch, Route, Redirect, withRouter } from 'react-router-dom'; import type { Location } from 'react-router-dom'; import { Helmet } from 'react-helmet'; import styled from 'styled-components'; @@ -17,6 +17,7 @@ import Sidebar from 'components/Sidebar'; import SettingsSidebar from 'components/Sidebar/Settings'; import Modals from 'components/Modals'; import Toasts from 'components/Toasts'; +import ErrorSuspended from 'scenes/ErrorSuspended'; import AuthStore from 'stores/AuthStore'; import UiStore from 'stores/UiStore'; @@ -66,11 +67,17 @@ class Layout extends React.Component { this.props.ui.setActiveModal('keyboard-shortcuts'); } + renderSuspended() { + return ; + } + render() { const { auth, ui } = this.props; const { user, team } = auth; const showSidebar = auth.authenticated && user && team; + if (auth.isSuspended) return this.renderSuspended(); + return ( diff --git a/app/scenes/ErrorSuspended/ErrorSuspended.js b/app/scenes/ErrorSuspended/ErrorSuspended.js new file mode 100644 index 00000000..40ae4040 --- /dev/null +++ b/app/scenes/ErrorSuspended/ErrorSuspended.js @@ -0,0 +1,24 @@ +// @flow +import React from 'react'; + +import CenteredContent from 'components/CenteredContent'; +import PageTitle from 'components/PageTitle'; + +const ErrorSuspended = () => ( + + +

+ + ⚠️ + {' '} + Your account has been suspended +

+ +

+ Team admin has suspended your account. To re-activate your account, please + reach out to them directly. +

+
+); + +export default ErrorSuspended; diff --git a/app/scenes/ErrorSuspended/index.js b/app/scenes/ErrorSuspended/index.js new file mode 100644 index 00000000..9406c393 --- /dev/null +++ b/app/scenes/ErrorSuspended/index.js @@ -0,0 +1,3 @@ +// @flow +import ErrorSuspended from './ErrorSuspended'; +export default ErrorSuspended; diff --git a/app/stores/AuthStore.js b/app/stores/AuthStore.js index 072ff5ac..22a1f3a2 100644 --- a/app/stores/AuthStore.js +++ b/app/stores/AuthStore.js @@ -14,6 +14,7 @@ class AuthStore { @observable token: ?string; @observable oauthState: string; @observable isLoading: boolean = false; + @observable isSuspended: boolean = false; /* Computed */ @@ -43,8 +44,9 @@ class AuthStore { this.team = res.data.team; }); } catch (err) { - // Failure to update user info is a non-fatal error. - console.error(err); + if (err.data.error === 'user_suspended') { + this.isSuspended = true; + } } }; diff --git a/server/api/middlewares/authentication.js b/server/api/middlewares/authentication.js index c1a0701e..85b865f2 100644 --- a/server/api/middlewares/authentication.js +++ b/server/api/middlewares/authentication.js @@ -75,7 +75,9 @@ export default function auth() { } } - if (user.isSuspended) throw new UserSuspendedError(); + if (user.isSuspended) { + throw new UserSuspendedError(); + } ctx.state.token = token; ctx.state.user = user; diff --git a/server/errors.js b/server/errors.js index da60eec0..bcad3828 100644 --- a/server/errors.js +++ b/server/errors.js @@ -22,7 +22,9 @@ export function AdminRequiredError( export function UserSuspendedError( message: string = 'Your access has been suspended by the team admin' ) { - return httpErrors(403, message, { id: 'user_suspended' }); + return httpErrors(403, message, { + id: 'user_suspended', + }); } export function InvalidRequestError(message: string = 'Request invalid') { diff --git a/server/migrations/20180303193036-suspended-users.js b/server/migrations/20180303193036-suspended-users.js index e49ce6fa..d403d6b4 100644 --- a/server/migrations/20180303193036-suspended-users.js +++ b/server/migrations/20180303193036-suspended-users.js @@ -2,6 +2,10 @@ module.exports = { up: async (queryInterface, Sequelize) => { await queryInterface.addColumn('users', 'suspendedById', { type: Sequelize.UUID, + allowNull: true, + references: { + model: 'users', + }, }); await queryInterface.addColumn('users', 'suspendedAt', { type: Sequelize.DATE, diff --git a/server/models/User.js b/server/models/User.js index 93e44906..44ed4a09 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -49,10 +49,6 @@ User.associate = models => { User.hasMany(models.ApiKey, { as: 'apiKeys' }); User.hasMany(models.Document, { as: 'documents' }); User.hasMany(models.View, { as: 'views' }); - User.belongsTo(models.User, { - as: 'suspendedBy', - foreignKey: 'suspendedById', - }); }; // Instance methods