From 8a0341a7aca3c14874cee946153a4c580a06568c Mon Sep 17 00:00:00 2001 From: Berkeley Martinez Date: Tue, 19 Jan 2016 22:30:01 -0800 Subject: [PATCH] Fix zipline/basejump completed endpoint This PR refactors and normalizes the endpoint and the ajax request. Some weird bug keeps popping up on the server, but keymetrics has decided to take a crap and not actually report back with the error I don't know what exactly is causing it. Normally I don't like fixing something I can't see, but I'm getting a constant flood of emails because of some obscure bug here. We removed the `completedWith` functionality a while back so that was removed from this endpoint and the ajax call. To test, verify that you can complete both a zipline/basejump. Also show last updated date since it is possible a user might want to update links --- client/commonFramework/bindings.js | 22 +++--- server/boot/challenge.js | 119 +++++++++++------------------ server/views/account/show.jade | 12 +-- 3 files changed, 59 insertions(+), 94 deletions(-) diff --git a/client/commonFramework/bindings.js b/client/commonFramework/bindings.js index fe96d0ec62..009bae4088 100644 --- a/client/commonFramework/bindings.js +++ b/client/commonFramework/bindings.js @@ -74,14 +74,14 @@ window.common = (function(global) { $('#next-courseware-button').unbind('click'); if ($('.signup-btn-nav').length < 1) { var data; - var completedWith = $('#completed-with').val() || null; - var publicURL = $('#public-url').val() || null; - var githubURL = $('#github-url').val() || null; + var solution = $('#public-url').val() || null; + var githubLink = $('#github-url').val() || null; switch (common.challengeType) { case common.challengeTypes.VIDEO: data = { id: common.challengeId, - name: common.challengeName + name: common.challengeName, + challengeType: common.challengeType }; $.post('/completed-challenge/', data) .success(function(res) { @@ -99,15 +99,11 @@ window.common = (function(global) { case common.challengeTypes.BASEJUMP: case common.challengeTypes.ZIPLINE: data = { - challengeInfo: { - challengeId: common.challengeId, - challengeName: common.challengeName, - completedWith: completedWith, - publicURL: publicURL, - githubURL: githubURL, - challengeType: common.challengeType, - verified: false - } + id: common.challengeId, + name: common.challengeName, + challengeType: +common.challengeType, + solution, + githubLink }; $.post('/completed-zipline-or-basejump/', data) diff --git a/server/boot/challenge.js b/server/boot/challenge.js index 0c3c1e0b37..df0ad21d8a 100644 --- a/server/boot/challenge.js +++ b/server/boot/challenge.js @@ -2,7 +2,6 @@ import _ from 'lodash'; import dedent from 'dedent'; import moment from 'moment'; import { Observable, Scheduler } from 'rx'; -import assign from 'object.assign'; import debugFactory from 'debug'; import accepts from 'accepts'; @@ -15,11 +14,7 @@ import { randomCompliment } from '../utils'; -import { - saveUser, - observeMethod, - observeQuery -} from '../utils/rx'; +import { saveUser, observeMethod } from '../utils/rx'; import { ifNoUserSend @@ -384,7 +379,6 @@ module.exports = function(app) { .map(challenge => challenge.toJSON()) .shareReplay(); - const User = app.models.User; const send200toNonUser = ifNoUserSend(true); router.post( @@ -506,7 +500,7 @@ module.exports = function(app) { function completedChallenge(req, res, next) { const type = accepts(req).type('html', 'json', 'text'); - const completedDate = Math.round(+new Date()); + const completedDate = Date.now(); const { id, name, @@ -547,21 +541,46 @@ module.exports = function(app) { } function completedZiplineOrBasejump(req, res, next) { + const { body = {} } = req; - var completedWith = req.body.challengeInfo.completedWith || ''; - var completedDate = Math.round(+new Date()); - var challengeId = req.body.challengeInfo.challengeId; - var solutionLink = req.body.challengeInfo.publicURL; + let completedChallenge; + // backwards compatibility + // please remove once in production + // to allow users to transition to new client code + if (body.challengeInfo) { - var githubLink = req.body.challengeInfo.challengeType === '4' ? - req.body.challengeInfo.githubURL : - true; + if (!body.challengeInfo.challengeId) { + req.flash('error', { msg: 'No id returned during save' }); + return res.sendStatus(403); + } - var challengeType = req.body.challengeInfo.challengeType === '4' ? - 4 : - 3; + completedChallenge = { + id: body.challengeInfo.challengeId, + name: body.challengeInfo.challengeName || '', + completedDate: Date.now(), - if (!solutionLink || !githubLink) { + challengeType: +body.challengeInfo.challengeType === 4 ? 4 : 3, + + solution: body.challengeInfo.publicURL, + githubLink: body.challengeInfo.githubURL + }; + } else { + completedChallenge = _.pick( + body, + [ 'id', 'name', 'solution', 'githubLink', 'challengeType' ] + ); + completedChallenge.challengeType = +completedChallenge.challengeType; + completedChallenge.completedDate = Date.now(); + } + + if ( + !completedChallenge.solution || + // only basejumps require github links + ( + completedChallenge.challengeType === 4 && + !completedChallenge.githubLink + ) + ) { req.flash('errors', { msg: 'You haven\'t supplied the necessary URLs for us to inspect ' + 'your work.' @@ -569,64 +588,12 @@ module.exports = function(app) { return res.sendStatus(403); } - var challengeData = { - id: challengeId, - name: req.body.challengeInfo.challengeName || '', - completedDate: completedDate, - solution: solutionLink, - githubLink: githubLink, - challengeType: challengeType, - verified: false - }; - observeQuery( - User, - 'findOne', - { where: { username: completedWith.toLowerCase() } } - ) - .doOnNext(function(pairedWith) { - if (pairedWith) { - updateUserProgress( - pairedWith, - challengeId, - assign({ completedWith: req.user.id }, challengeData) - ); - } - }) - .withLatestFrom(Observable.just(req.user), function(pairedWith, user) { - return { - user: user, - pairedWith: pairedWith - }; - }) - .doOnNext(function({ user, pairedWith }) { - updateUserProgress( - user, - challengeId, - pairedWith ? - assign({ completedWith: pairedWith.id }, challengeData) : - challengeData - ); - }) - .flatMap(function({ user, pairedWith }) { - return Observable.from([user, pairedWith]); - }) - // save users - .flatMap(function(user) { - // save user will do nothing if user is falsey - return saveUser(user); - }) - .subscribe( - function(user) { - if (user) { - debug('user %s saved', user.username); - } - }, - next, - function() { - return res.status(200).send(true); - } - ); + updateUserProgress(req.user, completedChallenge.id, completedChallenge); + + return saveUser(req.user) + .doOnNext(() => res.status(200).send(true)) + .subscribe(() => {}, next); } function showMap(showAside, { user }, res, next) { diff --git a/server/views/account/show.jade b/server/views/account/show.jade index b31cd23fb8..f7cf7c4e80 100644 --- a/server/views/account/show.jade +++ b/server/views/account/show.jade @@ -126,15 +126,17 @@ block content table.table.table-striped thead tr - th.col-xs-6 Projects - th.col-xs-3.hidden-xs Completed - th.col-xs-3.hidden-xs Link + th.col-xs-5 Projects + th.col-xs-2.hidden-xs Completed + th.col-xs-2.hidden-xs Last Updated + th.col-xs-2.hidden-xs Link for challenge in projects tr - td.col-xs-4.hidden-xs + td.col-xs-5.hidden-xs a(href='/challenges/' + removeOldTerms(challenge.name), target='_blank')= removeOldTerms(challenge.name) td.col-xs-2.hidden-xs= challenge.completedDate ? moment(challenge.completedDate, 'x').format("MMM DD, YYYY") : 'Not Available' - td.col-xs-6.hidden-xs + td.col-xs-2.hidden-xs= challenge.lastUpdated ? moment(challenge.lastUpdated, 'x').format("MMM DD, YYYY") : '' + td.col-xs-2.hidden-xs a(href=challenge.solution, target='_blank') View my project td.col-xs-12.visible-xs a(href=challenge.solution, target='_blank')= removeOldTerms(challenge.name)