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
This commit is contained in:
Berkeley Martinez
2016-01-19 22:30:01 -08:00
parent c3869ab717
commit 8a0341a7ac
3 changed files with 59 additions and 94 deletions

View File

@ -74,14 +74,14 @@ window.common = (function(global) {
$('#next-courseware-button').unbind('click'); $('#next-courseware-button').unbind('click');
if ($('.signup-btn-nav').length < 1) { if ($('.signup-btn-nav').length < 1) {
var data; var data;
var completedWith = $('#completed-with').val() || null; var solution = $('#public-url').val() || null;
var publicURL = $('#public-url').val() || null; var githubLink = $('#github-url').val() || null;
var githubURL = $('#github-url').val() || null;
switch (common.challengeType) { switch (common.challengeType) {
case common.challengeTypes.VIDEO: case common.challengeTypes.VIDEO:
data = { data = {
id: common.challengeId, id: common.challengeId,
name: common.challengeName name: common.challengeName,
challengeType: common.challengeType
}; };
$.post('/completed-challenge/', data) $.post('/completed-challenge/', data)
.success(function(res) { .success(function(res) {
@ -99,15 +99,11 @@ window.common = (function(global) {
case common.challengeTypes.BASEJUMP: case common.challengeTypes.BASEJUMP:
case common.challengeTypes.ZIPLINE: case common.challengeTypes.ZIPLINE:
data = { data = {
challengeInfo: { id: common.challengeId,
challengeId: common.challengeId, name: common.challengeName,
challengeName: common.challengeName, challengeType: +common.challengeType,
completedWith: completedWith, solution,
publicURL: publicURL, githubLink
githubURL: githubURL,
challengeType: common.challengeType,
verified: false
}
}; };
$.post('/completed-zipline-or-basejump/', data) $.post('/completed-zipline-or-basejump/', data)

View File

@ -2,7 +2,6 @@ import _ from 'lodash';
import dedent from 'dedent'; import dedent from 'dedent';
import moment from 'moment'; import moment from 'moment';
import { Observable, Scheduler } from 'rx'; import { Observable, Scheduler } from 'rx';
import assign from 'object.assign';
import debugFactory from 'debug'; import debugFactory from 'debug';
import accepts from 'accepts'; import accepts from 'accepts';
@ -15,11 +14,7 @@ import {
randomCompliment randomCompliment
} from '../utils'; } from '../utils';
import { import { saveUser, observeMethod } from '../utils/rx';
saveUser,
observeMethod,
observeQuery
} from '../utils/rx';
import { import {
ifNoUserSend ifNoUserSend
@ -384,7 +379,6 @@ module.exports = function(app) {
.map(challenge => challenge.toJSON()) .map(challenge => challenge.toJSON())
.shareReplay(); .shareReplay();
const User = app.models.User;
const send200toNonUser = ifNoUserSend(true); const send200toNonUser = ifNoUserSend(true);
router.post( router.post(
@ -506,7 +500,7 @@ module.exports = function(app) {
function completedChallenge(req, res, next) { function completedChallenge(req, res, next) {
const type = accepts(req).type('html', 'json', 'text'); const type = accepts(req).type('html', 'json', 'text');
const completedDate = Math.round(+new Date()); const completedDate = Date.now();
const { const {
id, id,
name, name,
@ -547,21 +541,46 @@ module.exports = function(app) {
} }
function completedZiplineOrBasejump(req, res, next) { function completedZiplineOrBasejump(req, res, next) {
const { body = {} } = req;
var completedWith = req.body.challengeInfo.completedWith || ''; let completedChallenge;
var completedDate = Math.round(+new Date()); // backwards compatibility
var challengeId = req.body.challengeInfo.challengeId; // please remove once in production
var solutionLink = req.body.challengeInfo.publicURL; // to allow users to transition to new client code
if (body.challengeInfo) {
var githubLink = req.body.challengeInfo.challengeType === '4' ? if (!body.challengeInfo.challengeId) {
req.body.challengeInfo.githubURL : req.flash('error', { msg: 'No id returned during save' });
true; return res.sendStatus(403);
}
var challengeType = req.body.challengeInfo.challengeType === '4' ? completedChallenge = {
4 : id: body.challengeInfo.challengeId,
3; 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', { req.flash('errors', {
msg: 'You haven\'t supplied the necessary URLs for us to inspect ' + msg: 'You haven\'t supplied the necessary URLs for us to inspect ' +
'your work.' 'your work.'
@ -569,64 +588,12 @@ module.exports = function(app) {
return res.sendStatus(403); return res.sendStatus(403);
} }
var challengeData = {
id: challengeId,
name: req.body.challengeInfo.challengeName || '',
completedDate: completedDate,
solution: solutionLink,
githubLink: githubLink,
challengeType: challengeType,
verified: false
};
observeQuery( updateUserProgress(req.user, completedChallenge.id, completedChallenge);
User,
'findOne', return saveUser(req.user)
{ where: { username: completedWith.toLowerCase() } } .doOnNext(() => res.status(200).send(true))
) .subscribe(() => {}, next);
.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);
}
);
} }
function showMap(showAside, { user }, res, next) { function showMap(showAside, { user }, res, next) {

View File

@ -126,15 +126,17 @@ block content
table.table.table-striped table.table.table-striped
thead thead
tr tr
th.col-xs-6 Projects th.col-xs-5 Projects
th.col-xs-3.hidden-xs Completed th.col-xs-2.hidden-xs Completed
th.col-xs-3.hidden-xs Link th.col-xs-2.hidden-xs Last Updated
th.col-xs-2.hidden-xs Link
for challenge in projects for challenge in projects
tr tr
td.col-xs-4.hidden-xs td.col-xs-5.hidden-xs
a(href='/challenges/' + removeOldTerms(challenge.name), target='_blank')= removeOldTerms(challenge.name) 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-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 a(href=challenge.solution, target='_blank') View my project
td.col-xs-12.visible-xs td.col-xs-12.visible-xs
a(href=challenge.solution, target='_blank')= removeOldTerms(challenge.name) a(href=challenge.solution, target='_blank')= removeOldTerms(challenge.name)