added suspending admin email to error screen

This commit is contained in:
Jori Lallo
2018-03-06 23:38:52 -08:00
parent e9e4538436
commit f5c1ddf8b9
7 changed files with 37 additions and 22 deletions

View File

@ -1,10 +1,13 @@
// @flow // @flow
import React from 'react'; import React from 'react';
import { inject, observer } from 'mobx-react';
import CenteredContent from 'components/CenteredContent'; import CenteredContent from 'components/CenteredContent';
import PageTitle from 'components/PageTitle'; import PageTitle from 'components/PageTitle';
import AuthStore from 'stores/AuthStore';
const ErrorSuspended = () => ( const ErrorSuspended = observer(({ auth }: { auth: AuthStore }) => {
return (
<CenteredContent> <CenteredContent>
<PageTitle title="Your account has been suspended" /> <PageTitle title="Your account has been suspended" />
<h1> <h1>
@ -15,10 +18,12 @@ const ErrorSuspended = () => (
</h1> </h1>
<p> <p>
A team admin has suspended your account. To re-activate your account, A team admin (<strong>{auth.suspendedContactEmail}</strong>) has
please reach out to them directly. suspended your account. To re-activate your account, please reach out to
them directly.
</p> </p>
</CenteredContent> </CenteredContent>
); );
});
export default ErrorSuspended; export default inject('auth')(ErrorSuspended);

View File

@ -15,6 +15,7 @@ class AuthStore {
@observable oauthState: string; @observable oauthState: string;
@observable isLoading: boolean = false; @observable isLoading: boolean = false;
@observable isSuspended: boolean = false; @observable isSuspended: boolean = false;
@observable suspendedContactEmail: ?string;
/* Computed */ /* Computed */
@ -46,6 +47,7 @@ class AuthStore {
} catch (err) { } catch (err) {
if (err.data.error === 'user_suspended') { if (err.data.error === 'user_suspended') {
this.isSuspended = true; this.isSuspended = true;
this.suspendedContactEmail = err.data.adminEmail;
} }
} }
}; };

View File

@ -29,6 +29,7 @@ api.use(async (ctx, next) => {
} catch (err) { } catch (err) {
ctx.status = err.status || 500; ctx.status = err.status || 500;
let message = err.message || err.name; let message = err.message || err.name;
let error;
if (err instanceof Sequelize.ValidationError) { if (err instanceof Sequelize.ValidationError) {
// super basic form error handling // super basic form error handling
@ -40,18 +41,21 @@ api.use(async (ctx, next) => {
if (message.match('Authorization error')) { if (message.match('Authorization error')) {
ctx.status = 403; ctx.status = 403;
error = 'authorization_error';
} }
if (ctx.status === 500) { if (ctx.status === 500) {
message = 'Internal Server Error'; message = 'Internal Server Error';
error = 'internal_server_error';
ctx.app.emit('error', err, ctx); ctx.app.emit('error', err, ctx);
} }
ctx.body = { ctx.body = {
ok: false, ok: false,
error: _.snakeCase(err.id || err.message), error: _.snakeCase(err.id || error),
status: err.status, status: err.status,
message, message,
adminEmail: err.adminEmail ? err.adminEmail : undefined,
}; };
} }
}); });

View File

@ -76,7 +76,8 @@ export default function auth() {
} }
if (user.isSuspended) { if (user.isSuspended) {
throw new UserSuspendedError(); const suspendingAdmin = await User.findById(user.suspendedById);
throw new UserSuspendedError({ adminEmail: suspendingAdmin.email });
} }
ctx.state.token = token; ctx.state.token = token;

View File

@ -159,8 +159,10 @@ describe('Authentication middleware', async () => {
it('should return an error for suspended users', async () => { it('should return an error for suspended users', async () => {
const state = {}; const state = {};
const admin = await buildUser({});
const user = await buildUser({ const user = await buildUser({
suspendedAt: new Date(), suspendedAt: new Date(),
suspendedById: admin.id,
}); });
const authMiddleware = auth(); const authMiddleware = auth();
@ -179,6 +181,7 @@ describe('Authentication middleware', async () => {
expect(e.message).toEqual( expect(e.message).toEqual(
'Your access has been suspended by the team admin' 'Your access has been suspended by the team admin'
); );
expect(e.adminEmail).toEqual(admin.email);
} }
}); });
}); });

View File

@ -19,11 +19,10 @@ export function AdminRequiredError(
return httpErrors(403, message, { id: 'admin_required' }); return httpErrors(403, message, { id: 'admin_required' });
} }
export function UserSuspendedError( export function UserSuspendedError({ adminEmail }: { adminEmail: string }) {
message: string = 'Your access has been suspended by the team admin' return httpErrors(403, 'Your access has been suspended by the team admin', {
) {
return httpErrors(403, message, {
id: 'user_suspended', id: 'user_suspended',
adminEmail,
}); });
} }

View File

@ -29,6 +29,7 @@ const User = sequelize.define(
slackData: DataTypes.JSONB, slackData: DataTypes.JSONB,
jwtSecret: encryptedFields.vault('jwtSecret'), jwtSecret: encryptedFields.vault('jwtSecret'),
suspendedAt: DataTypes.DATE, suspendedAt: DataTypes.DATE,
suspendedById: DataTypes.UUID,
}, },
{ {
getterMethods: { getterMethods: {