Unfurling of Slack links (#487)

* First pass: Unfurling of Slack links

* Add authentication in db

* Call associate on Event correctly

* Add SLACK_APP_ID, remove SLACK_REDIRECT_URI, tidy env sample

* PR feedback

* Comment clarify
This commit is contained in:
Tom Moor
2017-12-18 19:59:29 -08:00
committed by GitHub
parent 938bb3fc31
commit 32ba98bb1a
19 changed files with 219 additions and 48 deletions

View File

@@ -2,7 +2,7 @@
import Router from 'koa-router';
import auth from './middlewares/authentication';
import { presentUser, presentTeam } from '../presenters';
import { User, Team } from '../models';
import { Authentication, User, Team } from '../models';
import * as Slack from '../slack';
const router = new Router();
@@ -81,11 +81,21 @@ router.post('auth.slack', async ctx => {
};
});
router.post('auth.slackCommands', async ctx => {
router.post('auth.slackCommands', auth(), async ctx => {
const { code } = ctx.body;
ctx.assertPresent(code, 'code is required');
await Slack.oauthAccess(code, `${process.env.URL || ''}/auth/slack/commands`);
const user = ctx.state.user;
const endpoint = `${process.env.URL || ''}/auth/slack/commands`;
const data = await Slack.oauthAccess(code, endpoint);
await Authentication.create({
serviceId: 'slack',
userId: user.id,
teamId: user.teamId,
token: data.access_token,
scopes: data.scope.split(','),
});
});
export default router;

View File

@@ -1,10 +1,48 @@
// @flow
import Router from 'koa-router';
import httpErrors from 'http-errors';
import { Document, User } from '../models';
import { Authentication, Document, User } from '../models';
import * as Slack from '../slack';
const router = new Router();
router.post('hooks.unfurl', async ctx => {
const { challenge, token, event } = ctx.body;
if (challenge) return (ctx.body = ctx.body.challenge);
if (token !== process.env.SLACK_VERIFICATION_TOKEN)
throw httpErrors.BadRequest('Invalid token');
// TODO: Everything from here onwards will get moved to an async job
const user = await User.find({ where: { slackId: event.user } });
if (!user) return;
const auth = await Authentication.find({
where: { serviceId: 'slack', teamId: user.teamId },
});
if (!auth) return;
// get content for unfurled links
let unfurls = {};
for (let link of event.links) {
const id = link.url.substr(link.url.lastIndexOf('/') + 1);
const doc = await Document.findById(id);
if (!doc || doc.teamId !== user.teamId) continue;
unfurls[link.url] = {
title: doc.title,
text: doc.getSummary(),
color: doc.collection.color,
};
}
await Slack.post('chat.unfurl', {
token: auth.token,
channel: event.channel,
ts: event.message_ts,
unfurls,
});
});
router.post('hooks.slack', async ctx => {
const { token, user_id, text } = ctx.body;
ctx.assertPresent(token, 'token is required');

View File

@@ -10,11 +10,13 @@ export default function apiWrapper() {
const ok = ctx.status < 400;
// $FlowFixMe
ctx.body = {
...ctx.body,
status: ctx.status,
ok,
};
if (typeof ctx.body !== 'string') {
// $FlowFixMe
ctx.body = {
...ctx.body,
status: ctx.status,
ok,
};
}
};
}