Skip to content
This repository has been archived by the owner on Jan 14, 2020. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Implement monthly stats [closes #55]
This implements a fake model that aggregates statistics about badge
issuances and exposes that information at `/admin/stats`. Right now
the information given is low fidelity -- it only gives a total count of
badges per month, not a breakdown of total per badge. We could improve
upon this later if needed.
  • Loading branch information
brianloveswords committed Feb 3, 2013
1 parent 0bd0576 commit 568333a
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 0 deletions.
4 changes: 4 additions & 0 deletions app.js
Expand Up @@ -13,6 +13,7 @@ var admin = require('./routes/admin');
var issuer = require('./routes/issuer');
var api = require('./routes/api');
var debug = require('./routes/debug');
var stats = require('./routes/stats');

var app = express();
var logger = app.logger = require('./lib/logger');
Expand Down Expand Up @@ -69,6 +70,9 @@ app.configure('production', function () {
app.get('/admin/config', admin.configure);
app.post('/admin/config', issuer.update);

app.get('/admin/stats', [stats.monthly], admin.stats);


// Badge listing
// -------------
var indexMiddleware = [badge.findAll, behavior.findAll];
Expand Down
21 changes: 21 additions & 0 deletions models/stats.js
@@ -0,0 +1,21 @@
const BadgeInstance = require('./badge-instance');

const Stats = {};

function isoMonthDay(date) {
return date.toISOString().slice(0, 7);
}

Stats.monthly = function monthlyStats(callback) {
const months = {};
BadgeInstance.find({}, function (err, instances) {
if (err) return callback(err);
instances.forEach(function (instance) {
const month = isoMonthDay(instance.issuedOn);
months[month] = (months[month] || 0) + 1;
});
callback(null, months);
});
};

module.exports = Stats;
11 changes: 11 additions & 0 deletions routes/admin.js
Expand Up @@ -140,6 +140,17 @@ exports.userList = function userList(req, res, next) {
});
};

exports.stats = function stats(req, res, next) {
return res.render('admin/stats.html', {
page: 'stats',
issuer: req.issuer,
stats: req.stats,
user: req.session.user,
csrf: req.session._csrf,
users: req.users
});
};

exports.notFound = function notFound(req, res, next) {
res.status(404)
return res.render('public/404.html', {});
Expand Down
12 changes: 12 additions & 0 deletions routes/stats.js
@@ -0,0 +1,12 @@
const Stats = require('../models/stats');

exports.monthly = function monthly(req, res, next) {
Stats.monthly(function (err, stats) {
if (err) return next(err);
const months = Object.keys(stats).map(function (month) {
return { month: month, count: stats[month] };
}).reverse();
req.stats = months;
return next();
});
};
60 changes: 60 additions & 0 deletions tests/stats-model.test.js
@@ -0,0 +1,60 @@
const test = require('./');
const db = require('../models');
const BadgeInstance = require('../models/badge-instance');
const Stats = require('../models/stats');
const util = require('../lib/util');

test.applyFixtures({
'instance': new BadgeInstance({
issuedOn: new Date('2012-10-15'),
user: 'brian@example.org',
hash: 'hash',
badge: 'link-advanced',
assertion: '{ "assertion" : "yep" }',
}),
'instance2': new BadgeInstance({
issuedOn: new Date('2012-11-15'),
user: 'brian@example.org',
hash: 'hash',
badge: 'link-hyper-advanced',
assertion: '{ "assertion" : "yep" }',
}),
'instance3': new BadgeInstance({
issuedOn: new Date('2012-12-15'),
user: 'brian-delete@example.org',
hash: 'hash',
badge: 'link-hyper-advanced',
assertion: '{ "assertion" : "yep" }',
}),
'instance4': new BadgeInstance({
issuedOn: new Date('2013-01-15'),
user: 'brian-delete@example.org',
hash: 'otherhash',
badge: 'link-turbo-advanced',
assertion: '{ "assertion" : "yep" }',
}),
'instance5': new BadgeInstance({
issuedOn: new Date('2013-01-16'),
user: 'brian-delete@example.org',
hash: 'otherhash',
badge: 'link-mega-advanced',
assertion: '{ "assertion" : "yep" }',
}),
}, function (fixtures) {
test('Stats.monthly', function (t) {
Stats.monthly(function (err, stats) {
t.notOk(err, 'should not have an error');
t.same(stats['2011-01'], undefined, 'should not have badges for jan 2011');
t.same(stats['2012-10'], 1, 'should have one badge');
t.same(stats['2012-11'], 1, 'should have one badge');
t.same(stats['2012-12'], 1, 'should have one badge');
t.same(stats['2013-01'], 2, 'should have two badges');
t.end();
});
});

// necessary to stop the test runner
test('shutting down #', function (t) {
db.close(); t.end();
});
})
17 changes: 17 additions & 0 deletions views/admin/stats.html
@@ -0,0 +1,17 @@
{% extends "admin/base.html" %}
{% block main %}

<h1>Statistics</h1>

<ul>
{% for stat in stats %}
<li>
<dl>
<dt>{{ stat.month }}</dt>
<dd>{{ stat.count }} badges issued</dd>
</dl>
</li>
{% endfor %}
</ul>

{% endblock %}

0 comments on commit 568333a

Please sign in to comment.