From 1fc7be071550910dc7863338272426aa9159d7a2 Mon Sep 17 00:00:00 2001 From: Mike Stone Date: Thu, 15 Dec 2016 10:00:44 -0500 Subject: [PATCH] Sets user's gravatar URL in the API client (#629) --- frontend/kolide/helpers.js | 15 +++++- frontend/kolide/index.js | 46 ++++++++++++++++--- frontend/kolide/index.tests.js | 2 +- frontend/redux/nodes/auth/actions.js | 22 +++------ frontend/redux/nodes/auth/reducer.tests.js | 25 ++++++---- frontend/redux/nodes/entities/base/helpers.js | 15 +----- .../redux/nodes/entities/invites/config.js | 8 ++-- frontend/redux/nodes/entities/users/config.js | 8 ++-- frontend/test/mocks.js | 13 +++--- 9 files changed, 90 insertions(+), 64 deletions(-) diff --git a/frontend/kolide/helpers.js b/frontend/kolide/helpers.js index c0c6549596..143e875470 100644 --- a/frontend/kolide/helpers.js +++ b/frontend/kolide/helpers.js @@ -1,8 +1,21 @@ import { kebabCase, pick } from 'lodash'; +import md5 from 'js-md5'; const ORG_INFO_ATTRS = ['org_name', 'org_logo_url']; const ADMIN_ATTRS = ['email', 'name', 'password', 'password_confirmation', 'username']; +export const addGravatarUrlToResource = (resource) => { + const { email } = resource; + + const emailHash = md5(email.toLowerCase()); + const gravatarURL = `https://www.gravatar.com/avatar/${emailHash}?d=blank`; + + return { + ...resource, + gravatarURL, + }; +}; + const labelSlug = (label) => { const { display_text: displayText } = label; @@ -29,4 +42,4 @@ const setupData = (formData) => { }; }; -export default { labelSlug, setupData }; +export default { addGravatarUrlToResource, labelSlug, setupData }; diff --git a/frontend/kolide/index.js b/frontend/kolide/index.js index 587267a343..acefd7b4e0 100644 --- a/frontend/kolide/index.js +++ b/frontend/kolide/index.js @@ -44,7 +44,13 @@ class Kolide extends Base { const { INVITES } = endpoints; return this.authenticatedGet(this.endpoint(INVITES)) - .then((response) => { return response.invites; }); + .then((response) => { + const { invites } = response; + + return invites.map((invite) => { + return helpers.addGravatarUrlToResource(invite); + }); + }); } getHosts = () => { @@ -162,21 +168,40 @@ class Kolide extends Base { const { USERS } = endpoints; return this.authenticatedGet(this.endpoint(USERS)) - .then((response) => { return response.users; }); + .then((response) => { + const { users } = response; + + return users.map((user) => { + return helpers.addGravatarUrlToResource(user); + }); + }); } inviteUser = (formData) => { const { INVITES } = endpoints; return this.authenticatedPost(this.endpoint(INVITES), JSON.stringify(formData)) - .then((response) => { return response.invite; }); + .then((response) => { + const { invite } = response; + + return helpers.addGravatarUrlToResource(invite); + }); } loginUser ({ username, password }) { const { LOGIN } = endpoints; const loginEndpoint = this.baseURL + LOGIN; - return Base.post(loginEndpoint, JSON.stringify({ username, password })); + return Base.post(loginEndpoint, JSON.stringify({ username, password })) + .then((response) => { + const { user } = response; + const userWithGravatarUrl = helpers.addGravatarUrlToResource(user); + + return { + ...response, + user: userWithGravatarUrl, + }; + }); } logout () { @@ -190,7 +215,12 @@ class Kolide extends Base { const { ME } = endpoints; const meEndpoint = this.baseURL + ME; - return this.authenticatedGet(meEndpoint); + return this.authenticatedGet(meEndpoint) + .then((response) => { + const { user } = response; + + return helpers.addGravatarUrlToResource(user); + }); } resetPassword (formData) { @@ -227,7 +257,11 @@ class Kolide extends Base { const updateUserEndpoint = `${this.baseURL}${USERS}/${user.id}`; return this.authenticatedPatch(updateUserEndpoint, JSON.stringify(formData)) - .then((response) => { return response.user; }); + .then((response) => { + const { user: updatedUser } = response; + + return helpers.addGravatarUrlToResource(updatedUser); + }); } } diff --git a/frontend/kolide/index.tests.js b/frontend/kolide/index.tests.js index 1e27d1a2a8..e0f2d22b85 100644 --- a/frontend/kolide/index.tests.js +++ b/frontend/kolide/index.tests.js @@ -221,7 +221,7 @@ describe('Kolide - API client', () => { username: 'admin', password: 'secret', }) - .then((user) => { + .then(({ user }) => { expect(user).toEqual(validUser); expect(request.isDone()).toEqual(true); done(); diff --git a/frontend/redux/nodes/auth/actions.js b/frontend/redux/nodes/auth/actions.js index c0d5b51f15..2e37ac348d 100644 --- a/frontend/redux/nodes/auth/actions.js +++ b/frontend/redux/nodes/auth/actions.js @@ -1,5 +1,3 @@ -import md5 from 'js-md5'; - import { configSuccess } from 'redux/nodes/app/actions'; import Kolide from 'kolide'; import userActions from 'redux/nodes/entities/users/actions'; @@ -39,12 +37,7 @@ export const fetchCurrentUser = () => { return (dispatch) => { dispatch(loginRequest); return Kolide.me() - .then((response) => { - const { user } = response; - const { email } = user; - const emailHash = md5(email.toLowerCase()); - - user.gravatarURL = `https://www.gravatar.com/avatar/${emailHash}?d=blank`; + .then((user) => { return dispatch(loginSuccess({ user })); }) .catch((response) => { @@ -59,15 +52,12 @@ export const loginUser = (formData) => { return (dispatch) => { return new Promise((resolve, reject) => { dispatch(loginRequest); + return Kolide.loginUser(formData) .then((response) => { - const { user } = response; - const { email } = user; - const emailHash = md5(email.toLowerCase()); + dispatch(loginSuccess(response)); - user.gravatarURL = `https://www.gravatar.com/avatar/${emailHash}?d=blank`; - dispatch(loginSuccess({ ...response, user })); - return resolve(user); + return resolve(response.user); }) .catch((response) => { const { error } = response; @@ -111,9 +101,9 @@ export const updateUser = (targetUser, formData) => { return new Promise((resolve, reject) => { dispatch(updateUserRequest); return dispatch(userActions.update(targetUser, formData)) - .then((response) => { - const { user } = response; + .then((user) => { dispatch(updateUserSuccess(user)); + return resolve(user); }) .catch((response) => { diff --git a/frontend/redux/nodes/auth/reducer.tests.js b/frontend/redux/nodes/auth/reducer.tests.js index 1157d13cff..6082f3be4f 100644 --- a/frontend/redux/nodes/auth/reducer.tests.js +++ b/frontend/redux/nodes/auth/reducer.tests.js @@ -1,5 +1,6 @@ import configureStore from 'redux-mock-store'; import expect from 'expect'; +import { find } from 'lodash'; import thunk from 'redux-thunk'; import authMiddleware from '../../middlewares/auth'; @@ -48,11 +49,15 @@ describe('Auth - reducer', () => { it('calls the api login endpoint', (done) => { - const loginRequestMock = validLoginRequest(); + const expectedBearerToken = 'expected-bearer-token'; + const loginRequestMock = validLoginRequest(expectedBearerToken); + store.dispatch(loginUser(formData)) - .then((user) => { + .then(() => { + const loginSuccessAction = find(store.getActions(), { type: 'LOGIN_SUCCESS' }); + + expect(loginSuccessAction.payload.token).toEqual(expectedBearerToken); expect(loginRequestMock.isDone()).toEqual(true); - expect(local.getItem('auth_token')).toEqual(user.token); done(); }) .catch(done); @@ -70,22 +75,24 @@ describe('Auth - reducer', () => { }); it('sets the users auth token in local storage', (done) => { - validLoginRequest(); + const expectedBearerToken = 'expected-bearer-token'; + validLoginRequest(expectedBearerToken); store.dispatch(loginUser(formData)) - .then((user) => { - expect(local.getItem('auth_token')).toEqual(user.token); + .then(() => { + expect(local.getItem('auth_token')).toEqual(expectedBearerToken); done(); }) .catch(done); }); it('sets the api client bearerToken', (done) => { - validLoginRequest(); + const expectedBearerToken = 'expected-bearer-token'; + validLoginRequest(expectedBearerToken); store.dispatch(loginUser(formData)) - .then((user) => { - expect(kolide.bearerToken).toEqual(user.token); + .then(() => { + expect(kolide.bearerToken).toEqual(expectedBearerToken); done(); }) .catch(done); diff --git a/frontend/redux/nodes/entities/base/helpers.js b/frontend/redux/nodes/entities/base/helpers.js index a51eac1d3b..a5fd05f807 100644 --- a/frontend/redux/nodes/entities/base/helpers.js +++ b/frontend/redux/nodes/entities/base/helpers.js @@ -1,22 +1,9 @@ -import md5 from 'js-md5'; import { pickBy } from 'lodash'; -export const addGravatarUrlToResource = (resource) => { - const { email } = resource; - - const emailHash = md5(email.toLowerCase()); - const gravatarURL = `https://www.gravatar.com/avatar/${emailHash}?d=blank`; - - return { - ...resource, - gravatarURL, - }; -}; - export const entitiesExceptID = (entities, id) => { return pickBy(entities, (entity, key) => { return String(key) !== String(id); }); }; -export default { entitiesExceptID, addGravatarUrlToResource }; +export default { entitiesExceptID }; diff --git a/frontend/redux/nodes/entities/invites/config.js b/frontend/redux/nodes/entities/invites/config.js index 39dc78c68a..265bbf6617 100644 --- a/frontend/redux/nodes/entities/invites/config.js +++ b/frontend/redux/nodes/entities/invites/config.js @@ -1,7 +1,6 @@ -import { addGravatarUrlToResource } from '../base/helpers'; -import Kolide from '../../../../kolide'; -import reduxConfig from '../base/reduxConfig'; -import schemas from '../base/schemas'; +import Kolide from 'kolide'; +import reduxConfig from 'redux/nodes/entities/base/reduxConfig'; +import schemas from 'redux/nodes/entities/base/schemas'; const { INVITES: schema } = schemas; @@ -10,6 +9,5 @@ export default reduxConfig({ destroyFunc: Kolide.revokeInvite, entityName: 'invites', loadAllFunc: Kolide.getInvites, - parseEntityFunc: addGravatarUrlToResource, schema, }); diff --git a/frontend/redux/nodes/entities/users/config.js b/frontend/redux/nodes/entities/users/config.js index 9f79b95e51..5ed17d352a 100644 --- a/frontend/redux/nodes/entities/users/config.js +++ b/frontend/redux/nodes/entities/users/config.js @@ -1,14 +1,12 @@ -import { addGravatarUrlToResource } from '../base/helpers'; -import Kolide from '../../../../kolide'; -import reduxConfig from '../base/reduxConfig'; -import schemas from '../base/schemas'; +import Kolide from 'kolide'; +import reduxConfig from 'redux/nodes/entities/base/reduxConfig'; +import schemas from 'redux/nodes/entities/base/schemas'; const { USERS } = schemas; export default reduxConfig({ entityName: 'users', loadAllFunc: Kolide.getUsers, - parseEntityFunc: addGravatarUrlToResource, schema: USERS, updateFunc: Kolide.updateUser, }); diff --git a/frontend/test/mocks.js b/frontend/test/mocks.js index 36f47ce242..e521a4ce1b 100644 --- a/frontend/test/mocks.js +++ b/frontend/test/mocks.js @@ -3,7 +3,6 @@ import nock from 'nock'; import helpers from 'kolide/helpers'; export const validUser = { - token: 'auth_token', id: 1, username: 'admin', email: 'admin@kolide.co', @@ -11,7 +10,7 @@ export const validUser = { admin: true, enabled: true, needs_password_reset: false, - gravatarURL: 'https://www.gravatar.com/avatar/7157f4758f8423b59aaee869d919f6b9', + gravatarURL: 'https://www.gravatar.com/avatar/7157f4758f8423b59aaee869d919f6b9?d=blank', }; export const validCreateLabelRequest = (bearerToken, labelParams) => { @@ -85,7 +84,7 @@ export const validInviteUserRequest = (bearerToken, formData) => { }, }) .post('/api/v1/kolide/invites', JSON.stringify(formData)) - .reply(200, formData); + .reply(200, { invite: formData }); }; export const validGetHostsRequest = (bearerToken) => { @@ -149,10 +148,10 @@ export const validGetUsersRequest = (bearerToken) => { .reply(200, { users: [validUser] }); }; -export const validLoginRequest = () => { +export const validLoginRequest = (bearerToken = 'abc123') => { return nock('http://localhost:8080') .post('/api/v1/kolide/login') - .reply(200, validUser); + .reply(200, { user: validUser, token: bearerToken }); }; export const validMeRequest = (bearerToken) => { @@ -162,7 +161,7 @@ export const validMeRequest = (bearerToken) => { }, }) .get('/api/v1/kolide/me') - .reply(200, validUser); + .reply(200, { user: validUser }); }; export const validLogoutRequest = (bearerToken) => { @@ -236,7 +235,7 @@ export const validUpdateQueryRequest = (bearerToken, query, formData) => { export const validUpdateUserRequest = (user, formData) => { return nock('http://localhost:8080') .patch(`/api/v1/kolide/users/${user.id}`, JSON.stringify(formData)) - .reply(200, validUser); + .reply(200, { user: validUser }); };