diff --git a/client/src/pages/welcome.js b/client/src/pages/welcome.js
index a4b7afcfb9..56ecc8a8f9 100644
--- a/client/src/pages/welcome.js
+++ b/client/src/pages/welcome.js
@@ -9,7 +9,11 @@ import Helmet from 'react-helmet';
import { Loader, Spacer } from '../components/helpers';
import Layout from '../components/layouts/Default';
-import { userSelector, userFetchStateSelector } from '../redux';
+import {
+ userSelector,
+ userFetchStateSelector,
+ isSignedInSelector
+} from '../redux';
import { randomQuote } from '../utils/get-words';
import './welcome.css';
@@ -20,6 +24,7 @@ const propTypes = {
complete: PropTypes.bool,
errored: PropTypes.bool
}),
+ isSignedIn: PropTypes.bool,
user: PropTypes.shape({
acceptedPrivacyTerms: PropTypes.bool,
username: PropTypes.string,
@@ -32,20 +37,22 @@ const propTypes = {
const mapStateToProps = createSelector(
userFetchStateSelector,
+ isSignedInSelector,
userSelector,
- (fetchState, user) => ({ fetchState, user })
+ (fetchState, isSignedIn, user) => ({ fetchState, isSignedIn, user })
);
const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
function Welcome({
fetchState: { pending, complete },
+ isSignedIn,
user: {
acceptedPrivacyTerms,
name = '',
- completedChallengeCount = 0,
+ completedChallengeCount: completedChallenges = 0,
completedProjectCount = 0,
completedCertCount = 0,
- completedLegacyCertCount = 0
+ completedLegacyCertCount: completedLegacyCerts = 0
}
}) {
if (pending && !complete) {
@@ -58,7 +65,12 @@ function Welcome({
);
}
- if (!acceptedPrivacyTerms) {
+ if (!isSignedIn) {
+ navigate('/');
+ return null;
+ }
+
+ if (isSignedIn && !acceptedPrivacyTerms) {
navigate('/accept-privacy-terms');
return null;
}
@@ -70,72 +82,72 @@ function Welcome({
Welcome {name ? name : 'Camper'} | freeCodeCamp.org
-
-
-
-
- Welcome {name ? name : 'Camper'}!
-
-
-
-
-
-
- We're building a massive open dataset about new coders. Take the
- 2018 New Coder Survey. It only takes 5 minutes.
-
-
-
-
-
-
-
-
- {quote}
-
-
-
-
-
-
-
-
-
- You have completed {completedChallengeCount} of{' '}
- 1408 coding challenges.
-
-
- You have built {completedProjectCount} of{' '}
- 30 projects.
-
- {completedLegacyCertCount ? (
+
+
+
+
+ Welcome {name ? name : 'Camper'}!
+
+
+
+
+
+
+ We're building a massive open dataset about new coders. Take the
+ 2018 New Coder Survey. It only takes 5 minutes.
+
+
+
+
+
+
+
+
+ {quote}
+
+
+
+
+
+
+
+
- You have earned {completedLegacyCertCount} of{' '}
- 4 legacy certifications.
+ You have completed {completedChallenges} of{' '}
+ 1408 coding challenges.
- ) : null}
-
- You have earned {completedCertCount} of{' '}
- 6 certifications.
-
-
-
-
-
-
-
-
-
-
-
+
+ You have built {completedProjectCount} of{' '}
+ 30 projects.
+
+ {completedLegacyCerts ? (
+
+ You have earned {completedLegacyCerts} of{' '}
+ 4 legacy certifications.
+
+ ) : null}
+
+ You have earned {completedCertCount} of{' '}
+ 6 certifications.
+
+
+
+
+
+
+
+
+
+
+
);
diff --git a/client/src/redux/failed-updates-epic.js b/client/src/redux/failed-updates-epic.js
index be5875fba3..33fa0bd3c2 100644
--- a/client/src/redux/failed-updates-epic.js
+++ b/client/src/redux/failed-updates-epic.js
@@ -11,7 +11,12 @@ import { ofType } from 'redux-observable';
import store from 'store';
import uuid from 'uuid/v4';
-import { types, onlineStatusChange, isOnlineSelector } from './';
+import {
+ types,
+ onlineStatusChange,
+ isOnlineSelector,
+ isSignedInSelector
+} from './';
import postUpdate$ from '../templates/Challenges/utils/postUpdate$';
import { isGoodXHRStatus } from '../templates/Challenges/utils';
@@ -36,6 +41,7 @@ function failedUpdateEpic(action$, state$) {
const flushUpdates = action$.pipe(
ofType(types.fetchUserComplete, types.updateComplete),
+ filter(() => isSignedInSelector(state$.value)),
filter(() => store.get(key)),
filter(() => isOnlineSelector(state$.value)),
tap(() => {
diff --git a/client/src/redux/fetch-user-saga.js b/client/src/redux/fetch-user-saga.js
index 4d2e64559c..d6bb6c0696 100644
--- a/client/src/redux/fetch-user-saga.js
+++ b/client/src/redux/fetch-user-saga.js
@@ -2,8 +2,13 @@ import { call, put, takeEvery } from 'redux-saga/effects';
import { fetchUserComplete, fetchUserError } from './';
import { getSessionUser } from '../utils/ajax';
+import { jwt } from './cookieValues';
function* fetchSessionUser() {
+ if (!jwt) {
+ yield put(fetchUserComplete({ user: {}, username: '' }));
+ return;
+ }
try {
const {
data: { user = {}, result = '' }
diff --git a/client/src/redux/index.js b/client/src/redux/index.js
index 25b2a3cc74..dc29f9444f 100644
--- a/client/src/redux/index.js
+++ b/client/src/redux/index.js
@@ -47,6 +47,7 @@ export const types = createTypes(
[
'appMount',
'closeDonationModal',
+ 'hardGoTo',
'openDonationModal',
'onlineStatusChange',
'updateComplete',
@@ -81,6 +82,11 @@ export const openDonationModal = createAction(types.openDonationModal);
export const onlineStatusChange = createAction(types.onlineStatusChange);
+// `hardGoTo` is used to hit the API server directly
+// without going through /internal
+// used for things like /signin and /signout
+export const hardGoTo = createAction(types.hardGoTo);
+
export const updateComplete = createAction(types.updateComplete);
export const updateFailed = createAction(types.updateFailed);
diff --git a/config/secrets.js b/config/secrets.js
index a5d7f27c18..a0f4559fd9 100644
--- a/config/secrets.js
+++ b/config/secrets.js
@@ -1,53 +1,90 @@
+const {
+ MONGODB,
+ MONGOHQ_URL,
+
+ SESSION_SECRET,
+ COOKIE_SECRET,
+ JWT_SECRET,
+
+ AUTH0_CLIENT_ID,
+ AUTH0_CLIENT_SECRET,
+ AUTH0_DOMAIN,
+
+ FACEBOOK_ID,
+ FACEBOOK_SECRET,
+
+ GITHUB_ID,
+ GITHUB_SECRET,
+
+ GOOGLE_ID,
+ GOOGLE_SECRET,
+
+ LINKEDIN_ID,
+ LINKEDIN_SECRET,
+
+ TWITTER_KEY,
+ TWITTER_SECRET,
+ TWITTER_TOKEN,
+ TWITTER_TOKEN_SECRET,
+
+ STRIPE_PUBLIC,
+ STRIPE_SECRET
+} = process.env;
+
module.exports = {
+ db: MONGODB || MONGOHQ_URL,
- db: process.env.MONGODB || process.env.MONGOHQ_URL,
+ cookieSecret: COOKIE_SECRET,
+ jwtSecret: JWT_SECRET,
+ sessionSecret: SESSION_SECRET,
- sessionSecret: process.env.SESSION_SECRET,
+ auth0: {
+ clientID: AUTH0_CLIENT_ID,
+ clientSecret: AUTH0_CLIENT_SECRET,
+ domain: AUTH0_DOMAIN
+ },
facebook: {
- clientID: process.env.FACEBOOK_ID,
- clientSecret: process.env.FACEBOOK_SECRET,
+ clientID: FACEBOOK_ID,
+ clientSecret: FACEBOOK_SECRET,
callbackURL: '/auth/facebook/callback',
passReqToCallback: true
},
github: {
- clientID: process.env.GITHUB_ID,
- clientSecret: process.env.GITHUB_SECRET,
+ clientID: GITHUB_ID,
+ clientSecret: GITHUB_SECRET,
callbackURL: '/auth/github/callback',
passReqToCallback: true
},
twitter: {
- consumerKey: process.env.TWITTER_KEY,
- consumerSecret: process.env.TWITTER_SECRET,
- token: process.env.TWITTER_TOKEN,
- tokenSecret: process.env.TWITTER_TOKEN_SECRET,
+ consumerKey: TWITTER_KEY,
+ consumerSecret: TWITTER_SECRET,
+ token: TWITTER_TOKEN,
+ tokenSecret: TWITTER_TOKEN_SECRET,
callbackURL: '/auth/twitter/callback',
passReqToCallback: true
},
google: {
- clientID: process.env.GOOGLE_ID,
- clientSecret: process.env.GOOGLE_SECRET,
+ clientID: GOOGLE_ID,
+ clientSecret: GOOGLE_SECRET,
callbackURL: '/auth/google/callback',
passReqToCallback: true
},
linkedin: {
- clientID: process.env.LINKEDIN_ID,
- clientSecret: process.env.LINKEDIN_SECRET,
+ clientID: LINKEDIN_ID,
+ clientSecret: LINKEDIN_SECRET,
callbackURL: '/auth/linkedin/callback',
profileFields: ['public-profile-url'],
scope: ['r_basicprofile', 'r_emailaddress'],
passReqToCallback: true
},
- slackHook: process.env.SLACK_WEBHOOK,
-
- cookieSecret: process.env.COOKIE_SECRET,
stripe: {
- public: process.env.STRIPE_PUBLIC,
- secret: process.env.STRIPE_SECRET
+ public: STRIPE_PUBLIC,
+ secret: STRIPE_SECRET
}
};