Upload avatar to s3 on login

This commit is contained in:
Jori Lallo 2017-10-19 00:49:22 -07:00
parent 0515a6233e
commit 255d7564c5
8 changed files with 111 additions and 17 deletions

View File

@ -61,6 +61,7 @@
}, },
"dependencies": { "dependencies": {
"@tommoor/slate-drop-or-paste-images": "0.5.1", "@tommoor/slate-drop-or-paste-images": "0.5.1",
"aws-sdk": "^2.135.0",
"babel-core": "^6.24.1", "babel-core": "^6.24.1",
"babel-eslint": "^7.2.3", "babel-eslint": "^7.2.3",
"babel-loader": "6.2.5", "babel-loader": "6.2.5",

View File

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

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

View File

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

View File

@ -15,7 +15,6 @@ export async function request(endpoint: string, body: Object) {
} catch (e) { } catch (e) {
throw httpErrors.BadRequest(); throw httpErrors.BadRequest();
} }
console.log('DATA', data);
if (!data.ok) throw httpErrors.BadRequest(data.error); if (!data.ok) throw httpErrors.BadRequest(data.error);
return data; return data;

View File

@ -1,5 +1,13 @@
// @flow
import crypto from 'crypto'; import crypto from 'crypto';
import moment from 'moment'; import moment from 'moment';
import AWS from 'aws-sdk';
import fetch from 'isomorphic-fetch';
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
const makePolicy = () => { const makePolicy = () => {
const policy = { const policy = {
@ -19,7 +27,7 @@ const makePolicy = () => {
return new Buffer(JSON.stringify(policy)).toString('base64'); return new Buffer(JSON.stringify(policy)).toString('base64');
}; };
const signPolicy = policy => { const signPolicy = (policy: any) => {
const signature = crypto const signature = crypto
.createHmac('sha1', process.env.AWS_SECRET_ACCESS_KEY) .createHmac('sha1', process.env.AWS_SECRET_ACCESS_KEY)
.update(policy) .update(policy)
@ -28,4 +36,25 @@ const signPolicy = policy => {
return signature; return signature;
}; };
export { makePolicy, signPolicy }; const uploadToS3FromUrl = async (url: string, key: string) => {
const s3 = new AWS.S3();
try {
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/${process.env.AWS_S3_UPLOAD_BUCKET_NAME}/${key}`;
} catch (_e) {
return undefined;
}
};
export { makePolicy, signPolicy, uploadToS3FromUrl };

View File

@ -339,6 +339,21 @@ autoprefixer@^6.3.1:
postcss "^5.2.16" postcss "^5.2.16"
postcss-value-parser "^3.2.3" postcss-value-parser "^3.2.3"
aws-sdk@^2.135.0:
version "2.135.0"
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.135.0.tgz#81f4a47b99212f2f236bf5b11b0b3a3a02086db4"
dependencies:
buffer "4.9.1"
crypto-browserify "1.0.9"
events "^1.1.1"
jmespath "0.15.0"
querystring "0.2.0"
sax "1.2.1"
url "0.10.3"
uuid "3.1.0"
xml2js "0.4.17"
xmlbuilder "4.2.1"
aws-sign2@~0.6.0: aws-sign2@~0.6.0:
version "0.6.0" version "0.6.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f"
@ -1268,7 +1283,7 @@ buffer-xor@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
buffer@^4.3.0, buffer@^4.9.0: buffer@4.9.1, buffer@^4.3.0, buffer@^4.9.0:
version "4.9.1" version "4.9.1"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
dependencies: dependencies:
@ -1959,6 +1974,10 @@ cryptiles@2.x.x:
dependencies: dependencies:
boom "2.x.x" boom "2.x.x"
crypto-browserify@1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-1.0.9.tgz#cc5449685dfb85eb11c9828acc7cb87ab5bbfcc0"
crypto-browserify@^3.11.0: crypto-browserify@^3.11.0:
version "3.11.1" version "3.11.1"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f"
@ -2923,7 +2942,7 @@ event-stream@~3.3.0:
stream-combiner "~0.0.4" stream-combiner "~0.0.4"
through "~2.3.1" through "~2.3.1"
events@^1.0.0: events@^1.0.0, events@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
@ -4816,6 +4835,10 @@ jest-validate@^20.0.3:
leven "^2.1.0" leven "^2.1.0"
pretty-format "^20.0.3" pretty-format "^20.0.3"
jmespath@0.15.0:
version "0.15.0"
resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217"
joi@^6.10.1, joi@~6.10.1: joi@^6.10.1, joi@~6.10.1:
version "6.10.1" version "6.10.1"
resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06"
@ -7806,7 +7829,11 @@ sane@~1.6.0:
walker "~1.0.5" walker "~1.0.5"
watch "~0.10.0" watch "~0.10.0"
sax@^1.2.1, sax@~1.2.1: sax@1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
sax@>=0.6.0, sax@^1.2.1, sax@~1.2.1:
version "1.2.4" version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@ -8849,16 +8876,16 @@ url-to-options@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9"
url@^0.11.0: url@0.10.3, url@~0.10.1:
version "0.11.0" version "0.10.3"
resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64"
dependencies: dependencies:
punycode "1.3.2" punycode "1.3.2"
querystring "0.2.0" querystring "0.2.0"
url@~0.10.1: url@^0.11.0:
version "0.10.3" version "0.11.0"
resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
dependencies: dependencies:
punycode "1.3.2" punycode "1.3.2"
querystring "0.2.0" querystring "0.2.0"
@ -8899,14 +8926,14 @@ uuid@2.0.2:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.2.tgz#48bd5698f0677e3c7901a1c46ef15b1643794726" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.2.tgz#48bd5698f0677e3c7901a1c46ef15b1643794726"
uuid@3.1.0, uuid@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
uuid@^2.0.1, uuid@^2.0.3: uuid@^2.0.1, uuid@^2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"
uuid@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
v8flags@^2.0.2: v8flags@^2.0.2:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
@ -9202,6 +9229,19 @@ xml-name-validator@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
xml2js@0.4.17:
version "0.4.17"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.17.tgz#17be93eaae3f3b779359c795b419705a8817e868"
dependencies:
sax ">=0.6.0"
xmlbuilder "^4.1.0"
xmlbuilder@4.2.1, xmlbuilder@^4.1.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5"
dependencies:
lodash "^4.0.0"
"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"