From f380f1afb22da685d0b6528ec597c52181281cfc Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Wed, 18 Oct 2017 22:42:37 -0700 Subject: [PATCH 1/8] Fixes to strong and a --- frontend/components/Editor/Editor.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend/components/Editor/Editor.js b/frontend/components/Editor/Editor.js index 74779c25c..6a99e730f 100644 --- a/frontend/components/Editor/Editor.js +++ b/frontend/components/Editor/Editor.js @@ -291,6 +291,10 @@ const StyledEditor = styled(Editor)` position: relative; } + a:hover { + text-decoration: ${({ readOnly }) => (readOnly ? 'underline' : 'none')}; + } + li p { display: inline; margin: 0; @@ -332,6 +336,10 @@ const StyledEditor = styled(Editor)` td { padding: 5px 20px 5px 0; } + + b, strong { + font-weight: 600; + } `; export default MarkdownEditor; From 255d7564c597112cb26385db514e3b946cb37752 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Thu, 19 Oct 2017 00:49:22 -0700 Subject: [PATCH 2/8] Upload avatar to s3 on login --- package.json | 1 + server/api/auth.js | 4 ++ .../20171019071915-user-avatar-url.js | 12 ++++ server/models/User.js | 8 +++ server/presenters/user.js | 3 +- server/slack.js | 1 - server/utils/s3.js | 33 +++++++++- yarn.lock | 66 +++++++++++++++---- 8 files changed, 111 insertions(+), 17 deletions(-) create mode 100644 server/migrations/20171019071915-user-avatar-url.js diff --git a/package.json b/package.json index ba097038b..04d7b820b 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ }, "dependencies": { "@tommoor/slate-drop-or-paste-images": "0.5.1", + "aws-sdk": "^2.135.0", "babel-core": "^6.24.1", "babel-eslint": "^7.2.3", "babel-loader": "6.2.5", diff --git a/server/api/auth.js b/server/api/auth.js index 42752b477..51304e5d7 100644 --- a/server/api/auth.js +++ b/server/api/auth.js @@ -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), diff --git a/server/migrations/20171019071915-user-avatar-url.js b/server/migrations/20171019071915-user-avatar-url.js new file mode 100644 index 000000000..5be75d525 --- /dev/null +++ b/server/migrations/20171019071915-user-avatar-url.js @@ -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'); + }, +}; diff --git a/server/models/User.js b/server/models/User.js index 691587800..a2f29488f 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -2,6 +2,7 @@ import crypto from 'crypto'; import bcrypt from 'bcrypt'; import { DataTypes, sequelize, encryptedFields } from '../sequelize'; +import { uploadToS3FromUrl } from '../utils/s3'; import JWT from 'jsonwebtoken'; @@ -18,6 +19,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 +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 => { model.jwtSecret = crypto.randomBytes(64).toString('hex'); diff --git a/server/presenters/user.js b/server/presenters/user.js index f545cd667..1d064acec 100644 --- a/server/presenters/user.js +++ b/server/presenters/user.js @@ -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), }; } diff --git a/server/slack.js b/server/slack.js index 62bb75eb5..ab45d669a 100644 --- a/server/slack.js +++ b/server/slack.js @@ -15,7 +15,6 @@ export async function request(endpoint: string, body: Object) { } catch (e) { throw httpErrors.BadRequest(); } - console.log('DATA', data); if (!data.ok) throw httpErrors.BadRequest(data.error); return data; diff --git a/server/utils/s3.js b/server/utils/s3.js index 65351a98e..1837f7d26 100644 --- a/server/utils/s3.js +++ b/server/utils/s3.js @@ -1,5 +1,13 @@ +// @flow import crypto from 'crypto'; 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 policy = { @@ -19,7 +27,7 @@ const makePolicy = () => { return new Buffer(JSON.stringify(policy)).toString('base64'); }; -const signPolicy = policy => { +const signPolicy = (policy: any) => { const signature = crypto .createHmac('sha1', process.env.AWS_SECRET_ACCESS_KEY) .update(policy) @@ -28,4 +36,25 @@ const signPolicy = policy => { 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 }; diff --git a/yarn.lock b/yarn.lock index 10b245448..d70cdf870 100644 --- a/yarn.lock +++ b/yarn.lock @@ -339,6 +339,21 @@ autoprefixer@^6.3.1: postcss "^5.2.16" 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: version "0.6.0" 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" 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" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: @@ -1959,6 +1974,10 @@ cryptiles@2.x.x: dependencies: 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: version "3.11.1" 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" through "~2.3.1" -events@^1.0.0: +events@^1.0.0, events@^1.1.1: version "1.1.1" 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" 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: version "6.10.1" resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06" @@ -7806,7 +7829,11 @@ sane@~1.6.0: walker "~1.0.5" 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" 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" resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" -url@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" +url@0.10.3, url@~0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" dependencies: punycode "1.3.2" querystring "0.2.0" -url@~0.10.1: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" dependencies: punycode "1.3.2" querystring "0.2.0" @@ -8899,14 +8926,14 @@ uuid@2.0.2: version "2.0.2" 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: version "2.0.3" 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: version "2.1.1" 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" 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: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From e4e2ac8aa19623027660c6a3d01fea2b199a7f69 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 19 Oct 2017 20:44:03 -0700 Subject: [PATCH 3/8] Fixes broken links (#325) * Fixes #323 * Update yarn.lock --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 10b245448..1ac3019c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8036,8 +8036,8 @@ slate-edit-list@^0.7.0: resolved "https://registry.yarnpkg.com/slate-edit-list/-/slate-edit-list-0.7.1.tgz#84ee960d2d5b5a20ce267ad9df894395a91b93d5" slate-markdown-serializer@tommoor/slate-markdown-serializer: - version "0.5.0" - resolved "https://codeload.github.com/tommoor/slate-markdown-serializer/tar.gz/22bdaa096777f5dd7f7c366841a0c6e4392adeb6" + version "0.5.2" + resolved "https://codeload.github.com/tommoor/slate-markdown-serializer/tar.gz/75708cf421c0a0ac0d7d541b295315cbff0839c0" slate-paste-linkify@^0.2.1: version "0.2.1" From d0dbe4cf022da21835e0feb14cae7e37b03d6fed Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 19 Oct 2017 21:02:39 -0700 Subject: [PATCH 4/8] Fixes: Adding Slack command --- frontend/scenes/SlackAuth/SlackAuth.js | 34 ++++++++++++-------------- server/slack.js | 3 +-- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/frontend/scenes/SlackAuth/SlackAuth.js b/frontend/scenes/SlackAuth/SlackAuth.js index 21aa6beaa..2846b75ad 100644 --- a/frontend/scenes/SlackAuth/SlackAuth.js +++ b/frontend/scenes/SlackAuth/SlackAuth.js @@ -2,6 +2,7 @@ import React from 'react'; import { Redirect } from 'react-router'; import queryString from 'query-string'; +import { observable } from 'mobx'; import { observer, inject } from 'mobx-react'; import { client } from 'utils/ApiClient'; @@ -12,17 +13,15 @@ type Props = { location: Object, }; -type State = { - redirectTo: string, -}; - @observer class SlackAuth extends React.Component { props: Props; - state: State; - state = {}; + @observable redirectTo: string; - // $FlowIssue Flow doesn't like async lifecycle components https://github.com/facebook/flow/issues/1803 - async componentDidMount(): void { + componentDidMount() { + this.redirect(); + } + + async redirect() { const { error, code, state } = queryString.parse( this.props.location.search ); @@ -30,18 +29,18 @@ type State = { if (error) { if (error === 'access_denied') { // User selected "Deny" access on Slack OAuth - this.setState({ redirectTo: '/dashboard' }); + this.redirectTo = '/dashboard'; } else { - this.setState({ redirectTo: '/auth/error' }); + this.redirectTo = '/auth/error'; } } else { if (this.props.location.pathname === '/auth/slack/commands') { // User adding webhook integrations try { await client.post('/auth.slackCommands', { code }); - this.setState({ redirectTo: '/dashboard' }); + this.redirectTo = '/dashboard'; } catch (e) { - this.setState({ redirectTo: '/auth/error' }); + this.redirectTo = '/auth/error'; } } else { // Regular Slack authentication @@ -50,18 +49,15 @@ type State = { const { success } = await this.props.auth.authWithSlack(code, state); success - ? this.setState({ redirectTo: redirectTo || '/dashboard' }) - : this.setState({ redirectTo: '/auth/error' }); + ? (this.redirectTo = redirectTo || '/dashboard') + : (this.redirectTo = '/auth/error'); } } } render() { - return ( -
- {this.state.redirectTo && } -
- ); + if (this.redirectTo) return ; + return null; } } diff --git a/server/slack.js b/server/slack.js index 62bb75eb5..82d1a07f8 100644 --- a/server/slack.js +++ b/server/slack.js @@ -15,7 +15,6 @@ export async function request(endpoint: string, body: Object) { } catch (e) { throw httpErrors.BadRequest(); } - console.log('DATA', data); if (!data.ok) throw httpErrors.BadRequest(data.error); return data; @@ -28,7 +27,7 @@ export async function oauthAccess( return request('oauth.access', { client_id: process.env.SLACK_KEY, client_secret: process.env.SLACK_SECRET, - redirect_uri: `${process.env.URL || ''}/auth/slack`, + redirect_uri, code, }); } From 98986fe22699925c5d67a4a5feed57329d50fb66 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 19 Oct 2017 22:00:07 -0700 Subject: [PATCH 5/8] Fix horizontal rule interactions Closes #326 --- .../Editor/components/BlockInsert.js | 25 +++++++++++++------ .../Editor/components/HorizontalRule.js | 17 +++++++++++++ .../Editor/plugins/MarkdownShortcuts.js | 6 ++--- frontend/components/Editor/schema.js | 3 ++- 4 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 frontend/components/Editor/components/HorizontalRule.js diff --git a/frontend/components/Editor/components/BlockInsert.js b/frontend/components/Editor/components/BlockInsert.js index fdc7fb607..43df62813 100644 --- a/frontend/components/Editor/components/BlockInsert.js +++ b/frontend/components/Editor/components/BlockInsert.js @@ -90,12 +90,16 @@ export default class BlockInsert extends Component { this.left = Math.round(boxRect.left + window.scrollX - 20); }; - onClickBlock = ( + insertBlock = ( ev: SyntheticEvent, - type: string | Object, - wrapBlock?: string + options: { + type: string | Object, + wrapper?: string | Object, + append?: string | Object, + } ) => { ev.preventDefault(); + const { type, wrapper, append } = options; let { state } = this.props; let transform = state.transform(); const { document } = state; @@ -112,7 +116,8 @@ export default class BlockInsert extends Component { transform = transform.insertBlock(type); - if (wrapBlock) transform = transform.wrapBlock(wrapBlock); + if (wrapper) transform = transform.wrapBlock(wrapper); + if (append) transform = transform.insertBlock(append); state = transform.focus().apply(); this.props.onChange(state); @@ -134,6 +139,7 @@ export default class BlockInsert extends Component { render() { const style = { top: `${this.top}px`, left: `${this.left}px` }; const todo = { type: 'list-item', data: { checked: false } }; + const rule = { type: 'horizontal-rule', isVoid: true }; return ( @@ -148,9 +154,14 @@ export default class BlockInsert extends Component { label={} onPickImage={this.onPickImage} onInsertList={ev => - this.onClickBlock(ev, 'list-item', 'bulleted-list')} - onInsertTodoList={ev => this.onClickBlock(ev, todo, 'todo-list')} - onInsertBreak={ev => this.onClickBlock(ev, 'horizontal-rule')} + this.insertBlock(ev, { + type: 'list-item', + wrapper: 'bulleted-list', + })} + onInsertTodoList={ev => + this.insertBlock(ev, { type: todo, wrapper: 'todo-list' })} + onInsertBreak={ev => + this.insertBlock(ev, { type: rule, append: 'paragraph' })} onOpen={this.handleMenuOpen} onClose={this.handleMenuClose} /> diff --git a/frontend/components/Editor/components/HorizontalRule.js b/frontend/components/Editor/components/HorizontalRule.js new file mode 100644 index 000000000..375641eae --- /dev/null +++ b/frontend/components/Editor/components/HorizontalRule.js @@ -0,0 +1,17 @@ +// @flow +import React from 'react'; +import styled from 'styled-components'; +import type { Props } from '../types'; +import { color } from 'styles/constants'; + +function HorizontalRule(props: Props) { + const { state, node } = this.props; + const active = state.isFocused && state.selection.hasEdgeIn(node); + return ; +} + +const StyledHr = styled.hr` + border-bottom: 1px solid ${props => (props.active ? color.slate : color.slateLight)}; +`; + +export default HorizontalRule; diff --git a/frontend/components/Editor/plugins/MarkdownShortcuts.js b/frontend/components/Editor/plugins/MarkdownShortcuts.js index 0dd924156..de530b006 100644 --- a/frontend/components/Editor/plugins/MarkdownShortcuts.js +++ b/frontend/components/Editor/plugins/MarkdownShortcuts.js @@ -112,19 +112,17 @@ export default function MarkdownShortcuts() { if (chars === '--') { ev.preventDefault(); - const transform = state + return state .transform() .extendToStartOf(startBlock) .delete() .setBlock({ type: 'horizontal-rule', isVoid: true, - }); - state = transform + }) .collapseToStartOfNextBlock() .insertBlock('paragraph') .apply(); - return state; } }, diff --git a/frontend/components/Editor/schema.js b/frontend/components/Editor/schema.js index e915b636c..2010e4c22 100644 --- a/frontend/components/Editor/schema.js +++ b/frontend/components/Editor/schema.js @@ -1,6 +1,7 @@ // @flow import React from 'react'; import Code from './components/Code'; +import HorizontalRule from './components/HorizontalRule'; import InlineCode from './components/InlineCode'; import Image from './components/Image'; import Link from './components/Link'; @@ -33,7 +34,7 @@ const createSchema = () => { 'block-quote': (props: Props) => (
{props.children}
), - 'horizontal-rule': (props: Props) =>
, + 'horizontal-rule': HorizontalRule, 'bulleted-list': (props: Props) =>
    {props.children}
, 'ordered-list': (props: Props) =>
    {props.children}
, 'todo-list': (props: Props) => {props.children}, From c1a8e15a52ca4a349909ba86858c7491502ef3d2 Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Thu, 19 Oct 2017 23:00:40 -0700 Subject: [PATCH 6/8] flow --- server/utils/s3.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server/utils/s3.js b/server/utils/s3.js index 1837f7d26..ba27134d2 100644 --- a/server/utils/s3.js +++ b/server/utils/s3.js @@ -2,6 +2,7 @@ import crypto from 'crypto'; import moment from 'moment'; import AWS from 'aws-sdk'; +import invariant from 'invariant'; import fetch from 'isomorphic-fetch'; AWS.config.update({ @@ -9,6 +10,9 @@ AWS.config.update({ 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 = { conditions: [ @@ -28,8 +32,9 @@ const makePolicy = () => { }; const signPolicy = (policy: any) => { + invariant(AWS_SECRET_ACCESS_KEY); const signature = crypto - .createHmac('sha1', process.env.AWS_SECRET_ACCESS_KEY) + .createHmac('sha1', AWS_SECRET_ACCESS_KEY) .update(policy) .digest('base64'); @@ -38,8 +43,10 @@ const signPolicy = (policy: any) => { const uploadToS3FromUrl = async (url: string, key: string) => { const s3 = new AWS.S3(); + invariant(AWS_S3_UPLOAD_BUCKET_NAME); try { + // $FlowIssue dunno it's fine const res = await fetch(url); const buffer = await res.buffer(); await s3 @@ -51,7 +58,7 @@ const uploadToS3FromUrl = async (url: string, key: string) => { Body: buffer, }) .promise(); - return `https://s3.amazonaws.com/${process.env.AWS_S3_UPLOAD_BUCKET_NAME}/${key}`; + return `https://s3.amazonaws.com/${AWS_S3_UPLOAD_BUCKET_NAME}/${key}`; } catch (_e) { return undefined; } From 1fdbf256a751308428705e31eadf89ed83f06e0b Mon Sep 17 00:00:00 2001 From: Jori Lallo Date: Thu, 19 Oct 2017 23:30:31 -0700 Subject: [PATCH 7/8] review comments --- server/models/User.js | 3 ++- server/utils/s3.js | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/server/models/User.js b/server/models/User.js index a2f29488f..94b0affce 100644 --- a/server/models/User.js +++ b/server/models/User.js @@ -1,6 +1,7 @@ // @flow import crypto from 'crypto'; import bcrypt from 'bcrypt'; +import uuid from 'uuid'; import { DataTypes, sequelize, encryptedFields } from '../sequelize'; import { uploadToS3FromUrl } from '../utils/s3'; @@ -71,7 +72,7 @@ User.prototype.verifyPassword = function(password) { User.prototype.updateAvatar = async function() { this.avatarUrl = await uploadToS3FromUrl( this.slackData.image_192, - `avatars/${this.id}` + `avatars/${this.id}/${uuid.v4()}` ); }; diff --git a/server/utils/s3.js b/server/utils/s3.js index ba27134d2..14072b5a5 100644 --- a/server/utils/s3.js +++ b/server/utils/s3.js @@ -4,6 +4,7 @@ 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, @@ -32,7 +33,7 @@ const makePolicy = () => { }; const signPolicy = (policy: any) => { - invariant(AWS_SECRET_ACCESS_KEY); + invariant(AWS_SECRET_ACCESS_KEY, 'AWS_SECRET_ACCESS_KEY not set'); const signature = crypto .createHmac('sha1', AWS_SECRET_ACCESS_KEY) .update(policy) @@ -43,7 +44,7 @@ const signPolicy = (policy: any) => { const uploadToS3FromUrl = async (url: string, key: string) => { const s3 = new AWS.S3(); - invariant(AWS_S3_UPLOAD_BUCKET_NAME); + invariant(AWS_S3_UPLOAD_BUCKET_NAME, 'AWS_S3_UPLOAD_BUCKET_NAME not set'); try { // $FlowIssue dunno it's fine @@ -59,8 +60,8 @@ const uploadToS3FromUrl = async (url: string, key: string) => { }) .promise(); return `https://s3.amazonaws.com/${AWS_S3_UPLOAD_BUCKET_NAME}/${key}`; - } catch (_e) { - return undefined; + } catch (e) { + bugsnag.notify(e); } }; From d91c77bfcd602518d9fe4f6d72b809e18e284f56 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Fri, 20 Oct 2017 21:23:13 -0700 Subject: [PATCH 8/8] Fix --- frontend/components/Editor/components/HorizontalRule.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/Editor/components/HorizontalRule.js b/frontend/components/Editor/components/HorizontalRule.js index 375641eae..286a5acb1 100644 --- a/frontend/components/Editor/components/HorizontalRule.js +++ b/frontend/components/Editor/components/HorizontalRule.js @@ -5,7 +5,7 @@ import type { Props } from '../types'; import { color } from 'styles/constants'; function HorizontalRule(props: Props) { - const { state, node } = this.props; + const { state, node } = props; const active = state.isFocused && state.selection.hasEdgeIn(node); return ; }