diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-10-27 17:05:43 +0200 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-10-30 09:20:37 +0100 |
commit | 6daddd1d06a834867faccbbb6a0e60f448f2c6d4 (patch) | |
tree | 4b077a11038d5b2607e13200971961c0ec08710b /server/sonar-web | |
parent | 771c15c18356cfe02bad535bdd08ffb1c148d016 (diff) | |
download | sonarqube-6daddd1d06a834867faccbbb6a0e60f448f2c6d4.tar.gz sonarqube-6daddd1d06a834867faccbbb6a0e60f448f2c6d4.zip |
SONAR-10031 Stop computing avatar hash in web app (#2769)
Diffstat (limited to 'server/sonar-web')
19 files changed, 58 insertions, 98 deletions
diff --git a/server/sonar-web/package.json b/server/sonar-web/package.json index 070b2310f07..67eaef0baae 100644 --- a/server/sonar-web/package.json +++ b/server/sonar-web/package.json @@ -8,7 +8,6 @@ "babel-polyfill": "6.26.0", "backbone": "1.2.3", "backbone.marionette": "2.4.3", - "blueimp-md5": "1.1.1", "classnames": "2.2.5", "clipboard": "1.7.1", "create-react-class": "15.6.2", diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js index 68c45c921ec..761cff9cde4 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavUser.js @@ -29,6 +29,7 @@ import { translate } from '../../../../helpers/l10n'; /*:: type CurrentUser = { + avatar?: string, email?: string, isLoggedIn: boolean, name: string @@ -123,7 +124,7 @@ export default class GlobalNavUser extends React.PureComponent { className={classNames('dropdown js-user-authenticated', { open: this.state.open })} ref={node => (this.node = node)}> <a className="dropdown-toggle navbar-avatar" href="#" onClick={this.toggleDropdown}> - <Avatar email={currentUser.email} name={currentUser.name} size={24} /> + <Avatar hash={currentUser.avatar} name={currentUser.name} size={24} /> </a> {this.state.open && ( <ul className="dropdown-menu dropdown-menu-right"> diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.js b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.js index 54f0f55ab25..4fb4f28f2d2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.js +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/GlobalNavUser-test.js @@ -21,7 +21,7 @@ import React from 'react'; import { shallow } from 'enzyme'; import GlobalNavUser from '../GlobalNavUser'; -const currentUser = { isLoggedIn: true, name: 'foo', email: 'foo@bar.baz' }; +const currentUser = { avatar: 'abcd1234', isLoggedIn: true, name: 'foo', email: 'foo@bar.baz' }; const organizations = [ { key: 'myorg', name: 'MyOrg' }, { key: 'foo', name: 'Foo' }, diff --git a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.js.snap b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.js.snap index e77bc5d2d8d..d603a20a60f 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/nav/global/__tests__/__snapshots__/GlobalNavUser-test.js.snap @@ -10,7 +10,7 @@ exports[`should not render the users organizations when they are not activated 1 onClick={[Function]} > <Connect(Avatar) - email="foo@bar.baz" + hash="abcd1234" name="foo" size={24} /> @@ -83,7 +83,7 @@ exports[`should render the right interface for logged in user 1`] = ` onClick={[Function]} > <Connect(Avatar) - email="foo@bar.baz" + hash="abcd1234" name="foo" size={24} /> @@ -144,7 +144,7 @@ exports[`should render the users organizations 1`] = ` onClick={[Function]} > <Connect(Avatar) - email="foo@bar.baz" + hash="abcd1234" name="foo" size={24} /> @@ -283,7 +283,7 @@ exports[`should update the component correctly when the user changes to anonymou onClick={[Function]} > <Connect(Avatar) - email="foo@bar.baz" + hash="abcd1234" name="foo" size={24} /> diff --git a/server/sonar-web/src/main/js/apps/account/components/UserCard.js b/server/sonar-web/src/main/js/apps/account/components/UserCard.js index f6d071696a6..26dbe6e1f96 100644 --- a/server/sonar-web/src/main/js/apps/account/components/UserCard.js +++ b/server/sonar-web/src/main/js/apps/account/components/UserCard.js @@ -32,7 +32,7 @@ export default class UserCard extends React.PureComponent { return ( <div className="account-user"> <div id="avatar" className="pull-left account-user-avatar"> - <Avatar email={user.email} name={user.name} size={60} /> + <Avatar hash={user.avatar} name={user.name} size={60} /> </div> <h1 id="name" className="pull-left"> {user.name} diff --git a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.js b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.js index 025d92df51b..a8c14f3c0c0 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.js +++ b/server/sonar-web/src/main/js/apps/issues/components/BulkChangeModal.js @@ -272,10 +272,9 @@ export default class BulkChangeModal extends React.PureComponent { renderAssigneeOption = (option /*: { avatar?: string, email?: string, label: string } */) => ( <span> - {(option.avatar != null || option.email != null) && ( + {option.avatar != null && ( <Avatar className="little-spacer-right" - email={option.email} hash={option.avatar} name={option.label} size={16} diff --git a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js index 832d3050075..7c5c784dfd6 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/MembersListItem.js @@ -48,7 +48,7 @@ export default class MembersListItem extends React.PureComponent { return ( <tr> <td className="thin nowrap"> - <Avatar hash={member.avatar} email={member.email} name={member.name} size={AVATAR_SIZE} /> + <Avatar hash={member.avatar} name={member.name} size={AVATAR_SIZE} /> </td> <td className="nowrap text-middle"> <strong>{member.name}</strong> diff --git a/server/sonar-web/src/main/js/apps/permissions/shared/components/UserHolder.js b/server/sonar-web/src/main/js/apps/permissions/shared/components/UserHolder.js index 0b0bf92735a..d0b97ae588b 100644 --- a/server/sonar-web/src/main/js/apps/permissions/shared/components/UserHolder.js +++ b/server/sonar-web/src/main/js/apps/permissions/shared/components/UserHolder.js @@ -63,7 +63,7 @@ export default class UserHolder extends React.PureComponent { <td className="nowrap"> {!isCreator && ( <Avatar - email={user.email} + hash={user.avatar} name={user.name} size={36} className="text-middle big-spacer-right" diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js index 46f0794ddac..3fecdcc4592 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js +++ b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js @@ -64,7 +64,7 @@ export default class UsersSelectSearchOption extends React.PureComponent { onMouseEnter={this.handleMouseEnter} onMouseMove={this.handleMouseMove} title={user.name}> - <Avatar hash={user.avatar} email={user.email} name={user.name} size={AVATAR_SIZE} /> + <Avatar hash={user.avatar} name={user.name} size={AVATAR_SIZE} /> <strong className="spacer-left">{this.props.children}</strong> <span className="note little-spacer-left">{user.login}</span> </div> diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchValue.js b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchValue.js index 4354b75b1e0..347d9359b14 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchValue.js +++ b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchValue.js @@ -41,7 +41,7 @@ export default class UsersSelectSearchValue extends React.PureComponent { {user && user.login && ( <div className="Select-value-label"> - <Avatar hash={user.avatar} email={user.email} name={user.name} size={AVATAR_SIZE} /> + <Avatar hash={user.avatar} name={user.name} size={AVATAR_SIZE} /> <strong className="spacer-left">{this.props.children}</strong> <span className="note little-spacer-left">{user.login}</span> </div> diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap index b3e752014e7..e75246d2acb 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap @@ -8,7 +8,6 @@ exports[`should render correctly with email instead of hash 1`] = ` title="Administrator" > <Connect(Avatar) - email="admin@admin.ch" name="Administrator" size={16} /> diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchValue-test.js.snap b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchValue-test.js.snap index 1387a28aec2..1aad7300b2a 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchValue-test.js.snap +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchValue-test.js.snap @@ -36,7 +36,6 @@ exports[`should render correctly with email instead of hash 1`] = ` className="Select-value-label" > <Connect(Avatar) - email="admin@admin.ch" name="Administrator" size={16} /> diff --git a/server/sonar-web/src/main/js/apps/users/templates/users-list-item.hbs b/server/sonar-web/src/main/js/apps/users/templates/users-list-item.hbs index 44c303a7db1..63136b96402 100644 --- a/server/sonar-web/src/main/js/apps/users/templates/users-list-item.hbs +++ b/server/sonar-web/src/main/js/apps/users/templates/users-list-item.hbs @@ -1,5 +1,5 @@ <td class="thin nowrap"> - <div>{{avatarHelper email name 36}}</div> + <div>{{avatarHelper avatar name 36}}</div> </td> <td> diff --git a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js index 9c6b6187c65..365ed241de1 100644 --- a/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js +++ b/server/sonar-web/src/main/js/components/issue/popups/SetAssigneePopup.js @@ -148,13 +148,7 @@ export default class SetAssigneePopup extends React.PureComponent { {this.state.users.map(user => ( <SelectListItem key={user.login} item={user.login}> {!!user.login && ( - <Avatar - className="spacer-right" - email={user.email} - hash={user.avatar} - name={user.name} - size={16} - /> + <Avatar className="spacer-right" hash={user.avatar} name={user.name} size={16} /> )} <span className="vertical-middle" diff --git a/server/sonar-web/src/main/js/components/ui/Avatar.js b/server/sonar-web/src/main/js/components/ui/Avatar.tsx index 448fb782f4b..d9f09b24076 100644 --- a/server/sonar-web/src/main/js/components/ui/Avatar.js +++ b/server/sonar-web/src/main/js/components/ui/Avatar.tsx @@ -17,46 +17,21 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import React from 'react'; -import PropTypes from 'prop-types'; +import * as React from 'react'; import { connect } from 'react-redux'; -import md5 from 'blueimp-md5'; -import classNames from 'classnames'; +import * as classNames from 'classnames'; import { getGlobalSettingValue } from '../../store/rootReducer'; -function stringToColor(str) { - let hash = 0; - for (let i = 0; i < str.length; i++) { - hash = str.charCodeAt(i) + ((hash << 5) - hash); - } - let color = '#'; - for (let i = 0; i < 3; i++) { - const value = (hash >> (i * 8)) & 0xff; - color += ('00' + value.toString(16)).substr(-2); - } - return color; +interface Props { + className?: string; + enableGravatar: boolean; + gravatarServerUrl: string; + hash?: string; + name: string; + size: number; } -function getTextColor(background) { - const rgb = parseInt(background.substr(1), 16); - const r = (rgb >> 16) & 0xff; - const g = (rgb >> 8) & 0xff; - const b = (rgb >> 0) & 0xff; - const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; - return luma > 140 ? '#222' : '#fff'; -} - -class Avatar extends React.PureComponent { - static propTypes = { - enableGravatar: PropTypes.bool.isRequired, - gravatarServerUrl: PropTypes.string.isRequired, - email: PropTypes.string, - hash: PropTypes.string, - name: PropTypes.string.isRequired, - size: PropTypes.number.isRequired, - className: PropTypes.string - }; - +class Avatar extends React.PureComponent<Props> { renderFallback() { const className = classNames(this.props.className, 'rounded'); const color = stringToColor(this.props.name); @@ -90,30 +65,27 @@ class Avatar extends React.PureComponent { } render() { - if (!this.props.enableGravatar) { + if (!this.props.enableGravatar || !this.props.hash) { return this.renderFallback(); } - const emailHash = this.props.hash || md5((this.props.email || '').toLowerCase()).trim(); const url = this.props.gravatarServerUrl - .replace('{EMAIL_MD5}', emailHash) - .replace('{SIZE}', this.props.size * 2); - - const className = classNames(this.props.className, 'rounded'); + .replace('{EMAIL_MD5}', this.props.hash) + .replace('{SIZE}', String(this.props.size * 2)); return ( <img - className={className} + className={classNames(this.props.className, 'rounded')} src={url} width={this.props.size} height={this.props.size} - alt={this.props.email} + alt={this.props.name} /> ); } } -const mapStateToProps = state => ({ +const mapStateToProps = (state: any) => ({ enableGravatar: (getGlobalSettingValue(state, 'sonar.lf.enableGravatar') || {}).value === 'true', gravatarServerUrl: (getGlobalSettingValue(state, 'sonar.lf.gravatarServerUrl') || {}).value }); @@ -121,3 +93,26 @@ const mapStateToProps = state => ({ export default connect(mapStateToProps)(Avatar); export const unconnectedAvatar = Avatar; + +/* eslint-disable no-bitwise, no-mixed-operators */ +function stringToColor(str: string) { + let hash = 0; + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash); + } + let color = '#'; + for (let i = 0; i < 3; i++) { + const value = (hash >> (i * 8)) & 0xff; + color += ('00' + value.toString(16)).substr(-2); + } + return color; +} + +function getTextColor(background: string) { + const rgb = parseInt(background.substr(1), 16); + const r = (rgb >> 16) & 0xff; + const g = (rgb >> 8) & 0xff; + const b = (rgb >> 0) & 0xff; + const luma = 0.2126 * r + 0.7152 * g + 0.0722 * b; + return luma > 140 ? '#222' : '#fff'; +} diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.js b/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx index 044e07240b1..e42d8c0d454 100644 --- a/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.js +++ b/server/sonar-web/src/main/js/components/ui/__tests__/Avatar-test.tsx @@ -17,25 +17,12 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import * as React from 'react'; import { shallow } from 'enzyme'; -import React from 'react'; import { unconnectedAvatar as Avatar } from '../Avatar'; const gravatarServerUrl = 'http://example.com/{EMAIL_MD5}.jpg?s={SIZE}'; -it.skip('should render', () => { - const avatar = shallow( - <Avatar - enableGravatar={true} - gravatarServerUrl={gravatarServerUrl} - email="mail@example.com" - name="Foo" - size={20} - /> - ); - expect(avatar).toMatchSnapshot(); -}); - it('should be able to render with hash only', () => { const avatar = shallow( <Avatar diff --git a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Avatar-test.js.snap b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Avatar-test.tsx.snap index d51b5ecabcb..6dd7bc59142 100644 --- a/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Avatar-test.js.snap +++ b/server/sonar-web/src/main/js/components/ui/__tests__/__snapshots__/Avatar-test.tsx.snap @@ -24,19 +24,10 @@ exports[`falls back to dummy avatar 1`] = ` exports[`should be able to render with hash only 1`] = ` <img + alt="Foo" className="rounded" height={30} src="http://example.com/7daf6c79d4802916d83f6266e24850af.jpg?s=60" width={30} /> `; - -exports[`should render 1`] = ` -<img - alt="mail@example.com" - className="rounded" - height={20} - src="http://example.com/7daf6c79d4802916d83f6266e24850af.jpg?s=40" - width={20} -/> -`; diff --git a/server/sonar-web/src/main/js/helpers/handlebars/avatarHelper.js b/server/sonar-web/src/main/js/helpers/handlebars/avatarHelper.js index 03e2d4190a1..1d975f433cf 100644 --- a/server/sonar-web/src/main/js/helpers/handlebars/avatarHelper.js +++ b/server/sonar-web/src/main/js/helpers/handlebars/avatarHelper.js @@ -23,11 +23,11 @@ const Handlebars = require('handlebars/runtime'); const WithStore = require('../../components/shared/WithStore').default; const Avatar = require('../../components/ui/Avatar').default; -module.exports = function(email, name, size) { +module.exports = function(hash, name, size) { return new Handlebars.default.SafeString( renderToString( <WithStore> - <Avatar email={email} name={name} size={size} /> + <Avatar hash={hash} name={name} size={size} /> </WithStore> ) ); diff --git a/server/sonar-web/yarn.lock b/server/sonar-web/yarn.lock index 8bf05a358c7..d7a273aa92a 100644 --- a/server/sonar-web/yarn.lock +++ b/server/sonar-web/yarn.lock @@ -1296,10 +1296,6 @@ bluebird@^3.4.7: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" -blueimp-md5@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-1.1.1.tgz#cf84ba18285f5c8835dae8ddae5af6468ceace17" - bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" |