Skip to content

Commit

Permalink
Support User: Intercept and handle errors, display to user
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jordwest committed Dec 15, 2015
1 parent bc0b48b commit 34d0e22
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 14 deletions.
36 changes: 28 additions & 8 deletions client/components/support-user/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ module.exports = React.createClass( {
return {
supportUser: null,
isSupportUser: false,
showDialog: false
showDialog: false,
errorMessage: null
};
},

Expand All @@ -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 ) {
Expand All @@ -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 );
}
Expand Down Expand Up @@ -129,11 +146,11 @@ module.exports = React.createClass( {
render: function() {
if ( this.state.isSupportUser ) {
return (
<Dialog
<Dialog
isVisible={ this.state.showDialog }
onClose={ this.closeDialog }
buttons={ this.getButtonsRestoreUser() }
additionalClassNames="support-user__dialog"
additionalClassNames="support-user__dialog"
>
<div className="support-user__people-profile">
<div className="support-user__gravatar">
Expand All @@ -152,13 +169,16 @@ module.exports = React.createClass( {
);
} else {
return (
<Dialog
isVisible={ this.state.showDialog }
<Dialog
isVisible={ this.state.showDialog }
onClose={ this.closeDialog }
buttons={ this.getButtonsSupportUser() }
additionalClassNames="support-user__dialog"
additionalClassNames="support-user__dialog"
>
<h2 className="support-user__heading">Support user</h2>
{ this.state.errorMessage &&
<h3 className="support-user__error">{ this.state.errorMessage }</h3>
}
<FormFieldset>
<FormLabel>
<span>Username</span>
Expand Down
4 changes: 2 additions & 2 deletions client/lib/user/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
};

/**
Expand Down
61 changes: 57 additions & 4 deletions shared/lib/wp/support.js
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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' ) {
Expand All @@ -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.
Expand All @@ -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;
}

Expand All @@ -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 );
} );
},
Expand Down

0 comments on commit 34d0e22

Please sign in to comment.