DB migrations

Google button
This commit is contained in:
Tom Moor
2018-05-28 20:31:53 -07:00
parent ddd2b82d20
commit 72d874444e
12 changed files with 107 additions and 31 deletions

View File

@@ -14,7 +14,9 @@ router.post('hooks.unfurl', async ctx => {
throw new AuthenticationError('Invalid token');
// TODO: Everything from here onwards will get moved to an async job
const user = await User.find({ where: { slackId: event.user } });
const user = await User.find({
where: { service: 'slack', serviceId: event.user },
});
if (!user) return;
const auth = await Authentication.find({
@@ -55,7 +57,8 @@ router.post('hooks.slack', async ctx => {
const user = await User.find({
where: {
slackId: user_id,
service: 'slack',
serviceId: user_id,
},
});

View File

@@ -32,7 +32,7 @@ describe('#hooks.unfurl', async () => {
event: {
type: 'link_shared',
channel: 'Cxxxxxx',
user: user.slackId,
user: user.serviceId,
message_ts: '123456789.9875',
links: [
{
@@ -55,7 +55,7 @@ describe('#hooks.slack', async () => {
const res = await server.post('/api/hooks.slack', {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
user_id: user.slackId,
user_id: user.serviceId,
text: 'dsfkndfskndsfkn',
},
});
@@ -70,7 +70,7 @@ describe('#hooks.slack', async () => {
const res = await server.post('/api/hooks.slack', {
body: {
token: process.env.SLACK_VERIFICATION_TOKEN,
user_id: user.slackId,
user_id: user.serviceId,
text: document.title,
},
});
@@ -98,7 +98,7 @@ describe('#hooks.slack', async () => {
const res = await server.post('/api/hooks.slack', {
body: {
token: 'wrong-verification-token',
user_id: user.slackId,
user_id: user.serviceId,
text: 'Welcome',
},
});

View File

@@ -1,6 +1,7 @@
// @flow
import Router from 'koa-router';
import addMonths from 'date-fns/add_months';
import { capitalize } from 'lodash';
import { OAuth2Client } from 'google-auth-library';
import { User, Team } from '../models';
@@ -32,17 +33,14 @@ router.get('google.callback', async ctx => {
const response = await client.getToken(code);
client.setCredentials(response.tokens);
console.log('Tokens acquired.');
console.log(response.tokens);
const profile = await client.request({
url: 'https://www.googleapis.com/oauth2/v1/userinfo',
});
const teamName = profile.data.hd.split('.')[0];
const teamName = capitalize(profile.data.hd.split('.')[0]);
const [team, isFirstUser] = await Team.findOrCreate({
where: {
slackId: profile.data.hd,
googleId: profile.data.hd,
},
defaults: {
name: teamName,
@@ -50,9 +48,10 @@ router.get('google.callback', async ctx => {
},
});
const [user, isFirstSignin] = await User.findOrCreate({
const [user] = await User.findOrCreate({
where: {
slackId: profile.data.id,
service: 'google',
serviceId: profile.data.id,
teamId: team.id,
},
defaults: {
@@ -63,10 +62,6 @@ router.get('google.callback', async ctx => {
},
});
if (!isFirstSignin) {
await user.save();
}
if (isFirstUser) {
await team.createFirstCollection(user.id);
}
@@ -77,7 +72,7 @@ router.get('google.callback', async ctx => {
});
ctx.cookies.set('accessToken', user.getJwtToken(), {
httpOnly: false,
expires: addMonths(new Date(), 6),
expires: addMonths(new Date(), 1),
});
ctx.redirect('/');

View File

@@ -26,7 +26,9 @@ router.post('auth.slack', async ctx => {
const data = await Slack.oauthAccess(code);
let user = await User.findOne({ where: { slackId: data.user.id } });
let user = await User.findOne({
where: { service: 'slack', serviceId: data.user.id },
});
let team = await Team.findOne({ where: { slackId: data.team.id } });
const isFirstUser = !team;
@@ -48,7 +50,8 @@ router.post('auth.slack', async ctx => {
await user.save();
} else {
user = await User.create({
slackId: data.user.id,
service: 'slack',
serviceId: data.user.id,
name: data.user.name,
email: data.user.email,
teamId: team.id,

View File

@@ -0,0 +1,27 @@
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.addColumn('teams', 'googleId', {
type: Sequelize.STRING,
allowNull: true,
unique: true
});
await queryInterface.addColumn('teams', 'avatarUrl', {
type: Sequelize.STRING,
allowNull: true,
});
await queryInterface.addColumn('users', 'service', {
type: Sequelize.STRING,
allowNull: true,
defaultValue: 'slack'
});
await queryInterface.renameColumn('users', 'slackId', 'serviceId');
await queryInterface.addIndex('teams', ['googleId']);
},
down: async (queryInterface, Sequelize) => {
await queryInterface.removeColumn('teams', 'googleId');
await queryInterface.removeColumn('teams', 'avatarUrl');
await queryInterface.removeColumn('users', 'service');
await queryInterface.renameColumn('users', 'serviceId', 'slackId');
await queryInterface.removeIndex('teams', ['googleId']);
}
}

View File

@@ -13,6 +13,8 @@ const Team = sequelize.define(
},
name: DataTypes.STRING,
slackId: { type: DataTypes.STRING, allowNull: true },
googleId: { type: DataTypes.STRING, allowNull: true },
avatarUrl: { type: DataTypes.STRING, allowNull: true },
slackData: DataTypes.JSONB,
},
{

View File

@@ -25,7 +25,8 @@ const User = sequelize.define(
passwordDigest: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN,
slackAccessToken: encryptedFields.vault('slackAccessToken'),
slackId: { type: DataTypes.STRING, allowNull: true, unique: true },
service: { type: DataTypes.STRING, allowNull: true, unique: true },
serviceId: { type: DataTypes.STRING, allowNull: true, unique: true },
slackData: DataTypes.JSONB,
jwtSecret: encryptedFields.vault('jwtSecret'),
suspendedAt: DataTypes.DATE,

View File

@@ -3,6 +3,7 @@ import * as React from 'react';
import styled from 'styled-components';
import { signin } from '../../../shared/utils/routeHelpers';
import Flex from '../../../shared/components/Flex';
import GoogleLogo from '../../../shared/components/GoogleLogo';
import SlackLogo from '../../../shared/components/SlackLogo';
import { color } from '../../../shared/styles/constants';
@@ -10,22 +11,27 @@ type Props = {
lastLoggedIn: string,
};
const SlackSignin = ({ lastLoggedIn }: Props) => {
const SignupButton = ({ lastLoggedIn }: Props) => {
return (
<Flex justify="center">
<Flex>
<Flex column>
<Button href={signin('slack')}>
<SlackLogo />
<Spacer>Sign In with Slack</Spacer>
</Button>
{lastLoggedIn === 'slack' && 'You signed in with Slack previously'}
<LastLogin>
{lastLoggedIn === 'slack' && 'You signed in with Slack previously'}
</LastLogin>
</Flex>
&nbsp;
<Flex>
<Flex column>
<Button href={signin('google')}>
<GoogleLogo />
<Spacer>Sign In with Google</Spacer>
</Button>
{lastLoggedIn === 'google' && 'You signed in with Google previously'}
<LastLogin>
{lastLoggedIn === 'google' && 'You signed in with Google previously'}
</LastLogin>
</Flex>
</Flex>
);
@@ -43,6 +49,13 @@ const Button = styled.a`
background: ${color.black};
border-radius: 4px;
font-weight: 600;
height: 56px;
`;
export default SlackSignin;
const LastLogin = styled.p`
font-size: 12px;
color: ${color.slate};
padding-top: 4px;
`;
export default SignupButton;

View File

@@ -40,7 +40,8 @@ export async function buildUser(overrides: Object = {}) {
username: `user${count}`,
name: `User ${count}`,
password: 'test123!',
slackId: uuid.v4(),
service: 'slack',
serviceId: uuid.v4(),
...overrides,
});
}

View File

@@ -30,7 +30,8 @@ const seed = async () => {
name: 'User 1',
password: 'test123!',
teamId: team.id,
slackId: 'U2399UF2P',
service: 'slack',
serviceId: 'U2399UF2P',
slackData: {
id: 'U2399UF2P',
image_192: 'http://example.com/avatar.png',
@@ -45,7 +46,8 @@ const seed = async () => {
password: 'test123!',
teamId: team.id,
isAdmin: true,
slackId: 'U2399UF1P',
service: 'slack',
serviceId: 'U2399UF1P',
slackData: {
id: 'U2399UF1P',
image_192: 'http://example.com/avatar.png',