diff --git a/api-server/common/models/User-Identity.js b/api-server/common/models/User-Identity.js
index b3913ba3212c51..f9756885cabfec 100644
--- a/api-server/common/models/User-Identity.js
+++ b/api-server/common/models/User-Identity.js
@@ -9,7 +9,6 @@ import { wrapHandledError } from '../../server/utils/create-handled-error.js';
// const log = debug('fcc:models:userIdent');
export default function(UserIdent) {
-
UserIdent.on('dataSourceAttached', () => {
UserIdent.findOne$ = observeMethod(UserIdent, 'findOne');
});
@@ -33,7 +32,7 @@ export default function(UserIdent) {
// get the social provider data and the external id from auth0
profile.id = profile.id || profile.openid;
const auth0IdString = '' + profile.id;
- const [ provider, socialExtId ] = auth0IdString.split('|');
+ const [provider, socialExtId] = auth0IdString.split('|');
const query = {
where: {
provider: provider,
@@ -42,8 +41,10 @@ export default function(UserIdent) {
include: 'user'
};
// get the email from the auth0 (its expected from social providers)
- const email = (profile && profile.emails && profile.emails[0]) ?
- profile.emails[0].value : '';
+ const email =
+ profile && profile.emails && profile.emails[0]
+ ? profile.emails[0].value
+ : '';
if (!isEmail('' + email)) {
throw wrapHandledError(
new Error('invalid or empty email recieved from auth0'),
@@ -60,12 +61,11 @@ export default function(UserIdent) {
}
if (provider === 'email') {
-
return User.findOne$({ where: { email } })
.flatMap(user => {
- return user ?
- Observable.of(user) :
- User.create$({ email }).toPromise();
+ return user
+ ? Observable.of(user)
+ : User.create$({ email }).toPromise();
})
.flatMap(user => {
if (!user) {
@@ -81,56 +81,51 @@ export default function(UserIdent) {
}
);
}
- const createToken = observeQuery(
- AccessToken,
- 'create',
- {
- userId: user.id,
- created: new Date(),
- ttl: user.constructor.settings.ttl
- }
- );
- const updateUser = user.update$({
- emailVerified: true,
- emailAuthLinkTTL: null,
- emailVerifyTTL: null
+ const createToken = observeQuery(AccessToken, 'create', {
+ userId: user.id,
+ created: new Date(),
+ ttl: user.constructor.settings.ttl
});
+ const updateUserPromise = new Promise((resolve, reject) =>
+ user.updateAttributes(
+ {
+ emailVerified: true,
+ emailAuthLinkTTL: null,
+ emailVerifyTTL: null
+ },
+ err => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve();
+ }
+ )
+ );
return Observable.combineLatest(
Observable.of(user),
createToken,
- updateUser,
- (user, token) => ({user, token})
+ Observable.fromPromise(updateUserPromise),
+ (user, token) => ({ user, token })
);
})
- .subscribe(
- ({ user, token }) => cb(null, user, null, token),
- cb
- );
-
+ .subscribe(({ user, token }) => cb(null, user, null, token), cb);
} else {
-
return UserIdent.findOne$(query)
.flatMap(identity => {
- return identity ?
- Observable.of(identity.user()) :
- User.findOne$({ where: { email } })
- .flatMap(user => {
- return user ?
- Observable.of(user) :
- User.create$({ email }).toPromise();
+ return identity
+ ? Observable.of(identity.user())
+ : User.findOne$({ where: { email } }).flatMap(user => {
+ return user
+ ? Observable.of(user)
+ : User.create$({ email }).toPromise();
});
})
.flatMap(user => {
-
- const createToken = observeQuery(
- AccessToken,
- 'create',
- {
- userId: user.id,
- created: new Date(),
- ttl: user.constructor.settings.ttl
- }
- );
+ const createToken = observeQuery(AccessToken, 'create', {
+ userId: user.id,
+ created: new Date(),
+ ttl: user.constructor.settings.ttl
+ });
const updateUser = user.update$({
email: email,
emailVerified: true,
@@ -144,11 +139,7 @@ export default function(UserIdent) {
(user, token) => ({ user, token })
);
})
- .subscribe(
- ({ user, token }) => cb(null, user, null, token),
- cb
- );
-
+ .subscribe(({ user, token }) => cb(null, user, null, token), cb);
}
};
}
diff --git a/api-server/common/models/user.js b/api-server/common/models/user.js
index adfce5de015c8c..f3230fcf823fb9 100644
--- a/api-server/common/models/user.js
+++ b/api-server/common/models/user.js
@@ -614,10 +614,8 @@ module.exports = function(User) {
this.update$({ emailAuthLinkTTL })
);
})
- .map(() =>
- dedent`
- Check your email and click the link we sent you to confirm you email.
- `
+ .map(() => 'Check your email and click the link we sent you to confirm' +
+ ' your new email address.'
);
}
@@ -691,12 +689,18 @@ module.exports = function(User) {
}
})
.flatMap(()=>{
+ const updatePromise = new Promise((resolve, reject) =>
+ this.updateAttributes(updateConfig, err => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve();
+ }));
return Observable.forkJoin(
- this.update$(updateConfig),
+ Observable.fromPromise(updatePromise),
this.requestAuthEmail(false, newEmail),
(_, message) => message
- )
- .doOnNext(() => this.manualReload());
+ );
});
} else {
diff --git a/api-server/server/middlewares/email-not-verified-notice.js b/api-server/server/middlewares/email-not-verified-notice.js
index ae65a65282e317..39d0309c3de6ee 100644
--- a/api-server/server/middlewares/email-not-verified-notice.js
+++ b/api-server/server/middlewares/email-not-verified-notice.js
@@ -2,14 +2,12 @@ import dedent from 'dedent';
const ALLOWED_METHODS = ['GET'];
const EXCLUDED_PATHS = [
- '/api/flyers/findOne',
'/signout',
'/accept-privacy-terms',
'/update-email',
'/confirm-email',
- '/passwordless-change',
- '/external/services/user'
-];
+ '/passwordless-change'
+].reduce((list, item) => [...list, item, `/internal${item}`], []);
export default function emailNotVerifiedNotice() {
return function(req, res, next) {
diff --git a/client/src/client-only-routes/ShowSettings.js b/client/src/client-only-routes/ShowSettings.js
index 9eeb46571f2d02..7da818380f1915 100644
--- a/client/src/client-only-routes/ShowSettings.js
+++ b/client/src/client-only-routes/ShowSettings.js
@@ -12,20 +12,25 @@ import { submitNewAbout, updateUserFlag } from '../redux/settings';
import Layout from '../components/Layout';
import Spacer from '../components/helpers/Spacer';
import Loader from '../components/helpers/Loader';
-import { FullWidthRow } from '../components/helpers';
+import FullWidthRow from '../components/helpers/FullWidthRow';
import About from '../components/settings/About';
import Privacy from '../components/settings/Privacy';
+import Email from '../components/settings/Email';
const propTypes = {
about: PropTypes.string,
+ email: PropTypes.string,
+ isEmailVerified: PropTypes.bool,
location: PropTypes.string,
name: PropTypes.string,
picture: PropTypes.string,
points: PropTypes.number,
+ sendQuincyEmail: PropTypes.bool,
showLoading: PropTypes.bool,
submitNewAbout: PropTypes.func.isRequired,
theme: PropTypes.string,
toggleNightMode: PropTypes.func.isRequired,
+ updateQuincyEmail: PropTypes.func.isRequired,
username: PropTypes.string
};
@@ -34,8 +39,22 @@ const mapStateToProps = createSelector(
userSelector,
(
showLoading,
- { username = '', about, picture, points, name, location, theme }
+ {
+ username = '',
+ about,
+ email,
+ sendQuincyEmail,
+ isEmailVerified,
+ picture,
+ points,
+ name,
+ location,
+ theme
+ }
) => ({
+ email,
+ sendQuincyEmail,
+ isEmailVerified,
showLoading,
username,
about,
@@ -49,12 +68,19 @@ const mapStateToProps = createSelector(
const mapDispatchToProps = dispatch =>
bindActionCreators(
- { submitNewAbout, toggleNightMode: theme => updateUserFlag({theme}) },
+ {
+ submitNewAbout,
+ toggleNightMode: theme => updateUserFlag({ theme }),
+ updateQuincyEmail: sendQuincyEmail => updateUserFlag({ sendQuincyEmail })
+ },
dispatch
);
function ShowSettings(props) {
const {
+ email,
+ isEmailVerified,
+ sendQuincyEmail,
showLoading,
username,
about,
@@ -64,7 +90,8 @@ function ShowSettings(props) {
location,
name,
submitNewAbout,
- toggleNightMode
+ toggleNightMode,
+ updateQuincyEmail
} = props;
if (showLoading) {
@@ -120,9 +147,14 @@ function ShowSettings(props) {
+ You do not have an email associated with this account. +
+