Added signup API endpoint
This commit is contained in:
parent
bf84f792e2
commit
48a9a9f285
|
@ -0,0 +1,27 @@
|
|||
exports[`test should require params 1`] = `
|
||||
Object {
|
||||
"error": "name is required",
|
||||
"ok": false
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`test should require unique email 1`] = `
|
||||
Object {
|
||||
"error": "User already exists with this email",
|
||||
"ok": false
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`test should require unique username 1`] = `
|
||||
Object {
|
||||
"error": "User already exists with this username",
|
||||
"ok": false
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`test should require valid email 1`] = `
|
||||
Object {
|
||||
"error": "email is invalid",
|
||||
"ok": false
|
||||
}
|
||||
`;
|
|
@ -8,6 +8,36 @@ import { User, Team } from '../models';
|
|||
|
||||
const router = new Router();
|
||||
|
||||
router.post('auth.signup', async (ctx) => {
|
||||
const { username, name, email, password } = ctx.request.body;
|
||||
|
||||
ctx.assertPresent(username, 'name is required');
|
||||
ctx.assertPresent(name, 'name is required');
|
||||
ctx.assertPresent(email, 'email is required');
|
||||
ctx.assertEmail(email, 'email is invalid');
|
||||
ctx.assertPresent(password, 'password is required');
|
||||
|
||||
if (await User.findOne({ where: { email } })) {
|
||||
throw httpErrors.BadRequest('User already exists with this email');
|
||||
}
|
||||
|
||||
if (await User.findOne({ where: { username } })) {
|
||||
throw httpErrors.BadRequest('User already exists with this username');
|
||||
}
|
||||
|
||||
const user = await User.create({
|
||||
username,
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
ctx.body = { data: {
|
||||
user: await presentUser(ctx, user),
|
||||
accessToken: user.getJwtToken(),
|
||||
} };
|
||||
});
|
||||
|
||||
router.post('auth.slack', async (ctx) => {
|
||||
const { code } = ctx.body;
|
||||
ctx.assertPresent(code, 'code is required');
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import TestServer from 'fetch-test-server';
|
||||
import app from '..';
|
||||
import { flushdb, sequelize, seed } from '../test/support';
|
||||
|
||||
const server = new TestServer(app.callback());
|
||||
|
||||
beforeEach(flushdb);
|
||||
afterAll(() => server.close());
|
||||
afterAll(() => sequelize.close());
|
||||
|
||||
it('should signup a new user', async () => {
|
||||
const res = await server.post('/api/auth.signup', {
|
||||
body: {
|
||||
username: 'testuser',
|
||||
name: 'Test User',
|
||||
email: 'new.user@example.com',
|
||||
password: 'test123!',
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.ok).toBe(true);
|
||||
expect(body.data.user).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should require params', async () => {
|
||||
const res = await server.post('/api/auth.signup', {
|
||||
body: {
|
||||
username: 'testuser',
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(400);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
||||
it('should require valid email', async () => {
|
||||
const res = await server.post('/api/auth.signup', {
|
||||
body: {
|
||||
username: 'testuser',
|
||||
name: 'Test User',
|
||||
email: 'example.com',
|
||||
password: 'test123!',
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(400);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should require unique email', async () => {
|
||||
await seed();
|
||||
const res = await server.post('/api/auth.signup', {
|
||||
body: {
|
||||
username: 'testuser',
|
||||
name: 'Test User',
|
||||
email: 'user1@example.com',
|
||||
password: 'test123!',
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(400);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should require unique username', async () => {
|
||||
await seed();
|
||||
const res = await server.post('/api/auth.signup', {
|
||||
body: {
|
||||
username: 'user1',
|
||||
name: 'Test User',
|
||||
email: 'userone@example.com',
|
||||
password: 'test123!',
|
||||
},
|
||||
});
|
||||
const body = await res.json();
|
||||
|
||||
expect(res.status).toEqual(400);
|
||||
expect(body).toMatchSnapshot();
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
/* eslint-disable */
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (queryInterface, Sequelize) {
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'slackId',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: false,
|
||||
allowNull: true,
|
||||
}
|
||||
);
|
||||
queryInterface.changeColumn(
|
||||
'teams',
|
||||
'slackId',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: false,
|
||||
allowNull: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
down: function (queryInterface, Sequelize) {
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'slackId',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: true,
|
||||
allowNull: false,
|
||||
}
|
||||
);
|
||||
queryInterface.changeColumn(
|
||||
'teams',
|
||||
'slackId',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: true,
|
||||
allowNull: false,
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
up: function (queryInterface, Sequelize) {
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'email',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: true,
|
||||
allowNull: false,
|
||||
}
|
||||
);
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'username',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: true,
|
||||
allowNull: false,
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
down: function (queryInterface, Sequelize) {
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'email',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: false,
|
||||
allowNull: true,
|
||||
}
|
||||
);
|
||||
|
||||
queryInterface.changeColumn(
|
||||
'users',
|
||||
'username',
|
||||
{
|
||||
type: Sequelize.STRING,
|
||||
unique: false,
|
||||
allowNull: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
|
@ -9,7 +9,7 @@ import User from './User';
|
|||
const Team = sequelize.define('team', {
|
||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||
name: DataTypes.STRING,
|
||||
slackId: { type: DataTypes.STRING, unique: true },
|
||||
slackId: { type: DataTypes.STRING, allowNull: true },
|
||||
slackData: DataTypes.JSONB,
|
||||
}, {
|
||||
instanceMethods: {
|
||||
|
|
|
@ -9,12 +9,12 @@ import JWT from 'jsonwebtoken';
|
|||
|
||||
const User = sequelize.define('user', {
|
||||
id: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, primaryKey: true },
|
||||
email: DataTypes.STRING,
|
||||
username: DataTypes.STRING,
|
||||
email: { type: DataTypes.STRING, unique: true },
|
||||
username: { type: DataTypes.STRING, unique: true },
|
||||
name: DataTypes.STRING,
|
||||
isAdmin: DataTypes.BOOLEAN,
|
||||
slackAccessToken: encryptedFields.vault('slackAccessToken'),
|
||||
slackId: { type: DataTypes.STRING, unique: true },
|
||||
slackId: { type: DataTypes.STRING, allowNull: true },
|
||||
slackData: DataTypes.JSONB,
|
||||
jwtSecret: encryptedFields.vault('jwtSecret'),
|
||||
}, {
|
||||
|
|
|
@ -6,3 +6,12 @@ Object {
|
|||
"username": "testuser"
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`test presents a user without slack data 1`] = `
|
||||
Object {
|
||||
"avatarUrl": null,
|
||||
"id": "123",
|
||||
"name": "Test User",
|
||||
"username": "testuser"
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -4,9 +4,9 @@ const presentUser = (ctx, user) => {
|
|||
return new Promise(async (resolve, _reject) => {
|
||||
const data = {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
avatarUrl: user.slackData.image_192,
|
||||
name: user.name,
|
||||
avatarUrl: user.slackData ? user.slackData.image_192 : null,
|
||||
};
|
||||
resolve(data);
|
||||
});
|
||||
|
|
|
@ -17,3 +17,17 @@ it('presents a user', async () => {
|
|||
|
||||
expect(user).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('presents a user without slack data', async () => {
|
||||
const user = await presentUser(
|
||||
ctx,
|
||||
{
|
||||
id: '123',
|
||||
name: 'Test User',
|
||||
username: 'testuser',
|
||||
slackData: null,
|
||||
},
|
||||
);
|
||||
|
||||
expect(user).toMatchSnapshot();
|
||||
});
|
||||
|
|
|
@ -21,9 +21,9 @@ function runMigrations() {
|
|||
path: './server/migrations',
|
||||
},
|
||||
});
|
||||
umzug.up()
|
||||
return umzug.up()
|
||||
.then(() => {
|
||||
sequelize.close();
|
||||
return sequelize.close();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue