Skip to content

Commit

Permalink
Me: Allow Gravatar uploads (#15636)
Browse files Browse the repository at this point in the history
* EditGravatar: remove bearer token and use new endpoint

* Config: enable me/edit-gravatar in development

* Data-layer: add gravatarUpload

* EditGravatar: Fix calypso_edit_gravatar_file_receive_failure event typo
  • Loading branch information
sirbrillig authored Jul 7, 2017
1 parent b1f47d8 commit f839992
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 147 deletions.
25 changes: 1 addition & 24 deletions client/blocks/edit-gravatar/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import { connect } from 'react-redux';
import debugFactory from 'debug';
import { localize } from 'i18n-calypso';
import path from 'path';
import Gridicon from 'gridicons';
Expand All @@ -17,7 +16,6 @@ import { AspectRatios } from 'state/ui/editor/image-editor/constants';
import Dialog from 'components/dialog';
import FilePicker from 'components/file-picker';
import { getCurrentUser } from 'state/current-user/selectors';
import { getToken as getOauthToken } from 'lib/oauth-token';
import Gravatar from 'components/gravatar';
import {
isCurrentUserUploadingGravatar,
Expand All @@ -41,11 +39,6 @@ import {
composeAnalytics,
} from 'state/analytics/actions';

/**
* Module dependencies
*/
const debug = debugFactory( 'calypso:edit-gravatar' );

export class EditGravatar extends Component {
state = {
isEditingImage: false,
Expand Down Expand Up @@ -124,24 +117,8 @@ export class EditGravatar extends Component {
return;
}

// check for bearerToken from desktop app
let bearerToken = getOauthToken();

// check for bearer token from local storage - for testing purposes
if ( ! bearerToken ) {
bearerToken = localStorage.getItem( 'bearerToken' );
}

// send gravatar request
if ( bearerToken ) {
debug( 'Got the bearerToken, sending request' );
uploadGravatarAction( imageBlob, bearerToken, user.email );
} else {
receiveGravatarImageFailedAction( {
errorMessage: translate( "Hmm, we can't save a new Gravatar now. Please try again later." ),
statName: 'no_bearer_token',
} );
}
uploadGravatarAction( imageBlob, user.email );
};

hideImageEditor = () => {
Expand Down
53 changes: 6 additions & 47 deletions client/state/current-user/gravatar-status/actions.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,9 @@
/**
* External dependencies
*/
import request from 'superagent';

/**
* Internal dependencies
*/
import {
GRAVATAR_RECEIVE_IMAGE_FAILURE,
GRAVATAR_UPLOAD_RECEIVE,
GRAVATAR_UPLOAD_REQUEST,
GRAVATAR_UPLOAD_REQUEST_SUCCESS,
GRAVATAR_UPLOAD_REQUEST_FAILURE
} from 'state/action-types';
import {
bumpStat,
Expand All @@ -20,50 +12,17 @@ import {
withAnalytics,
} from 'state/analytics/actions';

export function uploadGravatar( file, bearerToken, email ) {
return dispatch => {
dispatch( withAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_start' ),
{ type: GRAVATAR_UPLOAD_REQUEST }
) );

const data = new FormData();
data.append( 'filedata', file );
data.append( 'account', email );
return request
.post( 'https://api.gravatar.com/v1/upload-image' )
.send( data )
.set( 'Authorization', 'Bearer ' + bearerToken )
.then( () => {
const fileReader = new FileReader();
fileReader.addEventListener( 'load', function() {
dispatch( {
type: GRAVATAR_UPLOAD_RECEIVE,
src: fileReader.result,
} );
dispatch( withAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_success' ),
{ type: GRAVATAR_UPLOAD_REQUEST_SUCCESS }
) );
} );
fileReader.readAsDataURL( file );
} )
.catch( () => {
dispatch( withAnalytics(
composeAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_failure' ),
bumpStat( 'calypso_gravatar_update_error', 'unsuccessful_http_response' )
),
{ type: GRAVATAR_UPLOAD_REQUEST_FAILURE }
) );
} );
};
export function uploadGravatar( file, email ) {
return withAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_start' ),
{ type: GRAVATAR_UPLOAD_REQUEST, file, email }
);
}

export const receiveGravatarImageFailed = ( { errorMessage, statName } ) =>
withAnalytics(
composeAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_file_recieve_failure' ),
recordTracksEvent( 'calypso_edit_gravatar_file_receive_failure' ),
bumpStat( 'calypso_gravatar_update_error', statName )
),
{
Expand Down
81 changes: 6 additions & 75 deletions client/state/current-user/gravatar-status/test/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,95 +2,26 @@
* External dependencies
*/
import { expect } from 'chai';
import { noop } from 'lodash';
import sinon from 'sinon';

/**
* Internal dependencies
*/
import {
GRAVATAR_RECEIVE_IMAGE_FAILURE,
GRAVATAR_UPLOAD_RECEIVE,
GRAVATAR_UPLOAD_REQUEST,
GRAVATAR_UPLOAD_REQUEST_SUCCESS,
GRAVATAR_UPLOAD_REQUEST_FAILURE
} from 'state/action-types';
} from 'state/action-types';
import {
receiveGravatarImageFailed,
uploadGravatar
} from '../actions';
import useNock from 'test/helpers/use-nock';
import { useSandbox } from 'test/helpers/use-sinon';

describe( 'actions', () => {
let sandbox, spy;
const tempImageSrc = 'tempImageSrc';
useSandbox( newSandbox => {
sandbox = newSandbox;
spy = sandbox.spy();
global.FormData = sandbox.stub().returns( {
append: noop
} );
global.FileReader = sandbox.stub().returns( {
readAsDataURL: noop,
addEventListener: function( event, callback ) {
this.result = tempImageSrc;
callback();
}
} );
} );

describe( '#uploadGravatar', () => {
it( 'dispatches request action when thunk triggered', () => {
uploadGravatar( 'file', 'bearerToken', 'email' )( spy );
expect( spy ).to.have.been.calledWith( sinon.match( {
type: GRAVATAR_UPLOAD_REQUEST
} ) );
} );

describe( 'successful request', () => {
useNock( ( nock ) => {
nock( 'https://api.gravatar.com' )
.persist()
.post( '/v1/upload-image' )
.reply( 200, 'Successful request' );
} );

it( 'dispatches receive action', () => {
return uploadGravatar( 'file', 'bearerToken', 'email' )( spy )
.then( () => {
expect( spy ).to.have.been.calledWith( {
type: GRAVATAR_UPLOAD_RECEIVE,
src: tempImageSrc
} );
} );
} );

it( 'dispatches success action', () => {
return uploadGravatar( 'file', 'bearerToken', 'email' )( spy )
.then( () => {
expect( spy ).to.have.been.calledWith( sinon.match( {
type: GRAVATAR_UPLOAD_REQUEST_SUCCESS
} ) );
} );
} );
} );

describe( 'failed request', () => {
useNock( ( nock ) => {
nock( 'https://api.gravatar.com' )
.post( '/v1/upload-image' )
.reply( 400, 'Failed request' );
} );

it( 'dispatches failure action', () => {
return uploadGravatar( 'file', 'bearerToken', 'email' )( spy )
.then( () => {
expect( spy ).to.have.been.calledWith( sinon.match( {
type: GRAVATAR_UPLOAD_REQUEST_FAILURE
} ) );
} );
} );
it( 'dispatches request action with the file and email', () => {
const action = uploadGravatar( 'file', 'email' );
expect( action.type ).to.equal( GRAVATAR_UPLOAD_REQUEST );
expect( action.file ).to.equal( 'file' );
expect( action.email ).to.equal( 'email' );
} );
} );

Expand Down
60 changes: 60 additions & 0 deletions client/state/data-layer/wpcom/gravatar-upload/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Internal dependencies
*/
import {
GRAVATAR_UPLOAD_RECEIVE,
GRAVATAR_UPLOAD_REQUEST,
GRAVATAR_UPLOAD_REQUEST_SUCCESS,
GRAVATAR_UPLOAD_REQUEST_FAILURE,
} from 'state/action-types';
import { http } from 'state/data-layer/wpcom-http/actions';
import { dispatchRequest } from 'state/data-layer/wpcom-http/utils';
import {
bumpStat,
composeAnalytics,
recordTracksEvent,
withAnalytics,
} from 'state/analytics/actions';

export function uploadGravatar( { dispatch }, action ) {
const { email, file } = action;
dispatch( http( {
method: 'POST',
path: '/gravatar-upload',
body: {},
apiNamespace: 'wpcom/v2',
formData: [
[ 'account', email ],
[ 'filedata', file ],
],
}, action ) );
}

export function announceSuccess( { dispatch }, { file } ) {
const fileReader = new FileReader();
fileReader.addEventListener( 'load', () => {
dispatch( {
type: GRAVATAR_UPLOAD_RECEIVE,
src: fileReader.result,
} );
dispatch( withAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_success' ),
{ type: GRAVATAR_UPLOAD_REQUEST_SUCCESS }
) );
} );
fileReader.readAsDataURL( file );
}

export function announceFailure( { dispatch } ) {
dispatch( withAnalytics(
composeAnalytics(
recordTracksEvent( 'calypso_edit_gravatar_upload_failure' ),
bumpStat( 'calypso_gravatar_update_error', 'unsuccessful_http_response' )
),
{ type: GRAVATAR_UPLOAD_REQUEST_FAILURE }
) );
}

export default {
[ GRAVATAR_UPLOAD_REQUEST ]: [ dispatchRequest( uploadGravatar, announceSuccess, announceFailure ) ],
};
101 changes: 101 additions & 0 deletions client/state/data-layer/wpcom/gravatar-upload/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* External dependencies
*/
import { expect } from 'chai';
import sinon, { spy } from 'sinon';

/**
* Internal dependencies
*/
import { useSandbox } from 'test/helpers/use-sinon';
import { http } from 'state/data-layer/wpcom-http/actions';
import {
GRAVATAR_UPLOAD_RECEIVE,
GRAVATAR_UPLOAD_REQUEST_SUCCESS,
GRAVATAR_UPLOAD_REQUEST_FAILURE,
} from 'state/action-types';
import {
uploadGravatar,
announceSuccess,
announceFailure,
} from '../';

describe( '#uploadGravatar()', () => {
it( 'dispatches an HTTP request to the gravatar upload endpoint', () => {
const action = {
type: 'DUMMY_ACTION',
file: 'file',
email: 'email',
};
const dispatch = spy();

uploadGravatar( { dispatch }, action );

expect( dispatch ).to.have.been.calledOnce;
expect( dispatch ).to.have.been.calledWith( http( {
apiNamespace: 'wpcom/v2',
method: 'POST',
body: {},
path: '/gravatar-upload',
formData: [
[ 'account', 'email' ],
[ 'filedata', 'file' ],
],
}, action ) );
} );
} );

describe( '#announceSuccess()', () => {
let sandbox;
const noop = () => {};

const tempImageSrc = 'tempImageSrc';
useSandbox( newSandbox => {
sandbox = newSandbox;
global.FormData = sandbox.stub().returns( {
append: noop
} );
global.FileReader = sandbox.stub().returns( {
readAsDataURL: noop,
addEventListener: function( event, callback ) {
this.result = tempImageSrc;
callback();
}
} );
} );

it( 'dispatches a success action when the file is read', () => {
const action = {
type: 'DUMMY_ACTION',
file: 'file',
email: 'email',
};
const dispatch = spy();

announceSuccess( { dispatch }, action, noop, { success: true } );
expect( dispatch ).to.have.been.calledWith( sinon.match( { type: GRAVATAR_UPLOAD_REQUEST_SUCCESS } ) );
} );

it( 'dispatches a upload received action with the image data when the file is read', () => {
const action = {
type: 'DUMMY_ACTION',
file: 'file',
email: 'email',
};
const dispatch = spy();

announceSuccess( { dispatch }, action, noop, { success: true } );
expect( dispatch ).to.have.been.calledWith( sinon.match( { type: GRAVATAR_UPLOAD_RECEIVE, src: 'tempImageSrc' } ) );
} );
} );

describe( '#announceFailure()', () => {
it( 'should dispatch an error notice', () => {
const dispatch = spy();

announceFailure( { dispatch } );

expect( dispatch ).to.have.been.calledOnce;
expect( dispatch ).to.have.been.calledWith( sinon.match( { type: GRAVATAR_UPLOAD_REQUEST_FAILURE } ) );
} );
} );
Loading

0 comments on commit f839992

Please sign in to comment.