зеркало из https://github.com/mozilla/CSOL-site.git
Basic badge sharing and privacy control
This commit is contained in:
Родитель
11c582c9be
Коммит
8485adb25b
|
@ -1,4 +1,5 @@
|
|||
const _ = require('underscore');
|
||||
const async = require('async');
|
||||
const openbadger = require('../openbadger');
|
||||
const db = require('../db');
|
||||
const isLearner = require('../middleware').isLearner;
|
||||
|
@ -6,6 +7,7 @@ const isLearner = require('../middleware').isLearner;
|
|||
const claim = db.model('Claim');
|
||||
const favorite = db.model('Favorite');
|
||||
const playlist = db.model('Playlist');
|
||||
const shareToken = db.model('ShareToken');
|
||||
const favoriteMiddleware = _.bind(favorite.middleware, favorite);
|
||||
const playlistMiddleware = _.bind(playlist.middleware, playlist);
|
||||
const applications = db.model('Application');
|
||||
|
@ -129,6 +131,7 @@ module.exports = function (app) {
|
|||
isLearner,
|
||||
openbadger.middleware('getUserBadge')
|
||||
], function (req, res, next) {
|
||||
var user = req.session.user;
|
||||
var data = req.remote;
|
||||
|
||||
// XXX: replace with API call to openbadger
|
||||
|
@ -161,13 +164,100 @@ module.exports = function (app) {
|
|||
|
||||
const NSIMILAR = 4;
|
||||
|
||||
res.render('user/badge.html', {
|
||||
badge: data.badge,
|
||||
user: req.session.user,
|
||||
similar: similar.slice(0, NSIMILAR)
|
||||
if (user.underage) {
|
||||
return res.render('user/badge.html', {
|
||||
badge: data.badge,
|
||||
user: req.session.user,
|
||||
similar: similar.slice(0, NSIMILAR),
|
||||
share: false
|
||||
});
|
||||
}
|
||||
else {
|
||||
async.waterfall([
|
||||
function getToken (callback) {
|
||||
shareToken.findOrCreate({
|
||||
shortName: data.badge.shortname,
|
||||
email: user.email
|
||||
}).complete(callback);
|
||||
},
|
||||
function ensureTokenValue (token, callback) {
|
||||
if (!token.token)
|
||||
token.generateToken(callback);
|
||||
else
|
||||
callback(null, token);
|
||||
}
|
||||
], function renderPage (err, shareToken) {
|
||||
var share = false;
|
||||
if (shareToken) {
|
||||
share = shareToken.values;
|
||||
share.url = shareToken.getUrl();
|
||||
share.toggleUrl = shareToken.getToggleUrl();
|
||||
}
|
||||
|
||||
return res.render('user/badge.html', {
|
||||
badge: data.badge,
|
||||
user: req.session.user,
|
||||
similar: similar.slice(0, NSIMILAR),
|
||||
share: share
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/share/:token', function (req, res, next) {
|
||||
var token = req.params.token;
|
||||
|
||||
shareToken.find({
|
||||
token: token
|
||||
}).complete(function (err, token) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (!token.shared)
|
||||
return next('Invalid share token');
|
||||
|
||||
openbadger.getUserBadge({
|
||||
id: token.shortName,
|
||||
email: token.email
|
||||
}, function (err, data) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
return res.render('user/badge-share.html', {
|
||||
badge: data.badge,
|
||||
user: {
|
||||
email: token.email
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/share/toggle/:token', [
|
||||
isLearner
|
||||
], function (req, res, next) {
|
||||
var token = req.params.token;
|
||||
var user = req.session.user;
|
||||
|
||||
shareToken.find({
|
||||
token: token
|
||||
}).complete(function (err, token) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
if (token.email !== user.email)
|
||||
return next('User does not own token');
|
||||
|
||||
token.toggle(function (err) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
return res.redirect('/mybadges/' + token.shortName);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
app.post('/mybadges/:id/favorite', [
|
||||
isLearner,
|
||||
openbadger.middleware('getBadge')
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
var db = require('../db');
|
||||
var crypto = require('crypto');
|
||||
var url = require('url');
|
||||
|
||||
const CSOL_HOST = process.env.CSOL_HOST;
|
||||
|
||||
function md5(value) {
|
||||
return (
|
||||
crypto
|
||||
.createHash('md5')
|
||||
.update(value)
|
||||
.digest('hex')
|
||||
);
|
||||
}
|
||||
|
||||
function urlgen(value) {
|
||||
const nonce = Math.random() * 0x10000000;
|
||||
return md5('' + value + Date.now() + nonce);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
properties: {
|
||||
token: {
|
||||
type: db.type.STRING,
|
||||
allowNull: true,
|
||||
unique: true
|
||||
},
|
||||
email: {
|
||||
type: db.type.STRING,
|
||||
allowNull: false,
|
||||
validate: {
|
||||
isEmail: true
|
||||
}
|
||||
},
|
||||
shortName: {
|
||||
type: db.type.STRING,
|
||||
allowNull: false
|
||||
},
|
||||
shared: {
|
||||
type: db.type.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
}
|
||||
},
|
||||
relationships: [
|
||||
{
|
||||
model: 'Learner',
|
||||
type: 'hasMany'
|
||||
}
|
||||
],
|
||||
instanceMethods: {
|
||||
getUrl: function () {
|
||||
return url.resolve(CSOL_HOST, 'share/' + this.token);
|
||||
},
|
||||
getToggleUrl: function () {
|
||||
return url.resolve(CSOL_HOST, 'share/toggle/' + this.token);
|
||||
},
|
||||
generateToken: function (callback) {
|
||||
this.updateAttributes({
|
||||
token: urlgen(this.email + this.shortName)
|
||||
}).complete(callback);
|
||||
},
|
||||
toggle: function (callback) {
|
||||
this.updateAttributes({
|
||||
shared: !this.shared
|
||||
}).complete(callback);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% set navitem = 'backpack' %}
|
||||
{% set pageTitle = badge.name %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="span4">
|
||||
<img src="{{ badge.image }}">
|
||||
</div>
|
||||
<div class="span8">
|
||||
<p>
|
||||
<b>Issued by:</b>
|
||||
{% if badge.program.issuer.url %}
|
||||
<a href="{{ badge.program.issuer.url }}">
|
||||
{% endif %}
|
||||
{{ badge.program.issuer.name }}
|
||||
{% if badge.program.issuer.url %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<b>Issued to:</b> {{ user.email }}
|
||||
</p>
|
||||
|
||||
<h3>What is this badge about?</h3>
|
||||
<p class="description">{{ badge.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -3,6 +3,23 @@
|
|||
{% set pageTitle = badge.name %}
|
||||
|
||||
{% block content %}
|
||||
{% if share %}
|
||||
<div class="row share">
|
||||
<div class="span12">
|
||||
{% if share.shared %}
|
||||
<p class="muted">
|
||||
Public url: <a href="{{share.url}}">{{share.url}}</a>
|
||||
<a class="share-toggle" href="{{share.toggleUrl}}">Make it private.</a>
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="muted">
|
||||
This page is private.
|
||||
<a class="share-toggle" href="{{share.toggleUrl}}">Make it public.</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="span4">
|
||||
<img src="{{ badge.image }}">
|
||||
|
|
Загрузка…
Ссылка в новой задаче