Files
shields/services/github/github-downloads.service.js
Paul Melnikow 47e8cc3de3 Refactor route functions in BaseService (#2860)
The route helper functions are fairly well isolated from the rest of BaseService, with a few convenient entry points. They are easier to test in isolation.

The way the code was written before, `pathToRegexp` was invoked once for every request, which seems inefficient.

`route` was validated when it was used, though it seems more helpful to validate it up front.

This breaks out `_makeFullUrl`, `_regex`, `_regexFromPath` into new helper functions `makeFullUrl`, `assertValidRoute`, `prepareRoute`, and `namedParamsForMatch`.

It adds validation to route, and updates the services without patterns to include one, in order to pass the new validation rules.
2019-01-26 02:38:12 -05:00

229 lines
6.2 KiB
JavaScript

'use strict'
const LegacyService = require('../legacy-service')
const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
const { makeLogo: getLogo } = require('../../lib/logos')
const { metric } = require('../../lib/text-formatters')
const {
documentation,
checkErrorResponse: githubCheckErrorResponse,
} = require('./github-helpers')
// This legacy service should be rewritten to use e.g. BaseJsonService.
//
// Tips for rewriting:
// https://github.com/badges/shields/blob/master/doc/rewriting-services.md
//
// Do not base new services on this code.
module.exports = class GithubDownloads extends LegacyService {
static get category() {
return 'downloads'
}
static get route() {
return {
base: 'github',
pattern: '',
}
}
static get examples() {
return [
{
title: 'GitHub All Releases',
pattern: 'downloads/:user/:repo/total',
namedParams: {
user: 'atom',
repo: 'atom',
},
staticPreview: {
label: 'downloads',
message: '857k total',
color: 'brightgreen',
},
documentation,
},
{
title: 'GitHub Releases',
pattern: 'downloads/:user/:repo/:tag/total',
namedParams: {
user: 'atom',
repo: 'atom',
tag: 'latest',
},
staticPreview: {
label: 'downloads',
message: '27k',
color: 'brightgreen',
},
documentation,
},
{
title: 'GitHub Pre-Releases',
pattern: 'downloads-pre/:user/:repo/:tag/total',
namedParams: {
user: 'atom',
repo: 'atom',
tag: 'latest',
},
staticPreview: {
label: 'downloads',
message: '2k',
color: 'brightgreen',
},
documentation,
},
{
title: 'GitHub Releases (by Release)',
pattern: 'downloads/:user/:repo/:tag/total',
namedParams: {
user: 'atom',
repo: 'atom',
tag: 'v0.190.0',
},
staticPreview: {
label: 'downloads',
message: '490k v0.190.0',
color: 'brightgreen',
},
documentation,
},
{
title: 'GitHub Releases (by Asset)',
pattern: 'downloads/:user/:repo/:tag/:path',
namedParams: {
user: 'atom',
repo: 'atom',
tag: 'latest',
path: 'atom-amd64.deb',
},
staticPreview: {
label: 'downloads',
message: '3k [atom-amd64.deb]',
color: 'brightgreen',
},
documentation,
},
{
title: 'GitHub Pre-Releases (by Asset)',
pattern: 'downloads-pre/:user/:repo/:tag/:path',
namedParams: {
user: 'atom',
repo: 'atom',
tag: 'latest',
path: 'atom-amd64.deb',
},
staticPreview: {
label: 'downloads',
message: '237 [atom-amd64.deb]',
color: 'brightgreen',
},
documentation,
},
]
}
static registerLegacyRouteHandler({ camp, cache, githubApiProvider }) {
camp.route(
/^\/github\/(downloads|downloads-pre)\/([^/]+)\/([^/]+)(\/.+)?\/([^/]+)\.(svg|png|gif|jpg|json)$/,
cache((data, match, sendBadge, request) => {
const type = match[1] // downloads or downloads-pre
const user = match[2] // eg, qubyte/rubidium
const repo = match[3]
let tag = match[4] // eg, v0.190.0, latest, null if querying all releases
const assetName = match[5].toLowerCase() // eg. total, atom-amd64.deb, atom.x86_64.rpm
const format = match[6]
if (tag) {
tag = tag.slice(1)
}
let total = true
if (tag) {
total = false
}
let apiUrl = `/repos/${user}/${repo}/releases`
if (!total) {
const releasePath =
tag === 'latest'
? type === 'downloads'
? 'latest'
: ''
: `tags/${tag}`
if (releasePath) {
apiUrl = `${apiUrl}/${releasePath}`
}
}
const badgeData = getBadgeData('downloads', data)
if (badgeData.template === 'social') {
badgeData.logo = getLogo('github', data)
}
githubApiProvider.request(request, apiUrl, {}, (err, res, buffer) => {
if (
githubCheckErrorResponse(
badgeData,
err,
res,
'repo or release not found'
)
) {
sendBadge(format, badgeData)
return
}
try {
let data = JSON.parse(buffer)
if (type === 'downloads-pre' && tag === 'latest') {
data = data[0]
}
let downloads = 0
const labelWords = []
if (total) {
data.forEach(tagData => {
tagData.assets.forEach(asset => {
if (
assetName === 'total' ||
assetName === asset.name.toLowerCase()
) {
downloads += asset.download_count
}
})
})
labelWords.push('total')
if (assetName !== 'total') {
labelWords.push(`[${assetName}]`)
}
} else {
data.assets.forEach(asset => {
if (
assetName === 'total' ||
assetName === asset.name.toLowerCase()
) {
downloads += asset.download_count
}
})
if (tag !== 'latest') {
labelWords.push(tag)
}
if (assetName !== 'total') {
labelWords.push(`[${assetName}]`)
}
}
labelWords.unshift(metric(downloads))
badgeData.text[1] = labelWords.join(' ')
badgeData.colorscheme = 'brightgreen'
sendBadge(format, badgeData)
} catch (e) {
badgeData.text[1] = 'none'
sendBadge(format, badgeData)
}
})
})
)
}
}