diff --git a/api-server/common/models/user.js b/api-server/common/models/user.js
index 7ff1db25c0..7db7b13e78 100644
--- a/api-server/common/models/user.js
+++ b/api-server/common/models/user.js
@@ -127,6 +127,9 @@ function nextTick(fn) {
const getRandomNumber = () => Math.random();
function populateRequiredFields(user) {
+ // by default, the displayUsername will have
+ // the same value as the username
+ user.displayUsername = user.username;
user.username = user.username.trim().toLowerCase();
user.email =
typeof user.email === 'string'
@@ -347,6 +350,7 @@ export default function(User) {
if (!username && (!email || !isEmail(email))) {
return Promise.resolve(false);
}
+ username = username.toLowerCase();
log('checking existence');
// check to see if username is on blacklist
@@ -395,6 +399,7 @@ export default function(User) {
cb(null, {});
});
}
+ username = username.toLowerCase();
return User.findOne({ where: { username } }, (err, user) => {
if (err) {
return cb(err);
@@ -724,13 +729,13 @@ export default function(User) {
User.prototype.updateMyUsername = function updateMyUsername(newUsername) {
return Observable.defer(() => {
- const isOwnUsername = isTheSame(newUsername, this.username);
+ const isOwnUsername = isTheSame(newUsername.toLowerCase(), this.username);
if (isOwnUsername) {
return Observable.of(dedent`
${newUsername} is already associated with this account.
`);
}
- return Observable.fromPromise(User.doesExist(newUsername));
+ return Observable.fromPromise(User.doesExist(newUsername.toLowerCase()));
}).flatMap(boolOrMessage => {
if (typeof boolOrMessage === 'string') {
return Observable.of(boolOrMessage);
@@ -741,14 +746,20 @@ export default function(User) {
`);
}
- const usernameUpdate = new Promise((resolve, reject) =>
- this.updateAttribute('username', newUsername, err => {
- if (err) {
- return reject(err);
+ const usernameUpdate = new Promise((resolve, reject) => {
+ this.updateAttributes(
+ {
+ username: newUsername.toLowerCase(),
+ displayUsername: newUsername
+ },
+ err => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve();
}
- return resolve();
- })
- );
+ );
+ });
return Observable.fromPromise(usernameUpdate).map(
() => dedent`
diff --git a/api-server/common/models/user.json b/api-server/common/models/user.json
index fc5d1aaec4..0f7a16fd54 100644
--- a/api-server/common/models/user.json
+++ b/api-server/common/models/user.json
@@ -74,6 +74,10 @@
},
"require": true
},
+ "displayUsername": {
+ "type": "string",
+ "default":""
+ },
"about": {
"type": "string",
"default": ""
diff --git a/api-server/server/boot/settings.js b/api-server/server/boot/settings.js
index 4e366391bd..9941ea06cb 100644
--- a/api-server/server/boot/settings.js
+++ b/api-server/server/boot/settings.js
@@ -194,7 +194,7 @@ function createUpdateMyUsername(app) {
user,
body: { username }
} = req;
- if (username === user.username) {
+ if (username.toLowerCase() === user.username) {
return res.json({
type: 'info',
message: 'Username is already associated with this account'
@@ -209,7 +209,7 @@ function createUpdateMyUsername(app) {
});
}
- const exists = await User.doesExist(username);
+ const exists = await User.doesExist(username.toLowerCase());
if (exists) {
return res.json({
@@ -218,16 +218,19 @@ function createUpdateMyUsername(app) {
});
}
- return user.updateAttribute('username', username, err => {
- if (err) {
- res.status(500).json(standardErrorMessage);
- return next(err);
+ return user.updateAttributes(
+ { username: username.toLowerCase(), displayUsername: username },
+ err => {
+ if (err) {
+ res.status(500).json(standardErrorMessage);
+ return next(err);
+ }
+ return res.status(200).json({
+ type: 'success',
+ message: `We have updated your username to ${username}`
+ });
}
- return res.status(200).json({
- type: 'success',
- message: `We have updated your username to ${username}`
- });
- });
+ );
};
}
diff --git a/api-server/server/utils/auth.js b/api-server/server/utils/auth.js
index dd6d9aad0e..3960799da6 100644
--- a/api-server/server/utils/auth.js
+++ b/api-server/server/utils/auth.js
@@ -37,6 +37,7 @@ function createProfileAttributesFromGithub(profile) {
return {
name,
username: username.toLowerCase(),
+ displayUsername: username,
location,
bio,
website,
diff --git a/api-server/server/utils/publicUserProps.js b/api-server/server/utils/publicUserProps.js
index 71becb1ac3..cde2aa6e9d 100644
--- a/api-server/server/utils/publicUserProps.js
+++ b/api-server/server/utils/publicUserProps.js
@@ -11,6 +11,7 @@ export const publicUserProps = [
'about',
'calendar',
'completedChallenges',
+ 'displayUsername',
'githubProfile',
'isApisMicroservicesCert',
'isBackEndCert',
diff --git a/client/src/client-only-routes/ShowProfileOrFourOhFour.js b/client/src/client-only-routes/ShowProfileOrFourOhFour.js
index b8a01477d5..d5a76f423f 100644
--- a/client/src/client-only-routes/ShowProfileOrFourOhFour.js
+++ b/client/src/client-only-routes/ShowProfileOrFourOhFour.js
@@ -22,6 +22,7 @@ const propTypes = {
navigate: PropTypes.func.isRequired,
requestedUser: PropTypes.shape({
username: PropTypes.string,
+ displayUsername: PropTypes.string,
profileUI: PropTypes.object
}),
showLoading: PropTypes.bool
diff --git a/client/src/client-only-routes/ShowSettings.js b/client/src/client-only-routes/ShowSettings.js
index 8b4e60be3b..ef216e2252 100644
--- a/client/src/client-only-routes/ShowSettings.js
+++ b/client/src/client-only-routes/ShowSettings.js
@@ -48,6 +48,7 @@ const propTypes = {
files: PropTypes.array
})
),
+ displayUsername: PropTypes.string,
email: PropTypes.string,
githubProfile: PropTypes.string,
is2018DataVisCert: PropTypes.bool,
@@ -121,6 +122,7 @@ export function ShowSettings(props) {
toggleNightMode,
user: {
completedChallenges,
+ displayUsername,
email,
is2018DataVisCert,
isApisMicroservicesCert,
@@ -191,9 +193,12 @@ export function ShowSettings(props) {
{name}
} {location &&{location}
} {about &&{about}
} diff --git a/client/src/components/profile/components/TimeLine.js b/client/src/components/profile/components/TimeLine.js index be93b87895..d967ab8c09 100644 --- a/client/src/components/profile/components/TimeLine.js +++ b/client/src/components/profile/components/TimeLine.js @@ -27,6 +27,7 @@ const propTypes = { ) }) ), + displayUsername: PropTypes.string, username: PropTypes.string }; @@ -130,6 +131,7 @@ class TimelineInner extends Component { render() { const { completedMap, + displayUsername, idToNameMap, username, sortedTimeline, @@ -171,9 +173,9 @@ class TimelineInner extends Component { >