From 34d0e2208857c84c83fa6030129a95f94052b801 Mon Sep 17 00:00:00 2001 From: Jordan West Date: Tue, 15 Dec 2015 21:56:18 +0100 Subject: [PATCH] Support User: Intercept and handle errors, display to user This change intercepts errors that occur when a support token becomes invalid. When this happens, the support user entry dialog is displayed along with the error message. This also now provides the user feedback when the password is entered incorrectly. --- client/components/support-user/index.jsx | 36 ++++++++++---- client/lib/user/user.js | 4 +- shared/lib/wp/support.js | 61 ++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 14 deletions(-) diff --git a/client/components/support-user/index.jsx b/client/components/support-user/index.jsx index b088fa70517ce..b7e9915f612eb 100644 --- a/client/components/support-user/index.jsx +++ b/client/components/support-user/index.jsx @@ -36,7 +36,8 @@ module.exports = React.createClass( { return { supportUser: null, isSupportUser: false, - showDialog: false + showDialog: false, + errorMessage: null }; }, @@ -58,18 +59,33 @@ module.exports = React.createClass( { this.setState( { showDialog: false } ); }, + onTokenError: function( error ) { + this.setState( { + supportUser: null, + supportPassword: null, + isSupportUser: false, + showDialog: true, + errorMessage: error.message + } ); + }, + onChangeUser: function( e ) { e.preventDefault(); if ( this.state.supportUser && this.state.supportPassword ) { let user = new User(); user.clear(); - user.changeUser( this.state.supportUser, this.state.supportPassword ); + user.changeUser( + this.state.supportUser, + this.state.supportPassword, + ( error ) => this.onTokenError( error ) + ); this.setState( { isSupportUser: true } ); this.setState( { supportPassword: null } ); } this.setState( { showDialog: false } ); + this.setState( { errorMessage: null } ); }, onRestoreUser: function( e ) { @@ -80,7 +96,8 @@ module.exports = React.createClass( { supportUser: null, supportPassword: null, isSupportUser: false, - showDialog: false + showDialog: false, + errorMessage: null } ); window.location.reload.bind( window.location ); } @@ -129,11 +146,11 @@ module.exports = React.createClass( { render: function() { if ( this.state.isSupportUser ) { return ( -
@@ -152,13 +169,16 @@ module.exports = React.createClass( { ); } else { return ( -

Support user

+ { this.state.errorMessage && +

{ this.state.errorMessage }

+ } Username diff --git a/client/lib/user/user.js b/client/lib/user/user.js index f2d6b9a042651..c33286444aec1 100644 --- a/client/lib/user/user.js +++ b/client/lib/user/user.js @@ -238,12 +238,12 @@ User.prototype.set = function( attributes ) { return changed; }; -User.prototype.changeUser = function( username, password ) { +User.prototype.changeUser = function( username, password, tokenErrorCallback ) { wpcom.changeUser( username, password, function( error ) { if ( ! error ) { this.fetch(); } - }.bind( this ) ); + }.bind( this ), tokenErrorCallback ); }; /** diff --git a/shared/lib/wp/support.js b/shared/lib/wp/support.js index 6ad97b80db19a..98e7880ca15f6 100644 --- a/shared/lib/wp/support.js +++ b/shared/lib/wp/support.js @@ -1,6 +1,20 @@ export default function wpcomSupport( wpcom ) { let supportUser = ''; let supportToken = ''; + let tokenErrorCallback; + + // Error names returned by the server + const ERROR_INVALID_SUPPORT_TOKEN = 'invalid_support_token'; + const ERROR_INCORRECT_SUPPORT_PASSWORD = 'incorrect_password' + + /** + * Return the index of the callback in the request arguments + */ + const getCallbackIndex = function( args ) { + return args.findIndex( ( arg ) => { + return 'function' === typeof arg; + } ); + } /** * Request parameters are as follows: @@ -18,9 +32,7 @@ export default function wpcomSupport( wpcom ) { let fnIndex, queryIndex; // Find the index of the callback in the arguments - fnIndex = args.findIndex( function( e ) { - return 'function' === typeof e; - } ); + fnIndex = getCallbackIndex( args ); // Set queryIndex based on the request type and fnIndex if ( req === 'post' || req === 'put' ) { @@ -41,6 +53,26 @@ export default function wpcomSupport( wpcom ) { } ); } + /** + * Intercept any token errors in the response callback. + */ + const interceptResponse = function ( responseCallback ) { + return ( ...args ) => { + const error = args[ 0 ], + response = args[ 1 ]; + + if ( error && error.error === ERROR_INVALID_SUPPORT_TOKEN ) { + if ( tokenErrorCallback ) { + tokenErrorCallback( error ); + } + } + + if ( responseCallback ) { + responseCallback( ...args ); + } + } + } + /** * Mutate the query parameter of the request by adding values for * support_user and _support_token to the query parameter. @@ -56,6 +88,17 @@ export default function wpcomSupport( wpcom ) { } else { args.splice( 1, 0, addSupportData( {} ) ); } + + let callbackIndex = getCallbackIndex( args ); + if ( callbackIndex ) { + // Wrap the callback to intercept any token errors + args[ callbackIndex ] = interceptResponse( args[ callbackIndex ] ); + } else { + // No response callback was provided, so we add one to the end of the + // arguments, purely to handle the token errors + args.push( interceptResponse( null ) ); + } + return args; } @@ -65,18 +108,28 @@ export default function wpcomSupport( wpcom ) { const put = wpcom.req.put.bind( wpcom.req ); return Object.assign( wpcom, { - changeUser: function( username, password, fn ) { + changeUser: function( username, password, fn, fnTokenError ) { var args = { apiVersion: '1.1', path: '/internal/support/' + username + '/grant' }; + tokenErrorCallback = ( ...args ) => { + wpcom.restoreUser(); + + fnTokenError( ...args ); + } + return wpcom.req.post( args, { password: password }, function( error, response ) { if ( ! error ) { supportUser = response.username; supportToken = response.token; } + if ( error && error.error === ERROR_INCORRECT_SUPPORT_PASSWORD ) { + fnTokenError( error ); + } + fn( error, response ); } ); },