diff --git a/frontend/fragments/try-footer.html b/frontend/fragments/try-footer.html index 0982cfea4f3f2..5684d355ac636 100644 --- a/frontend/fragments/try-footer.html +++ b/frontend/fragments/try-footer.html @@ -1,6 +1,8 @@

Your Badge

+

Static

+
@@ -49,6 +51,27 @@

Your Badge

ff69b4

+

Dynamic

+ + + + + + + + + + + + +
+ +

+/badge/dynamic/<TYPE>.svg?uri=<URI>&label=<LABEL>&query=<$.DATA.SUBDATA>&colorB=<COLOR>&prefix=<PREFIX>&suffix=<SUFFIX> +

+
+

Styles

The following styles are available (flat is the default as of Feb 1st 2015): @@ -448,6 +471,18 @@

Like This?

document.location = url; } +function generateDynamicImage() { + var url = document.getElementById('imgUrlPrefix').textContent; + url += 'dynamic/' + escapeField(dynamicImageMaker.type.value); + url += '.svg?label=' + escapeField(dynamicImageMaker.label.value); + url += '&colorB=' + escapeField(dynamicImageMaker.color.value); + url += '&prefix=' + escapeField(dynamicImageMaker.prefix.value); + url += '&suffix=' + escapeField(dynamicImageMaker.suffix.value); + url += '&query=' + dynamicImageMaker.query.value; + url += '&uri=' + escapeField(dynamicImageMaker.uri.value); + document.location = url; +} + function escapeField(s) { return encodeURIComponent(s.replace(/-/g, '--').replace(/_/g, '__')); } diff --git a/package.json b/package.json index 190498055cf5c..12328e6c4456f 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "dot": "~1.1.2", "gm": "^1.23.0", "json-autosave": "~1.1.2", + "jsonpath": "~0.2.12", "lodash.countby": "^4.6.0", "moment": "^2.18.1", "pdfkit": "~0.8.0", diff --git a/server.js b/server.js index 1a8982d820975..407f1a319ce46 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,7 @@ 'use strict'; const countBy = require('lodash.countby'); +const jp = require('jsonpath'); const path = require('path'); const prettyBytes = require('pretty-bytes'); const queryString = require('query-string'); @@ -7139,6 +7140,50 @@ camp.route(/^\/maven-metadata\/v\/(https?)\/(.+\.xml)\.(svg|png|gif|jpg|json)$/, }); })); +// User defined sources - JSON response +camp.route(/^\/badge\/dynamic\/(json)\.(svg|png|gif|jpg|json)$/, +cache({ + queryParams: ['uri', 'query', 'prefix', 'suffix'], + handler: function(query, match, sendBadge, request) { + var type = match[1]; + var format = match[2]; + var prefix = query.prefix || ''; + var suffix = query.suffix || ''; + var pathExpression = query.query; + + var badgeData = getBadgeData('custom badge', query); + + if (!query.uri){ + badgeData.text[1] = 'no uri specified'; + sendBadge(format, badgeData); + return; + } + var uri = encodeURI(decodeURIComponent(query.uri)); + + request(uri, (err, res, data) => { + try { + if (res && res.statusCode === 404) + throw 'invalid resource'; + + if (err != null || !res || res.statusCode !== 200) + throw 'inaccessible'; + + switch (type){ + case 'json': + data = (typeof data == 'object' ? data : JSON.parse(data)); + badgeData.text[1] = (prefix || '') + jp.query(data, pathExpression).join(', ') + (suffix || ''); + break; + } + } catch(e) { + badgeData.colorB = 'lightgrey'; + badgeData.text[1] = e; + } finally { + sendBadge(format, badgeData); + } + }); + } +})); + // nsp for npm packages camp.route(/^\/nsp\/npm\/(?:@([^/]+)?\/)?([^/]+)?(?:\/([^/]+)?)?\.(svg|png|gif|jpg|json)?$/, cache((data, match, sendBadge, request) => { // A: /nsp/npm/:package.:format diff --git a/service-tests/json.js b/service-tests/json.js new file mode 100644 index 0000000000000..0861b0c78308e --- /dev/null +++ b/service-tests/json.js @@ -0,0 +1,42 @@ +'use strict'; + +const Joi = require('joi'); +const ServiceTester = require('./runner/service-tester'); + +const t = new ServiceTester({ id: 'badge/dynamic/json', title: 'User Defined JSON Source Data' }); +module.exports = t; + +t.create('Connection error') + .get('.json?uri=https://github.com/badges/shields/raw/master/package.json&query=$.name&label=Package Name') + .networkOff() + .expectJSON({ name: 'Package Name', value: 'inaccessible' }); + +t.create('No URI specified') + .get('.json?query=$.name&label=Package Name') + .expectJSON({ name: 'Package Name', value: 'no uri specified' }); + +t.create('JSON from uri') + .get('.json?uri=https://github.com/badges/shields/raw/master/package.json&query=$.name') + .expectJSON({ name: 'custom badge', value: 'gh-badges'}); + +t.create('JSON from uri | caching with new query params') + .get('.json?uri=https://github.com/badges/shields/raw/master/package.json&query=$.version') + .expectJSONTypes(Joi.object().keys({ + name: 'custom badge', + value: Joi.string().regex(/^\d+(\.\d+)?(\.\d+)?$/) + })); + +t.create('JSON from uri | with prefix & suffix & label') + .get('.json?uri=https://github.com/badges/shields/raw/master/package.json&query=$.version&prefix=v&suffix= dev&label=Shields') + .expectJSONTypes(Joi.object().keys({ + name: 'Shields', + value: Joi.string().regex(/^v\d+(\.\d+)?(\.\d+)?\sdev$/) + })); + +t.create('JSON from uri | object doesnt exist') + .get('.json?uri=https://github.com/badges/shields/raw/master/package.json&query=$.does_not_exist') + .expectJSON({ name: 'custom badge', value: '' }); + +t.create('JSON from uri | invalid uri') + .get('.json?uri=https://github.com/badges/shields/raw/master/notafile.json&query=$.version') + .expectJSON({ name: 'custom badge', value: 'invalid resource' });