Merge pull request #359 from terakilobyte/staging

Site speed
This commit is contained in:
Nathan
2015-04-24 19:02:16 -04:00
8 changed files with 277 additions and 190 deletions

18
app.js
View File

@ -253,12 +253,8 @@ app.use(express.static(__dirname + '/public', { maxAge: 86400000 }));
app.get('/', homeController.index);
app.get('/privacy', function(req, res) {
res.redirect(301, "/field-guide/free-code-camp's-privacy-policy");
});
app.get('/nonprofit-project-instructions', function(req, res) {
res.redirect(301, "/field-guide/free-code-camp's-privacy-policy");
res.redirect(301, '/field-guide/nonprofit-project-instructions');
});
app.get('/chat', resourcesController.chat);
@ -384,17 +380,17 @@ app.post(
passportConf.isAuthenticated,
contactController.postDoneWithFirst100Hours
);
//app.get(
// '/nonprofit-project-instructions',
// passportConf.isAuthenticated,
// resourcesController.nonprofitProjectInstructions
//);
app.post(
'/update-progress',
passportConf.isAuthenticated,
userController.updateProgress
);
app.get('/privacy', function(req, res) {
res.redirect(301, '/field-guide/the-free-code-camp-privacy-policy');
});
app.get('/api/slack', function(req, res) {
if (req.user) {
if (req.user.email) {
@ -590,7 +586,7 @@ app.post('/completed-bonfire/', bonfireController.completedBonfire);
app.get('/field-guide/:fieldGuideName', fieldGuideController.returnIndividualFieldGuide);
app.get('/field-guide', fieldGuideController.returnNextFieldGuide);
app.get('/field-guide/', fieldGuideController.returnNextFieldGuide);
app.post('/completed-field-guide/', fieldGuideController.completedFieldGuide);

View File

@ -63,12 +63,12 @@ exports.returnNextBonfire = function(req, res, next) {
var uncompletedBonfires = req.user.uncompletedBonfires;
var displayedBonfires = Bonfire.find({'_id': uncompletedBonfires[0]});
displayedBonfires.exec(function(err, bonfire) {
displayedBonfires.exec(function(err, bonfireFromMongo) {
if (err) {
return next(err);
}
bonfire = bonfire.pop();
if (bonfire === undefined) {
var bonfire = bonfireFromMongo.pop();
if (typeof bonfire === 'undefined') {
req.flash('errors', {
msg: "It looks like you've completed all the bonfires we have available. Good job!"
});
@ -84,13 +84,13 @@ exports.returnIndividualBonfire = function(req, res, next) {
var bonfireName = dashedName.replace(/\-/g, ' ');
Bonfire.find({'name': new RegExp(bonfireName, 'i')}, function(err, bonfire) {
Bonfire.find({'name': new RegExp(bonfireName, 'i')}, function(err, bonfireFromMongo) {
if (err) {
next(err);
}
if (bonfire.length < 1) {
if (bonfireFromMongo.length < 1) {
req.flash('errors', {
msg: "404: We couldn't find a bonfire with that name. Please double check the name."
});
@ -98,9 +98,9 @@ exports.returnIndividualBonfire = function(req, res, next) {
return res.redirect('/bonfires');
}
bonfire = bonfire.pop();
var bonfire = bonfireFromMongo.pop();
var dashedNameFull = bonfire.name.toLowerCase().replace(/\s/g, '-');
if (dashedNameFull != dashedName) {
if (dashedNameFull !== dashedName) {
return res.redirect('../bonfires/' + dashedNameFull);
}
res.render('bonfire/show', {

View File

@ -50,14 +50,14 @@ exports.returnNextCourseware = function(req, res, next) {
}
courseware = courseware.pop();
if (courseware === undefined) {
if (typeof courseware === 'undefined') {
req.flash('errors', {
msg: "It looks like you've completed all the courses we have " +
"available. Good job!"
});
return res.redirect('../challenges/learn-how-free-code-camp-works');
}
nameString = courseware.name.toLowerCase().replace(/\s/g, '-');
var nameString = courseware.name.toLowerCase().replace(/\s/g, '-');
return res.redirect('../challenges/' + nameString);
});
};
@ -68,23 +68,23 @@ exports.returnIndividualCourseware = function(req, res, next) {
var coursewareName = dashedName.replace(/\-/g, ' ');
Courseware.find({'name': new RegExp(coursewareName, 'i')},
function(err, courseware) {
function(err, coursewareFromMongo) {
if (err) {
next(err);
}
// Handle not found
if (courseware.length < 1) {
if (coursewareFromMongo.length < 1) {
req.flash('errors', {
msg: "404: We couldn't find a challenge with that name. " +
"Please double check the name."
});
return res.redirect('/challenges');
}
courseware = courseware.pop();
var courseware = coursewareFromMongo.pop();
// Redirect to full name if the user only entered a partial
var dashedNameFull = courseware.name.toLowerCase().replace(/\s/g, '-');
if (dashedNameFull != dashedName) {
if (dashedNameFull !== dashedName) {
return res.redirect('../challenges/' + dashedNameFull);
}
@ -292,7 +292,7 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
if (isCompletedWith) {
var paired = User.find({'profile.username': isCompletedWith.toLowerCase()}).limit(1);
paired.exec(function (err, pairedWith) {
paired.exec(function (err, pairedWithFromMongo) {
if (err) {
return next(err);
} else {
@ -301,7 +301,7 @@ exports.completedZiplineOrBasejump = function (req, res, next) {
req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedCoursewares.splice(index, 1);
}
pairedWith = pairedWith.pop();
var pairedWith = pairedWithFromMongo.pop();
req.user.completedCoursewares.push({
_id: coursewareHash,

View File

@ -9,12 +9,12 @@ exports.returnIndividualFieldGuide = function(req, res, next) {
var fieldGuideName = dashedName.replace(/\-/g, ' ');
FieldGuide.find({'name': new RegExp(fieldGuideName, 'i')}, function(err, fieldGuide) {
FieldGuide.find({'name': new RegExp(fieldGuideName, 'i')}, function(err, fieldGuideFromMongo) {
if (err) {
next(err);
}
if (fieldGuide.length < 1) {
if (fieldGuideFromMongo.length < 1) {
req.flash('errors', {
msg: "404: We couldn't find a field guide entry with that name. Please double check the name."
});
@ -22,9 +22,9 @@ exports.returnIndividualFieldGuide = function(req, res, next) {
return res.redirect('/field-guide');
}
fieldGuide = fieldGuide.pop();
var fieldGuide = fieldGuideFromMongo.pop();
var dashedNameFull = fieldGuide.name.toLowerCase().replace(/\s/g, '-').replace(/\?/g, '');
if (dashedNameFull != dashedName) {
if (dashedNameFull !== dashedName) {
return res.redirect('../field-guide/' + dashedNameFull);
}
res.render('field-guide/show', {
@ -42,7 +42,7 @@ exports.showAllFieldGuides = function(req, res) {
if (req.user && req.user.completedFieldGuides) {
data.completedFieldGuides = req.user.completedFieldGuides;
} else {
data.completedFieldGuides = []
data.completedFieldGuides = [];
}
res.send(data);
};
@ -69,7 +69,7 @@ exports.returnNextFieldGuide = function(req, res, next) {
return next(err);
}
fieldGuide = fieldGuide.pop();
if (fieldGuide === undefined) {
if (typeof fieldGuide === 'undefined') {
req.flash('success', {
msg: "You've read all our current Field Guide entries. You can contribute to our Field Guide <a href='https://github.com/FreeCodeCamp/freecodecamp/blob/master/seed_data/field-guides.json'>here</a>."
});

View File

@ -8,7 +8,6 @@ var async = require('async'),
Nonprofit = require('./../models/Nonprofit'),
Comment = require('./../models/Comment'),
resources = require('./resources.json'),
steps = resources.steps,
secrets = require('./../config/secrets'),
bonfires = require('../seed_data/bonfires.json'),
nonprofits = require('../seed_data/nonprofits.json'),
@ -21,6 +20,12 @@ var async = require('async'),
request = require('request'),
R = require('ramda');
/**
* Cached values
*/
var allBonfireIds, allBonfireNames, allCoursewareIds, allCoursewareNames,
allFieldGuideIds, allFieldGuideNames, allNonprofitNames;
/**
* GET /
* Resources.
@ -38,63 +43,106 @@ Array.zip = function(left, right, combinerFunction) {
};
module.exports = {
privacy: function privacy(req, res) {
res.render('resources/privacy', {
title: 'Privacy'
});
},
sitemap: function sitemap(req, res, next) {
var appUrl = 'http://www.freecodecamp.com';
var now = moment(new Date()).format('YYYY-MM-DD');
User.find({'profile.username': {'$ne': '' }}, function(err, users) {
if (err) {
debug('User err: ', err);
return next(err);
}
Courseware.find({}, function (err, challenges) {
if (err) {
debug('User err: ', err);
return next(err);
}
Bonfire.find({}, function (err, bonfires) {
if (err) {
debug('User err: ', err);
return next(err);
}
Story.find({}, function (err, stories) {
if (err) {
debug('User err: ', err);
return next(err);
}
Nonprofit.find({}, function (err, nonprofits) {
async.parallel({
users: function(callback) {
User.aggregate()
.group({_id: 1, usernames: { $addToSet: '$profile.username'}})
.match({'profile.username': { $ne: ''}})
.exec(function(err, users) {
if (err) {
debug('User err: ', err);
return next(err);
callback(err);
} else {
callback(null, users[0].usernames);
}
FieldGuide.find({}, function (err, fieldGuides) {
if (err) {
debug('User err: ', err);
return next(err);
}
res.header('Content-Type', 'application/xml');
res.render('resources/sitemap', {
appUrl: appUrl,
now: now,
users: users,
challenges: challenges,
bonfires: bonfires,
stories: stories,
nonprofits: nonprofits,
fieldGuides: fieldGuides
});
});
});
},
challenges: function (callback) {
Courseware.aggregate()
.group({_id: 1, names: { $addToSet: '$name'}})
.exec(function (err, challenges) {
if (err) {
debug('Courseware err: ', err);
callback(err);
} else {
callback(null, challenges[0].names);
}
});
},
bonfires: function (callback) {
Bonfire.aggregate()
.group({_id: 1, names: { $addToSet: '$name'}})
.exec(function (err, bonfires) {
if (err) {
debug('Bonfire err: ', err);
callback(err);
} else {
callback(null, bonfires[0].names);
}
});
});
});
});
},
stories: function (callback) {
Story.aggregate()
.group({_id: 1, links: {$addToSet: '$link'}})
.exec(function (err, stories) {
if (err) {
debug('Story err: ', err);
callback(err);
} else {
callback(null, stories[0].links);
}
});
},
nonprofits: function (callback) {
Nonprofit.aggregate()
.group({_id: 1, names: { $addToSet: '$name'}})
.exec(function (err, nonprofits) {
if (err) {
debug('User err: ', err);
callback(err);
} else {
callback(null, nonprofits[0].names);
}
});
},
fieldGuides: function (callback) {
FieldGuide.aggregate()
.group({_id: 1, names: { $addToSet: '$name'}})
.exec(function (err, fieldGuides) {
if (err) {
debug('User err: ', err);
callback(err);
} else {
callback(null, fieldGuides[0].names);
}
});
}
}, function (err, results) {
if (err) {
return next(err);
} else {
setTimeout(function() {
res.header('Content-Type', 'application/xml');
res.render('resources/sitemap', {
appUrl: appUrl,
now: now,
users: results.users,
challenges: results.challenges,
bonfires: results.bonfires,
stories: results.stories,
nonprofits: results.nonprofits,
fieldGuides: results.fieldGuides
});
}, 0);
}
}
);
},
chat: function chat(req, res) {
@ -161,132 +209,165 @@ module.exports = {
debug('User err: ', err);
return next(err);
}
User.count({'points': {'$gt': 53}}, function (err, all) {
if (err) {
debug('User err: ', err);
return next(err);
}
res.render('resources/learn-to-code', {
title: 'About Free Code Camp',
daysRunning: daysRunning,
c3: numberWithCommas(c3),
announcements: announcements
});
res.render('resources/learn-to-code', {
title: 'About Free Code Camp',
daysRunning: daysRunning,
c3: numberWithCommas(c3),
announcements: announcements
});
});
},
randomPhrase: function() {
var phrases = resources.phrases;
return phrases[Math.floor(Math.random() * phrases.length)];
return resources.phrases[Math.floor(
Math.random() * resources.phrases.length)];
},
randomVerb: function() {
var verbs = resources.verbs;
return verbs[Math.floor(Math.random() * verbs.length)];
return resources.verbs[Math.floor(
Math.random() * resources.verbs.length)];
},
randomCompliment: function() {
var compliments = resources.compliments;
return compliments[Math.floor(Math.random() * compliments.length)];
return resources.compliments[Math.floor(
Math.random() * resources.compliments.length)];
},
allBonfireIds: function() {
return bonfires.map(function(elem) {
return {
_id: elem._id,
difficulty: elem.difficulty
}
})
.sort(function(a, b) {
return a.difficulty - b.difficulty;
})
.map(function(elem) {
return elem._id;
});
if (allBonfireIds) {
return allBonfireIds;
} else {
allBonfireIds = bonfires.
map(function (elem) {
return {
_id: elem._id,
difficulty: elem.difficulty
};
}).
sort(function (a, b) {
return a.difficulty - b.difficulty;
}).
map(function (elem) {
return elem._id;
});
return allBonfireIds;
}
},
allFieldGuideIds: function() {
return fieldGuides.map(function(elem) {
return {
_id: elem._id,
}
})
.map(function(elem) {
return elem._id;
});
if (allFieldGuideIds) {
return allFieldGuideIds;
} else {
allFieldGuideIds = fieldGuides.
map(function (elem) {
return {
_id: elem._id
};
});
return allFieldGuideIds;
}
},
allBonfireNames: function() {
return bonfires.map(function(elem) {
return {
name: elem.name,
difficulty: elem.difficulty,
_id: elem._id
}
})
.sort(function(a, b) {
return a.difficulty - b.difficulty;
})
.map (function(elem) {
return {
name : elem.name,
_id: elem._id
}
});
if (allBonfireNames) {
return allBonfireNames;
} else {
allBonfireNames = bonfires.
map(function (elem) {
return {
name: elem.name,
difficulty: elem.difficulty,
_id: elem._id
};
}).
sort(function (a, b) {
return a.difficulty - b.difficulty;
}).
map(function (elem) {
return {
name: elem.name,
_id: elem._id
};
});
return allBonfireNames;
}
},
allFieldGuideNames: function() {
return fieldGuides.map(function(elem) {
return {
name: elem.name
}
})
if (allFieldGuideNames) {
return allFieldGuideNames;
} else {
allFieldGuideNames = fieldGuides.
map(function (elem) {
return {
name: elem.name
};
});
return allFieldGuideNames;
}
},
allNonprofitNames: function() {
return nonprofits.map(function(elem) {
return {
name: elem.name
}
})
if (allNonprofitNames) {
return allNonprofitNames;
} else {
allNonprofitNames = nonprofits.
map(function (elem) {
return {
name: elem.name
};
});
return allNonprofitNames;
}
},
allCoursewareIds: function() {
return coursewares.map(function(elem) {
return {
_id: elem._id,
difficulty: elem.difficulty
};
})
.sort(function(a, b) {
return a.difficulty - b.difficulty;
})
.map(function(elem) {
return elem._id;
});
if (allCoursewareIds) {
return allCoursewareIds;
} else {
allCoursewareIds = coursewares.
map(function (elem) {
return {
_id: elem._id,
difficulty: elem.difficulty
};
}).
sort(function (a, b) {
return a.difficulty - b.difficulty;
}).
map(function (elem) {
return elem._id;
});
return allCoursewareIds;
}
},
allCoursewareNames: function() {
return coursewares.map(function(elem) {
return {
name: elem.name,
difficulty: elem.difficulty,
challengeType: elem.challengeType,
_id: elem._id
};
})
.sort(function(a, b) {
return a.difficulty - b.difficulty;
})
.map (function(elem) {
return {
name: elem.name,
challengeType: elem.challengeType,
_id: elem._id
};
});
if (allCoursewareNames) {
return allCoursewareNames;
} else {
allCoursewareNames = coursewares.
map(function (elem) {
return {
name: elem.name,
difficulty: elem.difficulty,
challengeType: elem.challengeType,
_id: elem._id
};
}).
sort(function (a, b) {
return a.difficulty - b.difficulty;
}).
map(function (elem) {
return {
name: elem.name,
challengeType: elem.challengeType,
_id: elem._id
};
});
return allCoursewareNames;
}
},
whichEnvironment: function() {
@ -302,8 +383,9 @@ module.exports = {
var metaDescription = $("meta[name='description']");
var metaImage = $("meta[property='og:image']");
var urlImage = metaImage.attr('content') ? metaImage.attr('content') : '';
var metaTitle = $('title');
var description = metaDescription.attr('content') ? metaDescription.attr('content') : '';
result.title = $('title').text().length < 141 ? $('title').text() : $('title').text().slice(0, 137) + " ...";
result.title = metaTitle.text().length < 141 ? metaTitle.text() : metaTitle.text().slice(0, 137) + " ...";
result.image = urlImage;
result.description = description;
callback(null, result);
@ -360,7 +442,9 @@ module.exports = {
});
}, foundStories);
async.parallel(tasks, function(err) {
if (err) { return cb(err); }
if (err) {
return cb(err);
}
cb();
});
}

View File

@ -253,7 +253,7 @@ exports.checkExistingUsername = function(req, res, next) {
exports.checkUniqueEmail = function(req, res, next) {
User.count({'email': decodeURIComponent(req.params.email).toLowerCase()}, function (err, data) {
if (err) { return next(err); }
if (data == 1) {
if (data === 1) {
return res.send(true);
} else {
return res.send(false);
@ -271,7 +271,7 @@ exports.returnUser = function(req, res, next) {
User.find({'profile.username': req.params.username.toLowerCase()}, function(err, user) {
if (err) { debug('Username err: ', err); next(err); }
if (user[0]) {
var user = user[0];
user = user[0];
user.progressTimestamps = user.progressTimestamps.sort(function(a, b) {
return a - b;
@ -284,6 +284,7 @@ exports.returnUser = function(req, res, next) {
var tmpLongest = 1;
var timeKeys = R.keys(timeObject);
for (var i = 1; i <= timeKeys.length; i++) {
if (moment(timeKeys[i - 1]).add(1, 'd').toString()
=== moment(timeKeys[i]).toString()) {
@ -305,13 +306,17 @@ exports.returnUser = function(req, res, next) {
var data = {};
var progressTimestamps = user.progressTimestamps;
for (var i = 0; i < progressTimestamps.length; i++) {
data[(progressTimestamps[i] / 1000).toString()] = 1;
}
progressTimestamps.forEach(function(timeStamp) {
data[(timeStamp / 1000)] = 1;
});
//for (var i = 0; i < progressTimestamps.length; i++) {
// data[(progressTimestamps[i] / 1000).toString()] = 1;
//}
user.currentStreak = user.currentStreak || 1;
user.longestStreak = user.longestStreak || 1;
challenges = user.completedCoursewares.filter(function ( obj ) {
var challenges = user.completedCoursewares.filter(function ( obj ) {
return !!obj.solution;
});
res.render('account/show', {

View File

@ -644,7 +644,8 @@
"difficulty": "3.12",
"description": [
"Fill in the object constructor with the methods specified in the tests.",
"Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(), setLastName(), and setFullName().",
"Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).",
"All functions that take an argument have an arity of 1, and the argument will be a string.",
"These methods must be the only available means for interacting with the object."
],
"challengeSeed": "var Person = function(firstAndLast) {\n return firstAndLast;\r\n};\n\nvar bob = new Person('Bob Ross');\nbob.getFullName();",

View File

@ -32,18 +32,19 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
changefreq daily
priority= 0.8
//- Users
//- User
each user in users
url
loc #{appUrl}/#{user.profile.username}
loc #{appUrl}/#{user}
lastmod= now
changefreq daily
priority= 0.9
//- Products
each bonfire in bonfires
url
loc #{appUrl}/bonfires/#{bonfire.name.replace(/\s/g, '-')}
loc #{appUrl}/bonfires/#{bonfire.replace(/\s/g, '-')}
lastmod= now
changefreq weekly
priority= 0.5
@ -51,7 +52,7 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
//- Challenges
each challenge in challenges
url
loc #{appUrl}/challenges/#{challenge.name.replace(/\s/g, '-')}
loc #{appUrl}/challenges/#{challenge.replace(/\s/g, '-')}
lastmod= now
changefreq weekly
priority= 0.5
@ -59,7 +60,7 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
//- Stories
each story in stories
url
loc #{appUrl}/stories/#{story.storyLink.replace(/\s/g, '-')}
loc #{appUrl}/stories/#{story.replace(/\s/g, '-')}
lastmod= now
changefreq daily
priority= 0.9
@ -67,7 +68,7 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
//- Nonprofit
each nonprofit in nonprofits
url
loc #{appUrl}/nonprofits/#{nonprofit.name.replace(/\s/g, '-')}
loc #{appUrl}/nonprofits/#{nonprofit.replace(/\s/g, '-')}
lastmod= now
changefreq daily
priority= 0.9
@ -75,7 +76,7 @@ urlset(xmlns="http://www.sitemaps.org/schemas/sitemap/0.9")
//- Nonprofit
each fieldGuide in fieldGuides
url
loc #{appUrl}/field-guide/#{fieldGuide.name.replace(/\s/g, '-')}
loc #{appUrl}/field-guide/#{fieldGuide.replace(/\s/g, '-')}
lastmod= now
changefreq daily
priority= 0.9