Merge branch 'staging' of github.com:FreeCodeCamp/freecodecamp into staging
This commit is contained in:
@@ -12,6 +12,7 @@ module.exports = function(app) {
|
||||
var User = app.models.User;
|
||||
var UserIdentity = app.models.UserIdentity;
|
||||
var UserCredential = app.models.UserCredential;
|
||||
var Email = app.models.Email;
|
||||
User.observe('before delete', function(ctx, next) {
|
||||
debug('removing user', ctx.where);
|
||||
var id = ctx.where && ctx.where.id ? ctx.where.id : null;
|
||||
@@ -41,4 +42,51 @@ module.exports = function(app) {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// set email varified false on user email signup
|
||||
// should not be set with oauth signin methods
|
||||
User.beforeRemote('create', function(ctx, user, next) {
|
||||
var body = ctx.req.body;
|
||||
if (body) {
|
||||
body.emailVerified = false;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// send welcome email to new camper
|
||||
User.afterRemote('create', function(ctx, user, next) {
|
||||
debug('user created, sending email');
|
||||
if (!user.email) { return next(); }
|
||||
|
||||
var mailOptions = {
|
||||
type: 'email',
|
||||
to: user.email,
|
||||
from: 'Team@freecodecamp.com',
|
||||
subject: 'Welcome to Free Code Camp!',
|
||||
redirect: '/',
|
||||
text: [
|
||||
'Greetings from San Francisco!\n\n',
|
||||
'Thank you for joining our community.\n',
|
||||
'Feel free to email us at this address if you have ',
|
||||
'any questions about Free Code Camp.\n',
|
||||
'And if you have a moment, check out our blog: ',
|
||||
'blog.freecodecamp.com.\n',
|
||||
'Good luck with the challenges!\n\n',
|
||||
'- the Free Code Camp Volunteer Team'
|
||||
].join('')
|
||||
};
|
||||
|
||||
debug('sending welcome email');
|
||||
Email.send(mailOptions, function(err) {
|
||||
if (err) { return next(err); }
|
||||
ctx.req.logIn(user, function(err) {
|
||||
if (err) { return next(err); }
|
||||
|
||||
ctx.req.flash('success', {
|
||||
msg: [ 'thanks for joining freecodecamp!' ]
|
||||
});
|
||||
ctx.res.redirect('/');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@@ -7,15 +7,15 @@
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
@@ -31,12 +31,13 @@
|
||||
*/
|
||||
|
||||
var R = require('ramda'),
|
||||
utils = require('../utils'),
|
||||
userMigration = require('../utils/middleware').userMigration,
|
||||
MDNlinks = require('../../seed/bonfireMDNlinks');
|
||||
utils = require('../utils'),
|
||||
userMigration = require('../utils/middleware').userMigration,
|
||||
MDNlinks = require('../../seed/bonfireMDNlinks');
|
||||
|
||||
var challengeMapWithNames = utils.getChallengeMapWithNames();
|
||||
var challengeMapWithIds = utils.getChallengeMapWithIds();
|
||||
var challengeMapWithDashedNames = utils.getChallengeMapWithDashedNames();
|
||||
|
||||
|
||||
function getMDNlinks(links) {
|
||||
@@ -79,7 +80,7 @@ module.exports = function(app) {
|
||||
|
||||
function returnNextChallenge(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
var completed = req.user.completedChallenges.map(function (elem) {
|
||||
return elem.id;
|
||||
@@ -108,32 +109,28 @@ module.exports = function(app) {
|
||||
if (indexOfChallenge + 1
|
||||
< challengeMapWithIds[challengeBlock].length) {
|
||||
nextChallengeName =
|
||||
challengeMapWithNames[challengeBlock][++indexOfChallenge];
|
||||
challengeMapWithDashedNames[challengeBlock][++indexOfChallenge];
|
||||
} else if (typeof challengeMapWithIds[++challengeBlock] !== 'undefined') {
|
||||
nextChallengeName = R.head(challengeMapWithNames[challengeBlock]);
|
||||
nextChallengeName = R.head(challengeMapWithDashedNames[challengeBlock]);
|
||||
} else {
|
||||
req.flash('errors', {
|
||||
msg: 'It looks like you have finished all of our challenges.' +
|
||||
' Great job! Now on to helping nonprofits!'
|
||||
});
|
||||
nextChallengeName = R.head(challengeMapWithNames[0].challenges);
|
||||
nextChallengeName = R.head(challengeMapWithDashedNames[0].challenges);
|
||||
}
|
||||
|
||||
var nameString = nextChallengeName.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-');
|
||||
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
return res.redirect('../challenges/' + nameString);
|
||||
return res.redirect('../challenges/' + nextChallengeName);
|
||||
});
|
||||
}
|
||||
|
||||
function returnCurrentChallenge(req, res, next) {
|
||||
if (!req.user) {
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
return res.redirect('../challenges/learn-how-free-code-camp-works');
|
||||
}
|
||||
var completed = req.user.completedChallenges.map(function (elem) {
|
||||
return elem.id;
|
||||
@@ -150,16 +147,12 @@ module.exports = function(app) {
|
||||
req.user.currentChallenge.challengeId = challengeMapWithIds['0'][0];
|
||||
req.user.currentChallenge.challengeName = challengeMapWithNames['0'][0];
|
||||
req.user.currentChallenge.challengeBlock = '0';
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
});
|
||||
req.user.currentChallenge.dashedName =
|
||||
challengeMapWithDashedNames['0'][0];
|
||||
}
|
||||
var nameString = req.user.currentChallenge.challengeName.trim()
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-\/.]/gi, '');
|
||||
|
||||
var nameString = req.user.currentChallenge.dashedName;
|
||||
|
||||
req.user.save(function(err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
@@ -171,40 +164,25 @@ module.exports = function(app) {
|
||||
function returnIndividualChallenge(req, res, next) {
|
||||
var dashedName = req.params.challengeName;
|
||||
|
||||
var challengeName =
|
||||
(/^(bonfire|waypoint|zipline|basejump)/i).test(dashedName) ?
|
||||
dashedName
|
||||
.replace(/\-/g, ' ')
|
||||
.split(' ')
|
||||
.slice(1)
|
||||
.join(' ') :
|
||||
dashedName.replace(/\-/g, ' ');
|
||||
|
||||
Challenge.find(
|
||||
{ where: { name: new RegExp(challengeName, 'i') } },
|
||||
function(err, challengeFromMongo) {
|
||||
Challenge.findOne(
|
||||
{ where: { dashedName: dashedName }},
|
||||
function(err, challenge) {
|
||||
if (err) { return next(err); }
|
||||
|
||||
// Handle not found
|
||||
if (challengeFromMongo.length < 1) {
|
||||
if (!challenge) {
|
||||
req.flash('errors', {
|
||||
msg: '404: We couldn\'t find a challenge with that name. ' +
|
||||
'Please double check the name.'
|
||||
});
|
||||
return res.redirect('/challenges');
|
||||
}
|
||||
var challenge = challengeFromMongo.pop();
|
||||
// Redirect to full name if the user only entered a partial
|
||||
var dashedNameFull = challenge.name
|
||||
.toLowerCase()
|
||||
.replace(/\s/g, '-')
|
||||
.replace(/[^a-z0-9\-\.]/gi, '');
|
||||
if (dashedNameFull !== dashedName) {
|
||||
return res.redirect('../challenges/' + dashedNameFull);
|
||||
} else if (req.user) {
|
||||
if (req.user) {
|
||||
req.user.currentChallenge = {
|
||||
challengeId: challenge.id,
|
||||
challengeName: challenge.name,
|
||||
dashedName: challenge.dashedName,
|
||||
challengeBlock: R.head(R.flatten(Object.keys(challengeMapWithIds).
|
||||
map(function (key) {
|
||||
return challengeMapWithIds[key]
|
||||
|
@@ -29,7 +29,7 @@ module.exports = function(app) {
|
||||
|
||||
var completedChallengeList = noDuplicatedChallenges
|
||||
.map(function(challenge) {
|
||||
return challenge.id;
|
||||
return (challenge.id || challenge._id); // backwards compatibility
|
||||
});
|
||||
var challengeList = utils.
|
||||
getChallengeMapForDisplay(completedChallengeList);
|
||||
@@ -37,7 +37,8 @@ module.exports = function(app) {
|
||||
Object.keys(challengeList).forEach(function(key) {
|
||||
challengeList[key].completed = challengeList[key]
|
||||
.challenges.filter(function(elem) {
|
||||
return completedChallengeList.indexOf(elem.id) > -1;
|
||||
return completedChallengeList.indexOf(elem.id || elem._id) > -1;
|
||||
//backwards compatibility hack
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
var R = require('ramda'),
|
||||
// Rx = require('rx'),
|
||||
// debug = require('debug')('freecc:fieldguides'),
|
||||
debug = require('debug')('freecc:fieldguides'),
|
||||
utils = require('../utils');
|
||||
|
||||
module.exports = function(app) {
|
||||
@@ -102,6 +102,11 @@ module.exports = function(app) {
|
||||
function(err, fieldGuide) {
|
||||
|
||||
if (err) { return next(err); }
|
||||
if (!fieldGuide) {
|
||||
debug('bad juju in field guide %s',
|
||||
req.user.uncompletedFieldGuides[0]);
|
||||
return res.redirect('../field-guide/how-do-i-use-this-guide');
|
||||
}
|
||||
return res.redirect('../field-guide/' + fieldGuide.dashedName);
|
||||
});
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@ var _ = require('lodash'),
|
||||
crypto = require('crypto'),
|
||||
nodemailer = require('nodemailer'),
|
||||
moment = require('moment'),
|
||||
debug = require('debug')('freecc:cntr:userController'),
|
||||
//debug = require('debug')('freecc:cntr:userController'),
|
||||
|
||||
secrets = require('../../config/secrets');
|
||||
|
||||
@@ -28,6 +28,7 @@ module.exports = function(app) {
|
||||
router.post('/reset/:token', postReset);
|
||||
router.get('/email-signup', getEmailSignup);
|
||||
router.get('/email-signin', getEmailSignin);
|
||||
|
||||
router.get('/account/api', getAccountAngular);
|
||||
router.post('/account/profile', postUpdateProfile);
|
||||
router.post('/account/password', postUpdatePassword);
|
||||
@@ -97,6 +98,9 @@ module.exports = function(app) {
|
||||
*/
|
||||
|
||||
function getAccount (req, res) {
|
||||
if (!req.user) {
|
||||
return res.redirect('/');
|
||||
}
|
||||
res.render('account/account', {
|
||||
title: 'Manage your Free Code Camp Account'
|
||||
});
|
||||
@@ -108,7 +112,7 @@ module.exports = function(app) {
|
||||
|
||||
function getAccountAngular (req, res) {
|
||||
res.json({
|
||||
user: req.user
|
||||
user: req.user || {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,15 +123,12 @@ module.exports = function(app) {
|
||||
*/
|
||||
|
||||
function returnUser (req, res, next) {
|
||||
debug(req.params.username);
|
||||
User.findOne(
|
||||
{ where: { 'username': req.params.username.toLowerCase() } },
|
||||
function(err, user) {
|
||||
if (err) {
|
||||
debug('Username err: ', err);
|
||||
return next(err);
|
||||
}
|
||||
debug(user);
|
||||
if (user) {
|
||||
user.progressTimestamps =
|
||||
user.progressTimestamps.sort(function(a, b) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"restApiRoot": "/api",
|
||||
"host": "0.0.0.0",
|
||||
"host": "127.0.0.1",
|
||||
"port": 3000,
|
||||
"legacyExplorer": false,
|
||||
"remoting": {
|
||||
|
@@ -1,5 +1,20 @@
|
||||
var globalConfig = require('../common/config.global');
|
||||
|
||||
module.exports = {
|
||||
restApiRoot: globalConfig.restApi
|
||||
};
|
||||
restApiRoot: globalConfig.restApi,
|
||||
sessionSecret: process.env.SESSION_SECRET,
|
||||
|
||||
trello: {
|
||||
key: process.env.TRELLO_KEY,
|
||||
secret: process.env.TRELLO_SECRET
|
||||
},
|
||||
|
||||
blogger: {
|
||||
key: process.env.BLOGGER_KEY
|
||||
},
|
||||
|
||||
github: {
|
||||
clientID: process.env.GITHUB_ID,
|
||||
clientSecret: process.env.GITHUB_SECRET
|
||||
}
|
||||
};
|
3
server/config.production.js
Normal file
3
server/config.production.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
host: process.env.HOST || 'localhost'
|
||||
};
|
@@ -96,6 +96,7 @@ app.use(function(req, res, next) {
|
||||
var trusted = [
|
||||
"'self'",
|
||||
'blob:',
|
||||
'104.236.218.15',
|
||||
'*.freecodecamp.com',
|
||||
'http://www.freecodecamp.com',
|
||||
'ws://freecodecamp.com/',
|
||||
|
@@ -16,7 +16,8 @@ var path = require('path'),
|
||||
*/
|
||||
var allFieldGuideIds, allFieldGuideNames, allNonprofitNames,
|
||||
challengeMap, challengeMapForDisplay, challengeMapWithIds,
|
||||
challengeMapWithNames, allChallengeIds, allChallenges;
|
||||
challengeMapWithNames, allChallengeIds, allChallenges,
|
||||
challengeMapWithDashedNames;
|
||||
|
||||
/**
|
||||
* GET /
|
||||
@@ -98,17 +99,6 @@ module.exports = {
|
||||
return allChallengeIds;
|
||||
},
|
||||
|
||||
allChallenges: function () {
|
||||
if (!allChallenges) {
|
||||
allChallenges = [];
|
||||
Object.keys(this.getChallengeMapWithNames()).forEach(function (key) {
|
||||
allChallenges.push(challengeMap[key].challenges);
|
||||
});
|
||||
allChallenges = R.flatten(allChallenges);
|
||||
}
|
||||
return allChallenges;
|
||||
},
|
||||
|
||||
getChallengeMapWithNames: function () {
|
||||
if (!challengeMapWithNames) {
|
||||
challengeMapWithNames = {};
|
||||
@@ -123,6 +113,20 @@ module.exports = {
|
||||
return challengeMapWithNames;
|
||||
},
|
||||
|
||||
getChallengeMapWithDashedNames: function() {
|
||||
if (!challengeMapWithDashedNames) {
|
||||
challengeMapWithDashedNames = {};
|
||||
Object.keys(challengeMap).
|
||||
forEach(function (key) {
|
||||
var onlyNames = challengeMap[key].challenges.map(function (elem) {
|
||||
return elem.dashedName;
|
||||
});
|
||||
challengeMapWithDashedNames[key] = onlyNames;
|
||||
});
|
||||
}
|
||||
return challengeMapWithDashedNames;
|
||||
},
|
||||
|
||||
|
||||
randomPhrase: function () {
|
||||
return resources.phrases[
|
||||
|
@@ -83,12 +83,12 @@ block content
|
||||
.col-xs-12
|
||||
ol
|
||||
for challenge in challengeBlock.challenges
|
||||
if completedChallengeList.indexOf(challenge.id) > -1
|
||||
if completedChallengeList.indexOf(challenge.id || challenge._id) > -1
|
||||
.row
|
||||
.hidden-xs.col-sm-3.col-md-2.text-primary.ion-checkmark-circled.padded-ionic-icon.text-center.large-p.negative-10
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.faded.large-p.negative-10
|
||||
a(href="/challenges/#{challenge.name}")= challenge.name
|
||||
a(href="/challenges/#{challenge.dashedName}")= challenge.name
|
||||
|
||||
else
|
||||
.row
|
||||
@@ -96,7 +96,7 @@ block content
|
||||
span.negative-10
|
||||
.col-xs-12.col-sm-9.col-md-10
|
||||
li.large-p.negative-10
|
||||
a(href="/challenges/#{challenge.name}")= challenge.name
|
||||
a(href="/challenges/#{challenge.dashedName}")= challenge.name
|
||||
|
||||
#announcementModal.modal(tabindex='-1')
|
||||
.modal-dialog.animated.fadeInUp.fast-animation
|
||||
|
Reference in New Issue
Block a user