Merge pull request #256 from terakilobyte/ux-improvements

User will now get a point for news/stories interactions
This commit is contained in:
Quincy Larson
2015-03-28 06:12:18 -07:00
8 changed files with 1131 additions and 1025 deletions

3
app.js
View File

@ -398,6 +398,8 @@ app.post(
app.all('/account', passportConf.isAuthenticated); app.all('/account', passportConf.isAuthenticated);
app.get('/account/api', userController.getAccountAngular); app.get('/account/api', userController.getAccountAngular);
app.get('/user/streak', userController.getStreak);
/** /**
* API routes * API routes
*/ */
@ -449,7 +451,6 @@ app.post('/account/password', userController.postUpdatePassword);
app.post('/account/delete', userController.postDeleteAccount); app.post('/account/delete', userController.postDeleteAccount);
app.get('/account/unlink/:provider', userController.getOauthUnlink); app.get('/account/unlink/:provider', userController.getOauthUnlink);
app.get('/sitemap.xml', resourcesController.sitemap); app.get('/sitemap.xml', resourcesController.sitemap);
/** /**
* OAuth sign-in routes. * OAuth sign-in routes.
*/ */

View File

@ -236,6 +236,7 @@ exports.completedBonfire = function (req, res) {
} else { } else {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash); var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) { if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0); req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1) req.user.uncompletedBonfires.splice(index, 1)
} }
@ -243,6 +244,7 @@ exports.completedBonfire = function (req, res) {
index = pairedWith.uncompletedBonfires.indexOf(bonfireHash); index = pairedWith.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) { if (index > -1) {
pairedWith.progressTimestamps.push(Date.now() || 0); pairedWith.progressTimestamps.push(Date.now() || 0);
pairedWith.uncompletedBonfires.splice(index, 1); pairedWith.uncompletedBonfires.splice(index, 1);
@ -285,6 +287,7 @@ exports.completedBonfire = function (req, res) {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash); var index = req.user.uncompletedBonfires.indexOf(bonfireHash);
if (index > -1) { if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0); req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1) req.user.uncompletedBonfires.splice(index, 1)
} }

View File

@ -3,7 +3,8 @@ var _ = require('lodash'),
Courseware = require('./../models/Courseware'), Courseware = require('./../models/Courseware'),
User = require('./../models/User'), User = require('./../models/User'),
resources = require('./resources'), resources = require('./resources'),
R = require('ramda'); R = require('ramda'),
moment = require('moment');
/** /**
* Courseware controller * Courseware controller
@ -253,20 +254,11 @@ exports.completedCourseware = function (req, res, next) {
var index = req.user.completedCoursewares.indexOf(coursewareHash); var index = req.user.completedCoursewares.indexOf(coursewareHash);
if (index === -1) { if (index === -1) {
req.user.progressTimestamps.push(Date.now() || 0); req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedCoursewares.splice(index, 1); req.user.uncompletedCoursewares.splice(index, 1);
} }
req.user.save(function (err, user) {
if (err) {
return next(err);
}
if (user) {
res.send(true);
}
});
};
exports.completedBasejump = function (req, res, next) { exports.completedBasejump = function (req, res, next) {
var isCompletedWith = req.body.bonfireInfo.completedWith || undefined; var isCompletedWith = req.body.bonfireInfo.completedWith || undefined;
var isCompletedDate = Math.round(+new Date()); var isCompletedDate = Math.round(+new Date());
@ -275,75 +267,93 @@ exports.completedBasejump = function (req, res, next) {
if(!solutionLink) { if(!solutionLink) {
// flash error and redirect // flash error and redirect
} }
if (user) {
res.send(true);
}
};
};
exports.completedZiplineOrBasejump = function (req, res, next) {
var isCompletedWith = req.body.bonfireInfo.completedWith || false;
var isCompletedDate = Math.round(+new Date());
var coursewareHash = req.body.coursewareInfo.coursewareHash;
var solutionLink = req.body.coursewareInfo.solutionLink;
if (!solutionLink) {
// flash error and redirect
return next(new Error('No solution provided'));
}
if (isCompletedWith) { if (isCompletedWith) {
var paired = User.find({"profile.username": isCompletedWith.toLowerCase()}).limit(1); var paired = User.find({'profile.username': isCompletedWith.toLowerCase()}).limit(1);
paired.exec(function (err, pairedWith) { paired.exec(function (err, pairedWith) {
if (err) { if (err) {
return err; return next(err);
} else { } else {
var index = req.user.uncompletedBonfires.indexOf(bonfireHash); var index = req.user.uncompletedCoursewares.indexOf(coursewareHash);
if (index > -1) { if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0); req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1) req.user.uncompletedCoursewares.splice(index, 1);
} }
pairedWith = pairedWith.pop(); pairedWith = pairedWith.pop();
index = pairedWith.uncompletedBonfires.indexOf(bonfireHash); index = pairedWith.uncompletedCoursewares.indexOf(coursewareHash);
if (index > -1) { if (index > -1) {
pairedWith.progressTimestamps.push(Date.now() || 0); pairedWith.progressTimestamps.push(Date.now() || 0);
pairedWith.uncompletedBonfires.splice(index, 1); pairedWith.uncompletedCoursewares.splice(index, 1);
} }
pairedWith.completedBonfires.push({ pairedWith.completedCoursewares.push({
_id: bonfireHash, _id: coursewareHash,
completedWith: req.user._id, completedWith: req.user._id,
completedDate: isCompletedDate, completedDate: isCompletedDate,
solution: isSolution solution: solutionLink
}); });
req.user.completedBonfires.push({ req.user.completedCoursewares.push({
_id: bonfireHash, _id: coursewareHash,
completedWith: pairedWith._id, completedWith: pairedWith._id,
completedDate: isCompletedDate, completedDate: isCompletedDate,
solution: isSolution solution: solutionLink
}); });
req.user.save(function (err, user) { req.user.save(function (err, user) {
if (err) {
return next(err);
}
pairedWith.save(function (err, paired) { pairedWith.save(function (err, paired) {
if (err) { if (err) {
throw err; return next(err);
} }
if (user && paired) { if (user && paired) {
res.send(true); return res.send(true);
} }
}) });
}); });
} }
}) });
} else { } else {
req.user.completedBonfires.push({ req.user.completedCoursewares.push({
_id: bonfireHash, _id: coursewareHash,
completedWith: null, completedWith: null,
completedDate: isCompletedDate, completedDate: isCompletedDate,
solution: isSolution solution: solutionLink
}); });
var index = req.user.uncompletedCourse.indexOf(bonfireHash); var index = req.user.uncompletedCourse.indexOf(coursewareHash);
if (index > -1) { if (index > -1) {
req.user.progressTimestamps.push(Date.now() || 0); req.user.progressTimestamps.push(Date.now() || 0);
req.user.uncompletedBonfires.splice(index, 1) req.user.uncompletedCoursewares.splice(index, 1);
} }
req.user.save(function (err, user) { req.user.save(function (err, user) {
if (err) { if (err) {
throw err; return next(err);
} }
if (user) { if (user) {
debug('Saving user'); debug('Saving user');
res.send(true) return res.send(true);
} }
}); });
} }

View File

@ -172,6 +172,7 @@ module.exports = {
var date2 = new Date(); var date2 = new Date();
var progressTimestamps = req.user.progressTimestamps; var progressTimestamps = req.user.progressTimestamps;
var now = Date.now() || 0; var now = Date.now() || 0;
if (req.user.pointsNeedMigration) { if (req.user.pointsNeedMigration) {
var challengesHash = req.user.challengesHash; var challengesHash = req.user.challengesHash;
for (var key in challengesHash) { for (var key in challengesHash) {
@ -180,23 +181,33 @@ module.exports = {
} }
} }
var timeStamps = []; var oldChallengeKeys = R.keys(req.user.challengesHash);
R.keys(req.user.challengesHash).forEach(function(key) {
"use strict"; var updatedTimesFromOldChallenges = oldChallengeKeys.map(function(timeStamp) {
var timeStamp = parseInt(challengesHash[key], 10); if (timeStamp.toString().length !== 13) {
timeStamps.push({timeStamp: timeStamp.length !== 13 ? (+timeStamp) : (+timeStamp * 1000)}); timeStamp *= 1000;
}
return timeStamp;
}); });
req.user.completedCoursewares = Array.zip(timeStamps, coursewares, var newTimeStamps = R.map(function(timeStamp) {
if (timeStamp.toString().length !== 13) {
timeStamp *= 1000;
}
return timeStamp;
}, req.user.progressTimestamps);
req.user.progressTimestamps = newTimeStamps;
req.user.completedCoursewares = Array.zip(updatedTimesFromOldChallenges, coursewares,
function(left, right) { function(left, right) {
"use strict";
return ({ return ({
completedDate: left.timeStamp, completedDate: left.timeStamp,
_id: right._id, _id: right._id,
name: right.name name: right.name
}); });
}).filter(function(elem) { }).filter(function(elem) {
"use strict";
return elem.completedDate !== 0; return elem.completedDate !== 0;
}); });
req.user.pointsNeedMigration = false; req.user.pointsNeedMigration = false;

View File

@ -1,3 +1,4 @@
/* eslint-disable no-catch-shadow, no-unused-vars */
var R = require('ramda'), var R = require('ramda'),
debug = require('debug')('freecc:cntr:story'), debug = require('debug')('freecc:cntr:story'),
Story = require('./../models/Story'), Story = require('./../models/Story'),
@ -24,11 +25,10 @@ function hotRank(timeValue, rank) {
} }
exports.hotJSON = function(req, res) { exports.hotJSON = function(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(1000); var story = Story.find({}).sort({'timePosted': -1}).limit(1000);
story.exec(function(err, stories) { story.exec(function(err, stories) {
if (err) { if (err) {
res.send(500);
return next(err); return next(err);
} }
@ -38,7 +38,8 @@ exports.hotJSON = function(req, res) {
return res.json(stories.map(function(elem) { return res.json(stories.map(function(elem) {
return elem; return elem;
}).sort(function(a, b) { }).sort(function(a, b) {
return hotRank(b.timePosted - foundationDate, b.rank, b.headline) - hotRank(a.timePosted - foundationDate, a.rank, a.headline); return hotRank(b.timePosted - foundationDate, b.rank, b.headline)
- hotRank(a.timePosted - foundationDate, a.rank, a.headline);
}).slice(0, sliceVal)); }).slice(0, sliceVal));
}); });
@ -48,36 +49,35 @@ exports.recentJSON = function(req, res, next) {
var story = Story.find({}).sort({'timePosted': -1}).limit(100); var story = Story.find({}).sort({'timePosted': -1}).limit(100);
story.exec(function(err, stories) { story.exec(function(err, stories) {
if (err) { if (err) {
res.status(500);
return next(err); return next(err);
} }
res.json(stories); return res.json(stories);
}); });
}; };
exports.hot = function(req, res) { exports.hot = function(req, res) {
res.render('stories/index', { return res.render('stories/index', {
title: 'Hot stories currently trending on Camper News', title: 'Hot stories currently trending on Camper News',
page: 'hot' page: 'hot'
}); });
}; };
exports.submitNew = function(req, res) { exports.submitNew = function(req, res) {
res.render('stories/index', { return res.render('stories/index', {
title: 'Submit a new story to Camper News', title: 'Submit a new story to Camper News',
page: 'submit' page: 'submit'
}); });
}; };
exports.search = function(req, res) { exports.search = function(req, res) {
res.render('stories/index', { return res.render('stories/index', {
title: 'Search the archives of Camper News', title: 'Search the archives of Camper News',
page: 'search' page: 'search'
}); });
}; };
exports.recent = function(req, res) { exports.recent = function(req, res) {
res.render('stories/index', { return res.render('stories/index', {
title: 'Recently submitted stories on Camper News', title: 'Recently submitted stories on Camper News',
page: 'recent' page: 'recent'
}); });
@ -104,7 +104,7 @@ exports.preSubmit = function(req, res) {
var image = data.image || ''; var image = data.image || '';
var description = data.description || ''; var description = data.description || '';
return res.render('stories/index', { return res.render('stories/index', {
title: "Confirm your Camper News story submission", title: 'Confirm your Camper News story submission',
page: 'storySubmission', page: 'storySubmission',
storyURL: data.url, storyURL: data.url,
storyTitle: title, storyTitle: title,
@ -121,7 +121,7 @@ exports.returnIndividualStory = function(req, res, next) {
Story.find({'storyLink': new RegExp(storyName, 'i')}, function(err, story) { Story.find({'storyLink': new RegExp(storyName, 'i')}, function(err, story) {
if (err) { if (err) {
next(err); return next(err);
} }
@ -143,7 +143,7 @@ exports.returnIndividualStory = function(req, res, next) {
try { try {
var votedObj = story.upVotes.filter(function(a) { var votedObj = story.upVotes.filter(function(a) {
return a['upVotedByUsername'] === req.user['profile']['username']; return a['upVotedByUsername'] === req.user['profile']['username'];
}) });
if (votedObj.length > 0) { if (votedObj.length > 0) {
userVoted = true; userVoted = true;
} }
@ -168,11 +168,14 @@ exports.returnIndividualStory = function(req, res, next) {
}); });
}; };
exports.getStories = function(req, res) { exports.getStories = function(req, res, next) {
MongoClient.connect(secrets.db, function(err, database) { MongoClient.connect(secrets.db, function(err, database) {
if (err) {
return next(err);
}
database.collection('stories').find({ database.collection('stories').find({
"$text": { '$text': {
"$search": req.body.data.searchValue '$search': req.body.data.searchValue
} }
}, { }, {
headline: 1, headline: 1,
@ -187,19 +190,22 @@ exports.getStories = function(req, res) {
storyLink: 1, storyLink: 1,
metaDescription: 1, metaDescription: 1,
textScore: { textScore: {
$meta: "textScore" $meta: 'textScore'
} }
}, { }, {
sort: { sort: {
textScore: { textScore: {
$meta: "textScore" $meta: 'textScore'
} }
} }
}).toArray(function(err, items) { }).toArray(function(err, items) {
if (err) {
return next(err);
}
if (items !== null && items.length !== 0) { if (items !== null && items.length !== 0) {
return res.json(items); return res.json(items);
} }
return res.status(404); return res.sendStatus(404);
}); });
}); });
}; };
@ -208,7 +214,6 @@ exports.upvote = function(req, res, next) {
var data = req.body.data; var data = req.body.data;
Story.find({'_id': data.id}, function(err, story) { Story.find({'_id': data.id}, function(err, story) {
if (err) { if (err) {
res.status(500);
return next(err); return next(err);
} }
story = story.pop(); story = story.pop();
@ -221,6 +226,15 @@ exports.upvote = function(req, res, next) {
); );
story.markModified('rank'); story.markModified('rank');
story.save(); story.save();
User.find({'_id': story.author.userId}, function(err, user) {
'use strict';
if (err) {
return next(err);
}
user = user.pop();
user.progressTimestamps.push(Date.now());
user.save();
});
return res.send(story); return res.send(story);
}); });
}; };
@ -229,7 +243,6 @@ exports.comments = function(req, res, next) {
var data = req.params.id; var data = req.params.id;
Comment.find({'_id': data}, function(err, comment) { Comment.find({'_id': data}, function(err, comment) {
if (err) { if (err) {
res.status(500);
return next(err); return next(err);
} }
comment = comment.pop(); comment = comment.pop();
@ -237,9 +250,9 @@ exports.comments = function(req, res, next) {
}); });
}; };
exports.newStory = function(req, res) { exports.newStory = function(req, res, next) {
if (!req.user) { if (!req.user) {
return res.status(500); return next(new Error('Must be logged in'));
} }
var url = req.body.data.url; var url = req.body.data.url;
var cleanURL = sanitizeHtml(url, { var cleanURL = sanitizeHtml(url, {
@ -261,7 +274,7 @@ exports.newStory = function(req, res) {
} }
Story.find({'link': url}, function(err, story) { Story.find({'link': url}, function(err, story) {
if (err) { if (err) {
return res.status(500); return next(err);
} }
if (story.length) { if (story.length) {
req.flash('errors', { req.flash('errors', {
@ -296,10 +309,10 @@ exports.newStory = function(req, res) {
} }
}; };
exports.storySubmission = function(req, res) { exports.storySubmission = function(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) { if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500); return next(new Error('Not authorized'));
} }
var storyLink = data.headline var storyLink = data.headline
.replace(/\'/g, '') .replace(/\'/g, '')
@ -332,9 +345,12 @@ exports.storySubmission = function(req, res) {
metaDescription: data.storyMetaDescription metaDescription: data.storyMetaDescription
}); });
req.user.progressTimestamps.push(Date.now());
req.user.save();
story.save(function(err) { story.save(function(err) {
if (err) { if (err) {
return res.status(500); return next(err);
} }
res.send(JSON.stringify({ res.send(JSON.stringify({
storyLink: story.storyLink.replace(/\s/g, '-').toLowerCase() storyLink: story.storyLink.replace(/\s/g, '-').toLowerCase()
@ -342,10 +358,10 @@ exports.storySubmission = function(req, res) {
}); });
}; };
exports.commentSubmit = function(req, res) { exports.commentSubmit = function(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) { if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500); return next(new Error('Not authorized'));
} }
var sanitizedBody = sanitizeHtml(data.body, var sanitizedBody = sanitizeHtml(data.body,
{ {
@ -368,14 +384,14 @@ exports.commentSubmit = function(req, res) {
topLevel: true, topLevel: true,
commentOn: Date.now() commentOn: Date.now()
}); });
commentSave(comment, Story, res); commentSave(comment, Story, res, next);
}; };
exports.commentOnCommentSubmit = function(req, res) { exports.commentOnCommentSubmit = function(req, res, next) {
var data = req.body.data; var data = req.body.data;
if (req.user._id.toString() !== data.author.userId.toString()) { if (req.user._id.toString() !== data.author.userId.toString()) {
return res.status(500); return next(new Error('Not authorized'));
} }
var sanitizedBody = sanitizeHtml(data.body, var sanitizedBody = sanitizeHtml(data.body,
@ -399,25 +415,25 @@ exports.commentOnCommentSubmit = function(req, res) {
topLevel: false, topLevel: false,
commentOn: Date.now() commentOn: Date.now()
}); });
commentSave(comment, Comment, res); commentSave(comment, Comment, res, next);
}; };
function commentSave(comment, Context, res) { function commentSave(comment, Context, res, next) {
comment.save(function(err, data) { comment.save(function(err, data) {
if (err) { if (err) {
return res.status(500); return next(err);
} }
try { try {
Context.find({'_id': comment.associatedPost}, function (err, associatedStory) { Context.find({'_id': comment.associatedPost}, function (err, associatedStory) {
if (err) { if (err) {
return res.status(500); return next(err);
} }
associatedStory = associatedStory.pop(); associatedStory = associatedStory.pop();
if (associatedStory) { if (associatedStory) {
associatedStory.comments.push(data._id); associatedStory.comments.push(data._id);
associatedStory.save(function (err) { associatedStory.save(function (err) {
if (err) { if (err) {
res.status(500); return next(err);
} }
res.send(true); res.send(true);
}); });
@ -425,7 +441,7 @@ function commentSave(comment, Context, res) {
}); });
} catch (e) { } catch (e) {
// delete comment // delete comment
return res.status(500); return next(err);
} }
}); });
} }

View File

@ -6,9 +6,9 @@ var _ = require('lodash'),
User = require('../models/User'), User = require('../models/User'),
secrets = require('../config/secrets'), secrets = require('../config/secrets'),
moment = require('moment'), moment = require('moment'),
Challenge = require('./../models/Challenge'),
debug = require('debug')('freecc:cntr:challenges'), debug = require('debug')('freecc:cntr:challenges'),
resources = require('./resources'); resources = require('./resources'),
R = require('ramda');
@ -18,7 +18,9 @@ var _ = require('lodash'),
*/ */
exports.getSignin = function(req, res) { exports.getSignin = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) {
return res.redirect('/');
}
res.render('account/signin', { res.render('account/signin', {
title: 'Free Code Camp Login' title: 'Free Code Camp Login'
}); });
@ -41,13 +43,17 @@ exports.postSignin = function(req, res, next) {
} }
passport.authenticate('local', function(err, user, info) { passport.authenticate('local', function(err, user, info) {
if (err) return next(err); if (err) {
return next(err);
}
if (!user) { if (!user) {
req.flash('errors', { msg: info.message }); req.flash('errors', { msg: info.message });
return res.redirect('/signin'); return res.redirect('/signin');
} }
req.logIn(user, function(err) { req.logIn(user, function(err) {
if (err) return next(err); if (err) {
return next(err);
}
req.flash('success', { msg: 'Success! You are logged in.' }); req.flash('success', { msg: 'Success! You are logged in.' });
res.redirect(req.session.returnTo || '/'); res.redirect(req.session.returnTo || '/');
}); });
@ -70,7 +76,9 @@ exports.signout = function(req, res) {
*/ */
exports.getEmailSignin = function(req, res) { exports.getEmailSignin = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) {
return res.redirect('/');
}
res.render('account/email-signin', { res.render('account/email-signin', {
title: 'Sign in to your Free Code Camp Account' title: 'Sign in to your Free Code Camp Account'
}); });
@ -82,7 +90,9 @@ exports.getEmailSignin = function(req, res) {
*/ */
exports.getEmailSignup = function(req, res) { exports.getEmailSignup = function(req, res) {
if (req.user) return res.redirect('/'); if (req.user) {
return res.redirect('/');
}
res.render('account/email-signup', { res.render('account/email-signup', {
title: 'Create Your Free Code Camp Account' title: 'Create Your Free Code Camp Account'
}); });
@ -174,7 +184,7 @@ exports.postEmailSignup = function(req, res, next) {
'Greetings from San Francisco!\n\n', 'Greetings from San Francisco!\n\n',
'Thank you for joining our community.\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', '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", 'And if you have a moment, check out our blog: blog.freecodecamp.com.\n',
'Good luck with the challenges!\n\n', 'Good luck with the challenges!\n\n',
'- the Volunteer Camp Counselor Team' '- the Volunteer Camp Counselor Team'
].join('') ].join('')
@ -190,10 +200,45 @@ exports.postEmailSignup = function(req, res, next) {
* For Calendar display * For Calendar display
*/ */
exports.getStreak = function(req, res) { exports.getStreak = function(req, res, next) {
var completedStreak = req.user.challengesHash;
req.user.progressTimestamps = req.user.progressTimestamps.sort(function(a, b) {
return a - b;
});
var timeObject = Object.create(null);
R.forEach(function(time) {
timeObject[moment(time).format('YYYY-MM-DD')] = time;
}, req.user.progressTimestamps);
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()) {
tmpLongest++;
if (tmpLongest > req.user.currentStreak) {
req.user.currentStreak = tmpLongest;
} }
if ( req.user.currentStreak > req.user.longestStreak) {
req.user.longestStreak = req.user.currentStreak;
}
}
}
req.user.save(function(err) {
if (err) {
return next(err);
}
});
s
var payload = {
longest: req.user.longestStreak,
timeObject: timeObject
};
return res.send(payload);
};
/** /**
* GET /account * GET /account
@ -272,7 +317,7 @@ exports.returnUser = function(req, res, next) {
var data = {}; var data = {};
var progressTimestamps = user.progressTimestamps; var progressTimestamps = user.progressTimestamps;
for (var i = 0; i < progressTimestamps.length; i++) { for (var i = 0; i < progressTimestamps.length; i++) {
data[progressTimestamps[i].toString()] = 1; data[(progressTimestamps[i] / 1000).toString()] = 1;
} }
res.render('account/show', { res.render('account/show', {

View File

@ -1,7 +1,9 @@
var bcrypt = require('bcrypt-nodejs'); var bcrypt = require('bcrypt-nodejs');
var crypto = require('crypto'); var crypto = require('crypto');
var mongoose = require('mongoose'); var mongoose = require('mongoose');
require('mongoose-long')(mongoose);
var Long = mongoose.Types.Long;
var userSchema = new mongoose.Schema({ var userSchema = new mongoose.Schema({
email: { email: {
type: String, type: String,
@ -21,7 +23,7 @@ var userSchema = new mongoose.Schema({
type: Number, type: Number,
default: 0 default: 0
}, },
progressTimestamps: { type: Array, default: [Date] }, progressTimestamps: [],
challengesCompleted: { type: Array, default: [] }, challengesCompleted: { type: Array, default: [] },
pointsNeedMigration: { type: Boolean, default: true }, pointsNeedMigration: { type: Boolean, default: true },
challengesHash: { challengesHash: {
@ -332,9 +334,30 @@ var userSchema = new mongoose.Schema({
resetPasswordToken: String, resetPasswordToken: String,
resetPasswordExpires: Date, resetPasswordExpires: Date,
uncompletedBonfires: Array, uncompletedBonfires: Array,
completedBonfires: Array, completedBonfires: [
{
_id: String,
completedWith: String,
completedDate: Long,
solution: String
}
],
uncompletedCoursewares: Array, uncompletedCoursewares: Array,
completedCoursewares: Array completedCoursewares: [
{
completedDate: Long,
_id: String,
name: String
}
],
currentStreak: {
type: Number,
default: 0
},
longestStreak: {
type: Number,
default: 0
}
}); });
/** /**

View File

@ -47,11 +47,9 @@
"method-override": "^2.3.0", "method-override": "^2.3.0",
"moment": "^2.8.4", "moment": "^2.8.4",
"mongodb": "^1.4.33", "mongodb": "^1.4.33",
"mongoose": "^3.8.19", "mongoose": "^4.0.0",
"mongoose-text-search": "0.0.2",
"morgan": "^1.5.0", "morgan": "^1.5.0",
"newrelic": "^1.13.3", "newrelic": "^1.13.3",
"node": "0.0.0",
"nodemailer": "^1.3.0", "nodemailer": "^1.3.0",
"passport": "^0.2.1", "passport": "^0.2.1",
"passport-facebook": "^1.0.3", "passport-facebook": "^1.0.3",
@ -76,7 +74,6 @@
"chai": "^1.10.0", "chai": "^1.10.0",
"gulp": "^3.8.8", "gulp": "^3.8.8",
"gulp-inject": "^1.0.2", "gulp-inject": "^1.0.2",
"gulp-minify-css": "^0.5.1",
"gulp-nodemon": "^1.0.4", "gulp-nodemon": "^1.0.4",
"mocha": "^2.0.1", "mocha": "^2.0.1",
"multiline": "^1.0.1", "multiline": "^1.0.1",