Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[badge/dynamic/json] User defined JSON source badge #820

Merged
merged 33 commits into from
Nov 1, 2017
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7eed1ca
Add User Defined URL support
RedSparr0w Oct 26, 2016
7765ce2
Merge remote-tracking branch 'refs/remotes/badges/master' into custom…
RedSparr0w Oct 30, 2016
7058fc0
Merge remote-tracking branch 'refs/remotes/badges/master' into custom…
RedSparr0w Nov 24, 2016
57639f7
Merge branch 'master' into custom_source
RedSparr0w Sep 22, 2017
bd02eac
Add test
RedSparr0w Sep 23, 2017
9659051
eslint fixes
RedSparr0w Sep 23, 2017
e6813cc
100% coverage
RedSparr0w Sep 23, 2017
ff7ce12
use JSONpath
RedSparr0w Oct 3, 2017
1895b5d
update try.html
RedSparr0w Oct 3, 2017
a792fe7
Update tests, restore prefix & suffix
RedSparr0w Oct 3, 2017
fe99975
order dependencies alphabetically
RedSparr0w Oct 3, 2017
ac1506f
update jsonpath version dependency
RedSparr0w Oct 4, 2017
339092e
update url structure & move to query strings
RedSparr0w Oct 4, 2017
1d83608
Merge branch 'master' into custom_source
RedSparr0w Oct 4, 2017
49260e4
update error handling & remove xml refrences
RedSparr0w Oct 4, 2017
476c6d8
fix eslint errors
RedSparr0w Oct 4, 2017
c90ba38
update tests
RedSparr0w Oct 17, 2017
a662287
Merge branch 'master' into custom_source
RedSparr0w Oct 17, 2017
3aa5abf
Merge remote-tracking branch 'refs/remotes/badges/master' into custom…
RedSparr0w Oct 18, 2017
6444481
update dynamic badge generator
RedSparr0w Oct 19, 2017
f162211
url -> uri & decode uri
RedSparr0w Oct 20, 2017
a3aa1e5
Merge remote-tracking branch 'refs/remotes/badges/master' into custom…
RedSparr0w Oct 30, 2017
695be9d
resolve conflicts
RedSparr0w Oct 30, 2017
0dd37d2
update for new page generation
RedSparr0w Oct 31, 2017
19e48ab
check uri is defined
RedSparr0w Oct 31, 2017
6841fa2
add query params to `request-handler.js`
RedSparr0w Oct 31, 2017
e27159f
eslint fixes
RedSparr0w Oct 31, 2017
c497f95
add test for no uri specified
RedSparr0w Oct 31, 2017
d841039
move query params to be local to dynamic badge
RedSparr0w Oct 31, 2017
f396d7f
update tests
RedSparr0w Oct 31, 2017
ea0619c
dynamic badge gen use same base url as static badge
RedSparr0w Oct 31, 2017
346dc25
Merge branch 'master' into custom_source
RedSparr0w Oct 31, 2017
9075290
Merge branch 'master' into custom_source
RedSparr0w Oct 31, 2017
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
34 changes: 34 additions & 0 deletions frontend/fragments/try-footer.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

<h2 id="your-badge"> Your Badge </h2>

<h3 id="static-badge"> Static </h3>

<form action='javascript:makeImage()' id='imageMaker'>
<input class='short' name='subject' placeholder='subject'/>
<input class='short' name='status' placeholder='status'/>
Expand Down Expand Up @@ -49,6 +51,27 @@ <h2 id="your-badge"> Your Badge </h2>
<img src="/badge/color-ff69b4-ff69b4.svg" alt='ff69b4'/>
</p>

<h3 id="dynamic-badge"> Dynamic </h3>

<form action='javascript:generateDynamicImage()' id='dynamicImageMaker'>
<input class='short' name='type' list='dynamic-type' placeholder='type'/>
<datalist id='dynamic-type'>
<option value='json'>
</datalist>
<input class='short' name='label' placeholder='label'/>
<input class='short' name='uri' placeholder='uri'/>
<input class='short' name='query' placeholder='$.data.subdata'/>
<input class='short' name='color' placeholder='hex color'/>
<input class='short' name='prefix' placeholder='prefix'/>
<input class='short' name='suffix' placeholder='suffix'/>
<button>Generate</button>
</form>

<p>
<code>/badge/dynamic/&lt;TYPE&gt;.svg?uri=&lt;URI&gt;&amp;label=&lt;LABEL&gt;&amp;query=&lt;<a href="https://www.npmjs.com/package/jsonpath" target="_BLANK" title="JSONdata syntax">$.DATA.SUBDATA</a>&gt;&amp;colorB=&lt;COLOR&gt;&amp;prefix=&lt;PREFIX&gt;&amp;suffix=&lt;SUFFIX&gt;</code>
</p>
<hr class='spacing'/>

<h2 id="styles"> Styles </h2>
<p>
The following styles are available (flat is the default as of Feb 1st 2015):
Expand Down Expand Up @@ -448,6 +471,17 @@ <h2 id="like-this"> Like This? </h2>
document.location = url;
}

function generateDynamicImage() {
var url = '/badge/dynamic/' + escapeField(dynamicImageMaker.type.value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you want to start with the var url = document.getElementById('imgUrlPrefix').textContent line from makeImage() above. Otherwise it will try to serve from shields.io instead of img.shields.io in production.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To test this you can run make website. The dynamic badge won't work of course, though you should be able to confirm that it's generating URLs that begin with https://img.shields.io/.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah did not think about that, i updated it to match the static badge function.

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=' + dynamicImageMaker.uri.value;
document.location = url;
}

function escapeField(s) {
return encodeURIComponent(s.replace(/-/g, '--').replace(/_/g, '__'));
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
45 changes: 45 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ var githubAuth = require('./lib/github-auth');
var queryString = require('query-string');
var prettyBytes = require('pretty-bytes');
var xml2js = require('xml2js');
var jp = require('jsonpath');
var serverSecrets = require('./lib/server-secrets');
log(tryUrl);

Expand Down Expand Up @@ -7109,6 +7110,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
Expand Down
48 changes: 48 additions & 0 deletions service-tests/json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'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: Joi.equal('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: Joi.equal('Shields'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can replace Joi.equal('Shields') with a bare literal 'Shields'.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know!

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')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('custom badge'),
value: Joi.equal('')
}));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these are both literals, you can simplify this:

.expectJSON({ name: 'custom badge', value: '' })

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, did not see that.


t.create('JSON from uri | invalid uri')
.get('.json?uri=https://github.com/badges/shields/raw/master/notafile.json&query=$.version')
.expectJSONTypes(Joi.object().keys({
name: Joi.equal('custom badge'),
value: Joi.equal('invalid resource')
}));