badges now show correct "playlisted" info on /earn and badge detail pages if they are playlisted. fixes #718

This commit is contained in:
Joe Curlee 2013-07-13 07:44:05 -05:00
Родитель 495ee328dc
Коммит fc58d26c03
6 изменённых файлов: 69 добавлений и 59 удалений

Просмотреть файл

@ -176,7 +176,7 @@ module.exports = function (app) {
var data = req.remote;
var user = req.session.user;
async.each(data.badges,
async.each(data.badges,
function prepForSharing(badge, callback){
shareToken.findOrCreate({
shortName: badge.id,
@ -346,10 +346,25 @@ module.exports = function (app) {
return [c.value, {label: c.label, badges: shuffle(grouped[c.value]).slice(0, maxPerCat)}];
}));
// Construct the user's playlist
// Expects that `req.remote.badges` exists and that it is the *full* list
// of all badges -- this list is then filtered down by what's in the
// playlist table to produce the user's playlist (nb: once/if the openbadger
// API supports taking a list of badge shortnames to return badge details
// about, retrieving the full list from the API is no longer necessary).
var playlist = new Array(req.paylist_ids);
_.each(req.remote.badges, function(badge) {
if (badge.id in req.playlist_shortnames) {
var index = req.playlist_shortnames[badge.id];
playlist[index] = badge;
}
});
res.render('user/myplaylist.html', {
user: res.locals.user,
recommended: recommended,
playlist: req.playlist
playlist: req.playlist,
paylist_ids: req.paylist_ids
});
});

Просмотреть файл

@ -9,6 +9,9 @@ var _ = require('underscore');
var applications = db.model('Application');
var evidence = db.model('Evidence');
const playlist = db.model('Playlist');
const playlistMiddleware = _.bind(playlist.middleware, playlist);
module.exports = function (app) {
function getFilters(query, subset) {
@ -221,22 +224,24 @@ module.exports = function (app) {
});
});
app.get('/earn', badger.middleware('getBadges'), function (req, res, next) {
app.get('/earn', [badger.middleware('getBadges'),playlistMiddleware], function (req, res, next) {
var data = req.remote;
res.render('badges/list.html', {
filters: getFilters(req.query, ['categories', 'ageRanges', 'badgeTypes', 'activityTypes', 'search']),
items: data.badges,
page: data.page,
pages: data.pages
pages: data.pages,
playlist_ids:req.playlist_ids,
});
});
app.get('/earn/:badgeName', badger.middleware('getBadgeRecommendations', {limit:4}), function (req, res, next) {
app.get('/earn/:badgeName', [badger.middleware('getBadgeRecommendations', {limit:4}),playlistMiddleware], function (req, res, next) {
var data = req.remote;
res.render('badges/single.html', {
badge: req.params.badge,
relatedBadges: data.badges
relatedBadges: data.badges,
playlist_ids:req.playlist_ids,
});
});

Просмотреть файл

@ -30,72 +30,64 @@ module.exports = {
// `add` adds a badge to the user's playlist
add: function (user, shortName, callback) {
var _this = this;
this.max('rank', {where: {LearnerId: user.id}})
.success(function(rank) {
_this.create({shortName: shortName, LearnerId: user.id, rank: (rank || 0)+1}).
success(function(item) {
callback(null, item);
if (user) {
this.max('rank', {where: {LearnerId: user.id}})
.success(function(rank) {
_this.create({shortName: shortName, LearnerId: user.id, rank: (rank || 0)+1}).
success(function(item) {
callback(null, item);
}).
error(function(err) {
callback(err);
});
}).
error(function(err) {
callback(err);
});
}).
error(function(err) {
callback(err);
});
}
},
// `remove` removes a badge from the user's playlist
remove: function (user, shortName, callback) {
this.find({where: {LearnerId: user.id, shortName: shortName}}).
success(function(item) {
if (item === null) {
// not treating this as an error condition as the result is what the user wanted to happen anyway: The badge in question is no longer in their playlist.
logger.log('info', 'playlist.classMethods.remove was unable to find item with learnerid %s and shortname %s', user.id, shortName);
callback(null);
}
else {
item.destroy().success(function() {
callback(null);
}).error(function(err) {
callback(err);
});
}
}).
error(function(err) {
callback(err);
});
if (user) {
this.find({where: {LearnerId: user.id, shortName: shortName}}).
success(function(item) {
if (item === null) {
// not treating this as an error condition as the result is what the user wanted to happen anyway: The badge in question is no longer in their playlist.
logger.log('info', 'playlist.classMethods.remove was unable to find item with learnerid %s and shortname %s', user.id, shortName);
callback(null);
}
else {
item.destroy().success(function() {
callback(null);
}).error(function(err) {
callback(err);
});
}
}).
error(function(err) {
callback(err);
});
}
},
// middleware gets the user's playlist of badges and makes it available via
// `req.playlist`, which is a sorted array of badges.
// It expects that `req.remote.badges` exists and that it is the *full* list
// of all badges -- this list is then filtered down by what's in the
// playlist table to produce the user's playlist (nb: once/if the openbadger
// API supports taking a list of badge shortnames to return badge details
// about, retrieving the full list from the API is no longer necessary).
middleware: function (req, res, next) {
var badges = req.remote.badges;
//var badges = req.remote.badges;
var user = res.locals.user;
this.findAll({where: {LearnerId: user.id}, order: 'rank DESC'}).
var userid = (user) ? user.id : 0;
this.findAll({where: {LearnerId: userid}, order: 'rank DESC'}).
success(function(rawList) {
// Make a badge short name -> rank lookup.
// This serves both as a way to filter down the full badge list into
// the ones in the playlist, as well as to sort the results by rank.
var shortNames = {}
var playlist_ids = new Array(rawList.length);
_.each(rawList, function(item, index) {
shortNames[item.shortName] = index;
playlist_ids.push(item.shortName);
});
// Construct the user's playlist
var playlist = new Array(rawList.length);
_.each(badges, function(badge) {
if (badge.id in shortNames) {
var index = shortNames[badge.id];
playlist[index] = badge;
}
});
req.playlist = playlist;
req.playlist_shortnames = shortNames;
req.playlist_ids = playlist_ids;
next();
}).

Просмотреть файл

@ -7,7 +7,6 @@
<div class="row">
<div class="span4">
<div class="featured-badge">
{% set hide_badge_actions = 1 %}
{% include "includes/badge-thumbnail.html" %}
</div>
</div>
@ -35,12 +34,14 @@
{% endif %}
</p>
<br>
{% if (not playlist_ids or playlist_ids.indexOf(item.id) < 0) %}
<p>
<form action="/myplaylist" method="POST">
<input type="hidden" name="shortname" value="{{ item.id }}">
<button type="submit" class="btn" title="Add to playlist">Add to your playlist</button>
</form>
</p>
{% endif %}
{% endif %}
<hr>
<ul class="tags">

Просмотреть файл

@ -4,7 +4,6 @@ Context variables from including template:
- item (required)
- url (optional)
- playlisted (optional)
#}
{# itemUrl simplifies getting the URL for the badge: it can be set in the
@ -17,11 +16,10 @@ doesn't have a URL #}
{{ item.url }}
{% endif %}
{% endmacro %}
<figure class="thumbnail{% if application %} state-{{ item.state }}{% endif %}">
{% if not application %}
<div class="playlist-bar text-center{% if playlisted %} in{% endif %}">
{% if not playlisted %}
<div class="playlist-bar text-center{% if playlist_ids and playlist_ids.indexOf(item.id) >= 0 %} in{% endif %}">
{% if not playlist_ids or playlist_ids.indexOf(item.id) < 0 %}
{% include "includes/add-to-playlist-btn.html" %}
{% else %}
<p>In Playlist</p>
@ -55,7 +53,7 @@ doesn't have a URL #}
{% if not hide_badge_actions %}
<div class="item-actions row-fluid">
<div class="span6">
{% if playlisted %}
{% if playlist_ids and playlist_ids.indexOf(item.id) >= 0 %}
<form action="/myplaylist" method="POST" class="playlist-remove">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="shortname" value="{{ item.id }}">

Просмотреть файл

@ -13,7 +13,6 @@
{% if playlist.length %}
<ul class="thumbnails">
{% for item in playlist %}
{% set playlisted = true %}
<li span="3">
{% include "includes/badge-thumbnail.html" %}
</li>