Merge pull request #329 from jorilallo/jori/avatar-s3

Upload avatars to S3
This commit is contained in:
Jori Lallo
2017-10-19 23:39:16 -07:00
committed by GitHub
7 changed files with 121 additions and 17 deletions

View File

@ -47,6 +47,10 @@ router.post('auth.slack', async ctx => {
await team.createFirstCollection(user.id);
}
// Update user's avatar
await user.updateAvatar();
await user.save();
ctx.body = {
data: {
user: await presentUser(ctx, user),

View File

@ -0,0 +1,12 @@
module.exports = {
up: function(queryInterface, Sequelize) {
queryInterface.addColumn('users', 'avatarUrl', {
type: Sequelize.TEXT,
allowNull: true,
});
},
down: function(queryInterface, Sequelize) {
queryInterface.removeColumn('users', 'avatarUrl');
},
};

View File

@ -1,7 +1,9 @@
// @flow
import crypto from 'crypto';
import bcrypt from 'bcrypt';
import uuid from 'uuid';
import { DataTypes, sequelize, encryptedFields } from '../sequelize';
import { uploadToS3FromUrl } from '../utils/s3';
import JWT from 'jsonwebtoken';
@ -18,6 +20,7 @@ const User = sequelize.define(
email: { type: DataTypes.STRING },
username: { type: DataTypes.STRING },
name: DataTypes.STRING,
avatarUrl: { type: DataTypes.STRING, allowNull: true },
password: DataTypes.VIRTUAL,
passwordDigest: DataTypes.STRING,
isAdmin: DataTypes.BOOLEAN,
@ -66,6 +69,12 @@ User.prototype.verifyPassword = function(password) {
});
});
};
User.prototype.updateAvatar = async function() {
this.avatarUrl = await uploadToS3FromUrl(
this.slackData.image_192,
`avatars/${this.id}/${uuid.v4()}`
);
};
const setRandomJwtSecret = model => {
model.jwtSecret = crypto.randomBytes(64).toString('hex');

View File

@ -8,7 +8,8 @@ function present(ctx: Object, user: User) {
id: user.id,
username: user.username,
name: user.name,
avatarUrl: user.slackData ? user.slackData.image_192 : null,
avatarUrl: user.avatarUrl ||
(user.slackData ? user.slackData.image_192 : null),
};
}

View File

@ -1,5 +1,18 @@
// @flow
import crypto from 'crypto';
import moment from 'moment';
import AWS from 'aws-sdk';
import invariant from 'invariant';
import fetch from 'isomorphic-fetch';
import bugsnag from 'bugsnag';
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
const AWS_S3_UPLOAD_BUCKET_NAME = process.env.AWS_S3_UPLOAD_BUCKET_NAME;
const makePolicy = () => {
const policy = {
@ -19,13 +32,37 @@ const makePolicy = () => {
return new Buffer(JSON.stringify(policy)).toString('base64');
};
const signPolicy = policy => {
const signPolicy = (policy: any) => {
invariant(AWS_SECRET_ACCESS_KEY, 'AWS_SECRET_ACCESS_KEY not set');
const signature = crypto
.createHmac('sha1', process.env.AWS_SECRET_ACCESS_KEY)
.createHmac('sha1', AWS_SECRET_ACCESS_KEY)
.update(policy)
.digest('base64');
return signature;
};
export { makePolicy, signPolicy };
const uploadToS3FromUrl = async (url: string, key: string) => {
const s3 = new AWS.S3();
invariant(AWS_S3_UPLOAD_BUCKET_NAME, 'AWS_S3_UPLOAD_BUCKET_NAME not set');
try {
// $FlowIssue dunno it's fine
const res = await fetch(url);
const buffer = await res.buffer();
await s3
.putObject({
Bucket: process.env.AWS_S3_UPLOAD_BUCKET_NAME,
Key: key,
ContentType: res.headers['content-type'],
ContentLength: res.headers['content-length'],
Body: buffer,
})
.promise();
return `https://s3.amazonaws.com/${AWS_S3_UPLOAD_BUCKET_NAME}/${key}`;
} catch (e) {
bugsnag.notify(e);
}
};
export { makePolicy, signPolicy, uploadToS3FromUrl };