зеркало из https://github.com/mozilla/CSOL-site.git
Incorporating /v2/program and /v2/programs endpoints, and
refining badge endpoints. The program endpoints currently do not return enough data from the OpenBadger side to fully build out their pages. I'm also not sure about the controllers organizational strategy, and whether I'm breaking it. Changing site main navigation and major endpoints to "Earn, Learn, Level Up".
This commit is contained in:
Родитель
5d549f0d3a
Коммит
bf5ce3393e
|
@ -98,62 +98,43 @@ module.exports = function (app) {
|
|||
return filters;
|
||||
}
|
||||
|
||||
app.param('programName', function (req, res, next, badgeName) {
|
||||
// yep, get stuff from the db.
|
||||
next();
|
||||
});
|
||||
app.param('programName', function (req, res, next, programName) {
|
||||
badger.getProgram(programName, function(err, data) {
|
||||
if (err)
|
||||
return next(data.message);
|
||||
|
||||
app.get('/programs', function (req, res, next) {
|
||||
var programs = [];
|
||||
|
||||
for (var i = 0; i < 12; ++i) {
|
||||
programs.push({
|
||||
thumbnail: '/media/images/program.png',
|
||||
description: 'Program blah sed eiusmod...',
|
||||
url: '/programs/ae784f'
|
||||
});
|
||||
}
|
||||
|
||||
res.render('programs/list.html', {
|
||||
filters: getFilters('categories', 'orgs', 'ages'),
|
||||
items: programs
|
||||
req.params.program = data.program;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/programs/science', function (req, res, next) {
|
||||
res.send('SCIENCE!!')
|
||||
app.get('/learn', api(badger.getPrograms), function (req, res, next) {
|
||||
var data = req.remote;
|
||||
|
||||
res.render('programs/list.html', {
|
||||
filters: getFilters('categories', 'orgs', 'ages'),
|
||||
items: data.programs,
|
||||
page: data.page,
|
||||
pages: data.pages
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/programs/technology', function (req, res, next) {
|
||||
res.send('TECHNOLOGY!!!')
|
||||
app.get('/learn/:programName', function (req, res, next) {
|
||||
res.render('programs/single.html', {
|
||||
program: req.params.program
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/programs/engineering', function (req, res, next) {
|
||||
res.send('ENGINEERING!!!')
|
||||
});
|
||||
|
||||
app.get('/programs/art', function (req, res, next) {
|
||||
res.send('ART!!!')
|
||||
});
|
||||
|
||||
app.get('/programs/math', function (req, res, next) {
|
||||
res.send('MATH!!!')
|
||||
});
|
||||
|
||||
app.get('/programs/:programName', function (req, res, next) {
|
||||
res.render('programs/single.html');
|
||||
});
|
||||
|
||||
app.get('/programs/:programName/favorite', function (req, res, next) {
|
||||
app.get('/learn/:programName/favorite', function (req, res, next) {
|
||||
return res.redirect('/login', 303);
|
||||
});
|
||||
|
||||
app.get('/programs/:programName/unfavorite', function (req, res, next) {
|
||||
app.get('/learn/:programName/unfavorite', function (req, res, next) {
|
||||
return res.redirect('/login', 303);
|
||||
});
|
||||
|
||||
app.param('badgeName', function (req, res, next, badgeName) {
|
||||
api.getBadge(badgeName, function(err, data) {
|
||||
badger.getBadge(badgeName, function(err, data) {
|
||||
if (err)
|
||||
return next(data.message);
|
||||
|
||||
|
@ -162,7 +143,7 @@ module.exports = function (app) {
|
|||
});
|
||||
});
|
||||
|
||||
app.get('/badges', api(badger.getBadges), function (req, res, next) {
|
||||
app.get('/earn', api(badger.getBadges), function (req, res, next) {
|
||||
var data = req.remote;
|
||||
|
||||
res.render('badges/list.html', {
|
||||
|
@ -171,40 +152,23 @@ module.exports = function (app) {
|
|||
page: data.page,
|
||||
pages: data.pages
|
||||
});
|
||||
|
||||
/*
|
||||
var badges = [];
|
||||
|
||||
for (var i = 0; i < 12; ++i) {
|
||||
badges.push({
|
||||
thumbnail: '/media/images/badge.png',
|
||||
description: 'Badge blah in voluptate velit...',
|
||||
url: '/badges/ae784f'
|
||||
});
|
||||
}
|
||||
|
||||
res.render('badges/list.html', {
|
||||
filters: getFilters(),
|
||||
items: badges
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
||||
app.get('/badges/:badgeName', function (req, res, next) {
|
||||
app.get('/earn/:badgeName', function (req, res, next) {
|
||||
res.render('badges/single.html', {
|
||||
badge: req.params.badge
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/badges/:badgeName/claim', function (req, res, next) {
|
||||
app.get('/earn/:badgeName/claim', function (req, res, next) {
|
||||
res.render('badges/claim.html');
|
||||
});
|
||||
|
||||
app.get('/badges/:badgeName/favorite', function (req, res, next) {
|
||||
app.get('/earn/:badgeName/favorite', function (req, res, next) {
|
||||
return res.redirect('/login', 303);
|
||||
});
|
||||
|
||||
app.get('/badges/:badgeName/unfavorite', function (req, res, next) {
|
||||
app.get('/earn/:badgeName/unfavorite', function (req, res, next) {
|
||||
return res.redirect('/favorites', 303);
|
||||
});
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ function normalizeBadge (badge, id) {
|
|||
badge.id = id;
|
||||
|
||||
if (!badge.url)
|
||||
badge.url = '/badge/' + badge.id;
|
||||
badge.url = '/earn/' + badge.id;
|
||||
|
||||
return badge;
|
||||
}
|
||||
|
@ -60,3 +60,50 @@ exports.getBadge = apiMethod(function getBadge (query, callback) {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
function normalizeProgram(program, id) {
|
||||
if (!id)
|
||||
id = program.shortname;
|
||||
|
||||
if (!program.id)
|
||||
program.id = id;
|
||||
|
||||
if (!program.url)
|
||||
program.url = '/learn/' + program.id;
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
exports.getPrograms = apiMethod(paginate('programs', function getPrograms (query, callback) {
|
||||
remote.get('/v2/programs', function(err, data) {
|
||||
if (err)
|
||||
return callback(err, data);
|
||||
|
||||
var programs = _.map(data.programs, normalizeProgram);
|
||||
|
||||
return callback(null, {
|
||||
programs: programs
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
exports.getProgram = apiMethod(function getProgram (query, callback) {
|
||||
var id = query.id;
|
||||
|
||||
if (!id)
|
||||
return callback(400, 'Invalid program key');
|
||||
|
||||
remote.get('/v2/program/' + id, function(err, data) {
|
||||
if (err)
|
||||
return callback(err, data);
|
||||
|
||||
var program = data.program;
|
||||
|
||||
normalizeProgram(program, id);
|
||||
|
||||
callback(null, {
|
||||
program: program
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -42,6 +42,30 @@ const DATA = {
|
|||
image: 'http://openbadger-csol.mofostaging.net/badge/image/link-basic.png',
|
||||
behaviors: [ { name: 'link', score: 5 } ]
|
||||
}
|
||||
},
|
||||
'programs': {
|
||||
status: 'ok',
|
||||
programs: {
|
||||
"prog-a": {
|
||||
image: "http://some.org/prog-a/img.png",
|
||||
name: "Program A"
|
||||
},
|
||||
"prog-b": {
|
||||
image: "http://some.org/prog-b/img.png",
|
||||
name: "Program B"
|
||||
},
|
||||
"prog-c": {
|
||||
image: "http://some.org/prog-c/img.png",
|
||||
name: "Program C"
|
||||
}
|
||||
}
|
||||
},
|
||||
'program': {
|
||||
status: 'ok',
|
||||
program: {
|
||||
image: "http://some.org/prog-a/img.png",
|
||||
name: "Program A"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -75,9 +99,9 @@ test('getBadge', function(t) {
|
|||
getStub.callsArgWith(1, null, DATA['badge']);
|
||||
openbadger.getBadge({ id: 'some-id' }, function(err, data) {
|
||||
t.notOk(err, "no error");
|
||||
t.ok(getStub.calledWithMatch('/badge/some-id'), 'endpoint');
|
||||
t.ok(getStub.calledWithMatch('/badge/some-id'), 'remote endpoint');
|
||||
t.similar(data.badge, { name: "Link Badge, basic"}, 'badge');
|
||||
t.similar(data.badge, { id: 'some-id', url: '/badge/some-id' }, 'normalized');
|
||||
t.similar(data.badge, { id: 'some-id', url: '/earn/some-id' }, 'normalized');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
@ -91,7 +115,7 @@ test('getBadges', function(t){
|
|||
openbadger.getBadges(DEFAULT_QUERY, function(err, data) {
|
||||
t.same(err, 500, 'error');
|
||||
t.similar(data, { message: 'error of some sort' }, 'data');
|
||||
t.end();
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -103,7 +127,7 @@ test('getBadges', function(t){
|
|||
var badge = data.badges[0];
|
||||
t.ok(badge.id && badge.url && badge.name && badge.behaviors, 'looks like normalized badge');
|
||||
t.ok(getStub.calledWithMatch('/v2/badges'), 'endpoint');
|
||||
t.end();
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -112,7 +136,78 @@ test('getBadges', function(t){
|
|||
openbadger.getBadges({ pageSize: 2, page: 1 }, function(err, data) {
|
||||
t.notOk(err, 'no error');
|
||||
t.same(data.badges.length, 2, 'paginated');
|
||||
t.end();
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('getProgram', function(t) {
|
||||
/* reset spy data/stub behavior */
|
||||
getStub.reset();
|
||||
getStub.resetBehavior();
|
||||
|
||||
t.test('called without id', function(t) {
|
||||
openbadger.getProgram(function(err, data) {
|
||||
t.notOk(getStub.called, 'no call');
|
||||
t.same(err, 400);
|
||||
t.same(data, { message: "Invalid program key" });
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('on error', function(t) {
|
||||
getStub.callsArgWith(1, 404, 'barf');
|
||||
openbadger.getProgram({ id: 'whatever' }, function(err, data) {
|
||||
t.ok(getStub.calledOnce, "called");
|
||||
t.same(err, 404);
|
||||
t.same(data.message, "barf", "error message");
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('on success', function(t) {
|
||||
getStub.callsArgWith(1, null, DATA['program']);
|
||||
openbadger.getProgram({ id: 'some-id' }, function(err, data) {
|
||||
t.notOk(err, "no error");
|
||||
t.ok(getStub.calledWithMatch('/program/some-id'), 'endpoint');
|
||||
t.similar(data.program, { name: "Program A" }, 'program');
|
||||
t.similar(data.program, { id: 'some-id', url: '/learn/some-id' }, 'normalized');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('getPrograms', function(t) {
|
||||
|
||||
t.test('on error', function(t) {
|
||||
getStub.callsArgWith(1, 500, 'error of some sort');
|
||||
openbadger.getPrograms(DEFAULT_QUERY, function(err, data) {
|
||||
t.same(err, 500, 'error');
|
||||
t.similar(data, { message: 'error of some sort' }, 'data');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('with data', function(t) {
|
||||
getStub.callsArgWith(1, null, DATA['programs']);
|
||||
openbadger.getPrograms(DEFAULT_QUERY, function(err, data) {
|
||||
t.notOk(err, 'no error');
|
||||
t.same(data.programs.length, 3, 'data length');
|
||||
var program = data.programs[0];
|
||||
t.ok(program.id && program.url && program.name, 'looks like normalized program');
|
||||
t.ok(getStub.calledWithMatch('/v2/programs'), 'endpoint');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
t.test('paginates', function(t) {
|
||||
getStub.callsArgWith(1, null, DATA['programs']);
|
||||
openbadger.getPrograms({ pageSize: 2, page: 1 }, function(err, data) {
|
||||
t.notOk(err, 'no error');
|
||||
t.same(data.programs.length, 2, 'paginated');
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
<figure class="thumbnail">
|
||||
<a href="{{ item.url }}"><img src="{{ item.image }}"></a>
|
||||
<figcaption class="caption">
|
||||
<p>{{ item.description }}</p>
|
||||
<p>{{ item.name }}</p>
|
||||
{% block item_actions_wrapper %}
|
||||
<p class="text-right">
|
||||
{% block item_actions %}
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
<a href="/learn">Learn</a>
|
||||
</li>
|
||||
<li class="badges{% if navItem == 'badges' %} active{% endif %}">
|
||||
<a href="/badges">Badges</a>
|
||||
<a href="/earn">Earn</a>
|
||||
</li>
|
||||
<li class="challenges{% if navItem == 'challenges' %} active{% endif %}">
|
||||
<a href="/challenges">Challenges</a>
|
||||
<a href="/challenges">Level Up</a>
|
||||
</li>
|
||||
{% if user %}
|
||||
{% if user.type == 'learner' %}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{% extends 'programs/layout.html' %}
|
||||
{% set pageTitle = 'Some Program' %}
|
||||
{% set pageTitle = program.name %}
|
||||
{% set user = {} %}
|
||||
|
||||
{% block content %}
|
||||
|
|
Загрузка…
Ссылка в новой задаче