Skip to content

Commit

Permalink
Indaba api (#36)
Browse files Browse the repository at this point in the history
* Initial embedable views
* Initial router logic for embedable views
* Use Indaba and update the cache once every 6 months
* Add open-budget-indaba-client and bump gulp-imagemin
* Remove unnecessary Indaba JSON
* Update node version
* Use okfn repo for open-budget-indaba-client
  • Loading branch information
dumyan authored and pwalsh committed Sep 1, 2016
1 parent d8866f5 commit 72e4222
Show file tree
Hide file tree
Showing 8 changed files with 632 additions and 18 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: node_js
node_js:
- "0.10"
- "6.5.0"
script:
- npm test
- npm run coverage
25 changes: 9 additions & 16 deletions api.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
var request = require('request');
var fs = require('fs');

var uri = 'http://obstracker.internationalbudget.org/';
// Sets the cache age to an hour
var cache_age = 3600000;
var Indaba = require('open-budget-indaba-client').default.Indaba;
var moment = require('moment');

function api_call (endpoint, callback) {
var cache_file = './cache/'+endpoint+'.json';
Expand All @@ -14,8 +11,8 @@ function api_call (endpoint, callback) {
should_update_cache = false;
should_get_from_cache = true;
var stat = fs.statSync(cache_file);
var difference = new Date().getTime() - stat.mtime.getTime();
if (difference > cache_age) {
var months = moment().diff(new Date(stat.mtime), 'months');
if (months >= 6) {
should_update_cache = true;
should_get_from_cache = false;
}
Expand All @@ -24,16 +21,12 @@ function api_call (endpoint, callback) {
var data = fs.readFileSync(cache_file);
callback(JSON.parse(data));
} else {
var url = uri+endpoint+'.json';
request(url, function (error, response, data) {
if (!error && response.statusCode == 200) {
if (should_update_cache) {
fs.writeFileSync(cache_file, data);
}
callback(JSON.parse(data));
} else {
console.log(error);

Indaba.getTrackerJSON().then( function (res) {
if (should_update_cache) {
fs.writeFileSync(cache_file, JSON.stringify(res));
}
callback(res);
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"gulp-clean": "0.3.1",
"gulp-concat": "2.3.4",
"gulp-extend": "0.2.0",
"gulp-imagemin": "0.6.2",
"gulp-imagemin": "3.0.3",
"gulp-less": "1.3.3",
"gulp-minify-css": "0.3.7",
"gulp-rev": "1.0.0",
Expand All @@ -34,6 +34,7 @@
"imagemin-pngquant": "^5.0.0",
"moment": "2.8.1",
"morgan": "~1.0.0",
"open-budget-indaba-client": "git+https://github.com/okfn/open-budget-indaba-client.git",
"request": "~2.39.0",
"swig": "~1.4.2",
"underscore": "~1.8.3"
Expand Down
113 changes: 113 additions & 0 deletions routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,46 @@ router.get('/country/:country', function (req, res) {
});
});

router.get('/country/:country/embed', function (req, res) {
api.call('countries', function (countries) {
var country = {};
for (var i in countries) {
if (countries[i].country == req.params.country) {
country = countries[i];
break;
}
}
country.snapshots = _.sortBy(country.snapshots, function(obj) {
return -obj.date;
});

// Override country if needed (e.g. discontinued countries)
if (country.country in country_override) {
var documents = _.indexBy(_.pluck(docs, 'title'));
documents = _.mapObject(documents, function(value){
return country_override[country.country].value;
});
var this_year = ''+(new Date).getFullYear();
var overwritten = {};
overwritten[this_year] = documents;
country.snapshots = _.map(country.snapshots, function(obj) {
if (new Date(obj.date) > country_override[country.country].date) {
obj.snapshot = overwritten;
}
return obj;
});
country.message = country_override[country.country].message;
}

res.render('country_embed', {
'docs': docs,
'country': country,
'EXPLORER_URL': process.env.EXPLORER_URL
});
});
});


router.get('/status/:country', function (req, res) {
api.call('countries', function (countries) {
var country = {};
Expand Down Expand Up @@ -119,6 +159,36 @@ router.get('/status/:country', function (req, res) {
});
});

router.get('/status/:country/embed', function (req, res) {
api.call('countries', function (countries) {
var country = {};
for (var i in countries) {
if (countries[i].country == req.params.country) {
country = countries[i];
break;
}
}

// Override country if needed (e.g. discontinued countries)
if (country.country in country_override) {
var documents = _.indexBy(_.pluck(docs, 'title'));
documents = _.mapObject(documents, function(value){
return country_override[country.country].value;
});
var this_year = ''+(new Date).getFullYear();
country.documents = {};
country.documents[this_year] = documents;
country.message = country_override[country.country].message;
}

res.render('status_embed', {
'docs': docs,
'country': country,
'EXPLORER_URL': process.env.EXPLORER_URL
});
});
});

router.get('/datagathering', function (req, res) {
res.render('gathering', {});
});
Expand Down Expand Up @@ -220,6 +290,11 @@ router.get('/locale/:locale', function (req, res) {
res.redirect('/');
});

router.get('/locale/:locale/embed', function (req, res) {
res.cookie('obstracker_language', req.params.locale, { maxAge: 900000 })
res.redirect('/embed');
});

router.get('/', function (req, res) {
api.call('countries', function (countries) {
// If today is less than the 22nd of the month the data is from
Expand Down Expand Up @@ -256,4 +331,42 @@ router.get('/', function (req, res) {
});
});

router.get('/embed', function (req, res) {
api.call('countries', function (countries) {
// If today is less than the 22nd of the month the data is from
// the last date of two months ago else it's from last date of one
// month ago
var last_update = new Date();
if (last_update.getDate() < 22) {
last_update = new Date(last_update.getFullYear(),
last_update.getMonth()-1, 0);
}
else {
last_update = new Date(last_update.getFullYear(),
last_update.getMonth(), 0);
}

//Override countries (e.g. discontinued countries)
countries = _.map(countries, function(obj) {
if (obj.country in country_override) {
var documents = _.indexBy(_.pluck(docs, 'title'));
documents = _.mapObject(documents, function(value){
return country_override[obj.country].value;
});
obj.documents = {}
obj.documents[''+last_update.getFullYear()] = documents;
}
return obj;
});

res.render('index_embed', {
'docs': docs,
'countries': countries,
'last_update': last_update,
'EXPLORER_URL': process.env.EXPLORER_URL
});
});
});


module.exports = router;
141 changes: 141 additions & 0 deletions views/country_embed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
{% extends "layout_embed.html" %}
{% import "helpers.html" as h %}

{% block page_title %}{{ country.country + gettext(" - Open Budget Survey - Tracker") }}{% endblock %}

{% block content %}

<div class="row">
<div class="col-md-9">
<h1>{{ gettext(country.country) }}</h1>
{%- if country.message %}
<div class="alert alert-danger">{{ gettext(country.message) }}</div>
{% endif %}
<h2>{{ gettext("Open Budget Index") }} <small><a href="/about"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span></a></small></h2>
{% if country.obi_scores %}
<div class="table-responsive">
<table class="table">
<thead>
<tr>
{% for score in country.obi_scores %}
<th scope="row">{{ date_format(Date.parse(score.year), 'YYYY') }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for score in country.obi_scores %}
<td>{{ score.score }}</td>
{% endfor %}
</tr>
</tbody>
</table>
</div>
{% else %}
<p class="text-muted">{{ gettext('N/A -- This country was not included in the Open Budget Survey') }}</p>
{% endif %}
</div>
<div class="col-md-3">
<div class="row top20">
<a href="{{ country.library }}" target="_blank" class="btn btn-primary col-md-12">{{ gettext("View the Budget Library") }}</a>
</div>
<div class="row top5">
<a href="/status/{{ country.country }}/embed" class="btn btn-primary col-md-12">{{ gettext("View current status") }}</a>
</div>
</div>
</div>

<h2>{{ gettext("Historical Information") }}</h2>
<div class="panel panel-default">
<div id="heading" class="panel-heading">
<div class="text-right"{% if lang == 'ru'%} style="font-size:70%;"{% endif %}>
<strong>{{ gettext("Key") }}:</strong>
<span class="item">
<span class="badge state state-available"><span>{{ gettext("Publicly available") }}</span></span>
{{ gettext("Publicly available") }}
</span>
<span class="item">
<span class="badge state state-internal"><span>{{ gettext("Internally available") }}</span></span>
{{ gettext("Internal use only") }}
</span>
<span class="item">
<span class="badge state state-not-produced"><span>{{ gettext("Not produced") }}</span></span>
{{ gettext("Not produced") }} / {{ gettext("Published late") }}
</span>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover">
<colgroup>
<col width="16%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
<col width="10.5%">
</colgroup>
<thead>
<th></th>
{% set obi_latest = country.obi.availability|sort|last %}
{% for doc in docs %}
<th class="text-center" scope="row" data-toggle="popover" data-placement="top" data-content="{{ gettext(doc.description) }}"{% if lang == 'es' %} style="font-size:90%;"{% endif %}{% if lang == 'ru' %} style="font-size:70%;"{% endif %}>{{ gettext(doc.title) }}</th>
{% endfor %}
</thead>
<tbody>
{% for snapshot_obj in country.snapshots %}
{% set snapshot = snapshot_obj.snapshot %}
<tr>
<th>{{ date_format(Date.parse(snapshot_obj.date), 'MMM YYYY')|capitalize }}</th>
{% for doc in docs %}
{% set cell = undefined %}
{% for year in snapshot|reverse %}
{% if not cell %}
{% if doc.title in snapshot[year] %}
{% set cell = snapshot[year][doc.title]|first %}
{% endif %}
{% endif %}
{% endfor %}
<td class="text-center">
{% if cell %}
<div {% if cell.comments %}class="comment-cell"{% endif %}>
<span class="badge state state-{{ cell.state|replace(' ', '-') }}" data-toggle="popover" data-placement="top" data-content="{{ h.tooltip(country, cell) }}">
<span>{{ h.state(cell.state) }}</span>
</span>
{% if cell.comments %}
<span data-toggle="popover" data-placement="top" data-content="{{ cell.comments }}" class="text-info glyphicon glyphicon-comment"></span>
{% endif %}
{% else %}
<span class="badge state state-not-produced" data-placement="top" data-toggle="popover" data-content="{{ h.tooltip(country, doc) }}">
<span>{{ h.state("not produced") }}</span>
</span>
</div>
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
<tr class="info">
<th>OBS{% if obi_latest %} {{ date_format(Date.parse(obi_latest), 'YYYY') }}{% endif %}</th>
{% for doc in docs %}
<td class="text-center">
{% if obi_latest %}
{% set state = country.obi.availability[obi_latest][doc.title] %}
<span class="badge state state-{{ state|replace(' ', '-') }}" data-placement="top" data-toggle="popover" data-content="{{ h.state(state) }}">
<span>{{ h.state(state) }}</span>
</span>
{% else %}
<span class="badge state state-untracked" data-placement="top" data-toggle="popover" data-content="{{ gettext('Not tracked') }}">
<span>{{ gettext("Not tracked") }}</span>
</span>
{% endif %}
</td>
{% endfor %}
</tr>

</tbody>
</table>
</div>
{% endblock %}

0 comments on commit 72e4222

Please sign in to comment.