Skip to content
This repository was archived by the owner on Jan 14, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions models/badge-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ const regex = {
email: /[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?/i
};

const EvidenceFileSchema = new Schema({
path: {
type: String,
required: true
},
mimeType: {
type: String,
required: true
}
});

const BadgeInstanceSchema = new Schema({
_id: {
type: String,
Expand Down Expand Up @@ -36,6 +47,7 @@ const BadgeInstanceSchema = new Schema({
type: String,
trim: true,
},
evidenceFiles: [EvidenceFileSchema],
seen: {
type: Boolean,
required: true,
Expand Down
16 changes: 9 additions & 7 deletions models/badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,10 +548,7 @@ Badge.prototype.redeemClaimCode = function redeemClaimCode(code, email, cb) {
if (!claim.multi && claim.claimedBy && claim.claimedBy !== email)
return cb(null, false);
claim.claimedBy = email;
Badge.temporaryEvidence.destroy(claim, function(err) {
if (err) return cb(err);
cb(null, true);
});
cb(null, true);
};

Badge.prototype.removeClaimCode = function removeClaimCode(code, cb) {
Expand Down Expand Up @@ -623,10 +620,12 @@ Badge.prototype.award = function award(options, callback) {
const categories = this.categories;
const weight = this.weight;
const evidence = options.evidence;
const evidenceFiles = options.evidenceFiles;
const instance = new BadgeInstance({
user: email,
badge: this.id,
evidence: evidence,
evidenceFiles: evidenceFiles
});

// We don't want to fail with an error if the user already has the
Expand All @@ -649,9 +648,12 @@ Badge.prototype.award = function award(options, callback) {
});
};

Badge.prototype.awardOrFind = function awardOrFind(email, callback) {
const query = { userBadgeKey: [email, this.id].join('.') };
this.award(email, function (err, instance) {
Badge.prototype.awardOrFind = function awardOrFind(options, callback) {
if (typeof options === 'string')
options = {user: options};

const query = { userBadgeKey: [options.user, this.id].join('.') };
this.award({ user: options.user, evidenceFiles: options.evidenceFiles }, function (err, instance) {
if (!instance) {
BadgeInstance.findOne(query, function (err, instance) {
if (err) return callback(err);
Expand Down
8 changes: 6 additions & 2 deletions routes/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ function tryAwardingBadge(opts, res, successCb) {
const badge = opts.badge;
const email = opts.email;
const evidence = opts.evidence;
const evidenceFiles = opts.evidenceFiles;

if (!badge)
return res.json(404, {status: 'error', reason: 'badge not found'});
Expand All @@ -381,7 +382,8 @@ function tryAwardingBadge(opts, res, successCb) {

return badge.award({
email: email,
evidence: evidence
evidence: evidence,
evidenceFiles: evidenceFiles
}, function (err, instance, autoAwardedInstances) {
if (err) {
// TODO: log error properly
Expand Down Expand Up @@ -484,10 +486,12 @@ exports.awardBadgeFromClaimCode = function(req, res, next) {
return res.json(400, {status: 'error', reason: 'missing email address'});

getUnclaimedBadgeFromCode(code, req, res, next, function(badge) {
var claim = badge.getClaimCode(code);
tryAwardingBadge({
badge: badge,
email: email,
evidence: evidence
evidence: evidence,
evidenceFiles: claim.evidence
}, res, function(success) {
async.series([
badge.redeemClaimCode.bind(badge, code, email),
Expand Down
35 changes: 34 additions & 1 deletion routes/badge.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const BadgeInstance = require('../models/badge-instance');
const Work = require('../models/work');
const util = require('../lib/util');
const async = require('async');
const s3 = require('../lib/s3');
const mime = require('mime');

function handleTagInput(input) {
return (
Expand Down Expand Up @@ -146,6 +148,36 @@ exports.assertion = function assertion(req, res) {
});
};

exports.getEvidenceFile = function getEvidenceFile(req, res) {
var assertionId = req.param('hash');
var evidenceIndex = req.param('index');

BadgeInstance.findOne({ _id: assertionId }, function (err, instance) {
if (err)
return res.send(500, err);
if (!instance)
return res.send(404);

if (evidenceIndex < 0 || evidenceIndex >= instance.evidenceFiles.length)
return res.send(404);

var evidence = instance.evidenceFiles[evidenceIndex];

s3.get(evidence.path).on('response', function(s) {
if (err) return res.json(500, {
status: 'error',
reason: 'cannot retrieve evidence'
});
res.type(evidence.mimeType);
var ext = mime.extension(evidence.mimeType);
var filename = 'evidence-' + evidenceIndex + (ext ? '.' + ext : '');
res.set('Content-Disposition',
'attachment; filename="' + filename + '"');
s.pipe(res);
}).end();
});
};

exports.meta = function meta(req, res) {
req.badge.populate('program', function(err) {
if (err)
Expand Down Expand Up @@ -242,6 +274,7 @@ exports.awardToUser = function awardToUser(req, res, next) {
var email = (form.email || '').trim();
var code = (form.code || '').trim();
var badge = req.badge;
var evidenceFiles = req.claim.evidence;

badge.redeemClaimCode(code, email, function(err, claimSuccess) {
if (err) return res.send(reportError(err));
Expand All @@ -251,7 +284,7 @@ exports.awardToUser = function awardToUser(req, res, next) {
if (claimSuccess === null)
return res.send({ status: 'not-found' });

badge.awardOrFind(email, function (err, instance) {
badge.awardOrFind({ user: email, evidenceFiles: evidenceFiles }, function (err, instance) {
if (err) return res.send(reportError(err));
badge.save(function (err) {
if (err) return res.send(reportError(err));
Expand Down
3 changes: 3 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ exports.define = function defineRoutes(app) {
app.get('/badge/criteria/:shortname', [
findBadgeByParamShortname
], render.criteria);
app.get('/badge/evidence/:hash', render.evidence);
app.get('/badge/evidence/:hash/:index', badge.getEvidenceFile);

app.get('/program/meta/:programId', [
issuer.findProgramById
], issuer.meta);
Expand Down
22 changes: 22 additions & 0 deletions routes/render.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const Issuer = require('../models/issuer');
const Program = require('../models/program');
const Badge = require('../models/badge');
const BadgeInstance = require('../models/badge-instance');
const phrases = require('../lib/phrases');
const logger = require('../lib/logger');
const async = require('async');
Expand Down Expand Up @@ -170,6 +171,27 @@ exports.criteria = function criteria(req, res) {
});
}

exports.evidence = function evidence(req, res) {
var assertionId = req.param('hash');

BadgeInstance.findOne({ _id: assertionId }, function (err, instance) {
if (err)
return res.send(500, err);
if (!instance)
return res.send(404);
instance.populate('badge', function(err) {
if (err)
return res.send(500, err);

return res.render('public/evidence.html', {
instance: instance,
user: req.session.user,
csrf: req.session._csrf
});
});
});
}

exports.anonymousHome = function all(req, res) {
return res.render('public/anonymous-home.html', {
user: req.session.user,
Expand Down
21 changes: 21 additions & 0 deletions views/public/evidence.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% extends "public/layout.html" %}
{% block title %}{{ instance.badge.name }}{% endblock %}
{% block body %}
<h1>{{ instance.badge.name }}</h1>
{% if instance.evidence or instance.evidenceFiles.length %}
<dl>
<dt>Evidence:</dt>
<dd>
<p>
{{ instance.evidence }}
</p>

{% for file in instance.evidenceFiles %}
<p><a href="/badge/evidence/{{ instance._id }}/{{ loop.index0 }}">Attachment {{ loop.index }}</a></p>
{% endfor %}
</dd>
</dl>
{% else %}
<h3>No evidence found for this badge</h3>
{% endif %}
{% endblock %}