CSOL-site/controllers/program.js

405 строки
11 KiB
JavaScript

var async = require('async');
var aestimia = require('../aestimia');
var badger = require('../openbadger');
var db = require('../db');
var errors = require('../lib/errors');
var mime = require('mime');
var _ = require('underscore');
var applications = db.model('Application');
var evidence = db.model('Evidence');
module.exports = function (app) {
function getFilters(query, subset) {
var all = badger.getFilters(),
filters = [];
query = query || {};
if (!subset || !subset.length)
subset = _.keys(all);
if (subset && !_.isArray(subset))
subset = [subset];
_.each(subset, function (item) {
var filter = all[item] || {name:item, label: item, options: []};
filter.selected = query[filter.name];
filters.push(filter);
});
return filters;
}
app.param('programName', function (req, res, next, programName) {
badger.getProgram(programName, function(err, data) {
if (err)
return next(err);
req.params.program = data.program;
next();
});
});
app.get('/explore', badger.middleware('getPrograms'), function (req, res, next) {
var data = req.remote;
res.render('programs/list.html', {
filters: getFilters(req.query, ['categories', 'orgs', 'ageRanges', 'activityTypes']),
items: data.programs,
page: data.page,
pages: data.pages
});
});
app.get('/explore/:programName', function (req, res, next) {
res.render('programs/single.html', {
program: req.params.program
});
});
app.get('/explore/:programName/favorite', function (req, res, next) {
return res.redirect('/login', 303);
});
app.get('/explore/:programName/unfavorite', function (req, res, next) {
return res.redirect('/login', 303);
});
app.post('/applications', function (req, res, next) {
function finish (err) {
if (err)
return res.json({status: err.message || err});
return res.json({status: 'ok'});
}
if (!req.body['_id'])
return finish('Could not find submission ID in request');
applications.find({where: {submissionId: req.body['_id']}})
.complete(function(err, application) {
if (err)
return finish(err);
aestimia.update(application);
finish();
});
});
app.param('evidenceSlug', function (req, res, next, slug) {
var parts = /^([a-z0-9]+?)(?:_(thumb))?$/.exec(slug);
var shouldAuthenticate = (req.method !== 'GET');
if (!parts)
return next(new errors.NotFound());
if (shouldAuthenticate && !req.session.user)
return next(new errors.Forbidden());
var key = parts[1],
thumb = !!parts[2];
evidence.find({where: {key: key}})
.complete(function (err, instance) {
if (err)
return next(err);
if (!instance)
return next(new errors.NotFound());
req.params.evidence = instance;
req.params.thumb = thumb;
instance.getApplication()
.complete(function (err, application) {
if (err)
return next(err);
req.params.application = application;
// We'll need to decide how to authenticate external services
// like, for example, Aestimia. For now, restrict access to either
// the learner who uploaded it, or their guardian
if (!shouldAuthenticate)
return next();
application.getLearner()
.complete(function (err, learner) {
if (err)
return next(err);
if (learner.id === req.session.user.id)
return next();
learner.getGuardian()
.complete(function (err, guardian) {
if (err)
return next(err);
if (!guardian || guardian.id !== req.session.user.id)
return next(new errors.Forbidden());
return next();
});
});
});
});
});
app.get('/evidence/:applicationId/:authHash', function (req, res, next) {
applications.find({where: {id: req.params.applicationId}})
.complete(function (err, application) {
if (err)
return next(err);
var hash = application.getHash();
if (req.params.authHash !== hash)
return next(new errors.NotFound());
res.type('text/plain');
res.send(application.description);
});
});
app.get('/evidence/:evidenceSlug', function (req, res, next) {
var evidence = req.params.evidence,
thumb = req.params.thumb;
res.type(evidence.mediaType);
res.header('Vary', 'Cookie');
res.header('Cache-Control', 'max-age=2419200'); // 4 weeks
res.header('Last-Modified', evidence.updatedAt);
evidence[thumb ? 'fetchThumb' : 'fetch'](function (remote) {
remote
.on('response', function(proxy) {
proxy.pipe(res);
})
.end();
});
});
app.post('/evidence/:evidenceSlug', function (req, res, next) {
var evidence = req.params.evidence,
application = req.params.application,
thumb = req.params.thumb;
if (thumb)
return next(new errors.NotAllowed());
if (!req.body.action || req.body.action !== 'delete')
return next(new errors.NotAllowed());
if (application.state !== 'open')
return next(new errors.NotAllowed());
evidence.destroy()
.complete(function (err) {
if (err)
return next(err);
evidence.getApplication()
.complete(function (err, application) {
if (err)
return next(err);
return res.redirect('/earn/' + application.badgeId + '/apply');
});
})
});
app.param('badgeName', function (req, res, next, badgeName) {
badger.getBadge(badgeName, function(err, data) {
if (err)
return next(err);
req.params.badge = data.badge;
next();
});
});
app.get('/earn', badger.middleware('getBadges'), function (req, res, next) {
var data = req.remote;
res.render('badges/list.html', {
filters: getFilters(req.query, ['categories', 'ageRanges', 'badgeTypes', 'activityTypes']),
items: data.badges,
page: data.page,
pages: data.pages
});
});
app.get('/earn/:badgeName', badger.middleware('getBadgeRecommendations', {limit:4}), function (req, res, next) {
var data = req.remote;
res.render('badges/single.html', {
badge: req.params.badge,
relatedBadges: data.badges
});
});
app.get('/earn/:badgeName/apply', function (req, res, next) {
var badge = req.params.badge;
var mimeTypes = evidence.getMimeTypes();
if (!req.session.user) {
req.session.afterLogin = '/earn/' + req.params.badgeName + '/apply';
return res.redirect('/login');
}
function render (state, context) {
context = _.defaults(context || {}, {
application: applications.build({
badgeId: badge.id,
state: 'open'
}),
mimeTypes: mimeTypes,
evidence: [],
badge: badge
});
res.render('applications/' + state + '.html', context);
}
applications.find({where: {
badgeId: badge.id,
LearnerId: req.session.user.id
}})
.complete(function(err, application) {
if (err)
return next(err);
if (!application)
return render('new');
var wordcount = application.description.replace(/[^\w\s]/g, '').split(/\s+/).length;
application.getEvidence()
.complete(function(err, evidence) {
if (err)
return next(err);
var state = evidence.length || (wordcount >= 20) ? application.state : 'new';
render(state, {
evidence: evidence,
application: application
});
});
});
});
app.post('/earn/:badgeName/apply', function (req, res, next) {
var badge = req.params.badge;
if (!req.session.user)
return res.redirect(badge.url);
function finish (err, evidence) {
if (req.xhr) {
return res.json({
status: err ? 'failed' : 'ok',
message: err || null,
evidence: evidence || []
});
}
if (err)
req.flash('error', err);
res.redirect(badge.url + '/apply');
}
applications.findOrCreate({
badgeId: badge.id,
LearnerId: req.session.user.id
})
.complete(function(err, application) {
if (err || !application)
return finish(err);
if (req.body.action === 'apply')
return application.submit(finish);
if (req.body.action === 'reopen')
return application.reopen(finish);
if ('description' in req.body) {
application.updateAttributes({
description: req.body.description.replace(/^\s*|\s*$/gi, '')
});
}
var files = (req.files||{}).media;
if (!files)
return finish();
if (!_.isArray(files))
files = [files];
async.map(files, function (file, callback) {
application.process(file, function (err, item) {
if (err || !item)
return callback(err);
callback(null, {
type: item.mediaType,
thumbnail: item.getThumbnailUrl(),
location: item.getLocationUrl(),
original: item.original
});
});
}, finish);
});
});
app.get('/earn/:badgeName/claim', function (req, res, next) {
res.render('badges/claim.html');
});
app.get('/earn/:badgeName/favorite', function (req, res, next) {
return res.redirect('/login', 303);
});
app.get('/earn/:badgeName/unfavorite', function (req, res, next) {
return res.redirect('/favorites', 303);
});
app.get('/orgs', function (req, res, next) {
var orgs = [];
for (var i = 0; i < 12; ++i) {
orgs.push({
thumbnail: '/media/img/org.png',
description: 'Organization blah irure...',
url: '/orgs/some-organization'
});
}
res.render('orgs/list.html', {
filters: getFilters('categories', 'ages'),
items: orgs
});
});
app.param('orgName', function (req, res, next, orgName) {
// pull some stuff from the database probably
next();
});
app.get('/orgs/:orgName', function (req, res, next) {
res.render('orgs/single.html');
});
app.get('/orgs/:orgName/favorite', function (req, res, next) {
return res.redirect('/login', 303);
});
app.get('/orgs/:orgName/unfavorite', function (req, res, next) {
return res.redirect('/login', 303);
});
};