diff --git a/services/wordpress/wordpress-downloads.service.js b/services/wordpress/wordpress-downloads.service.js index 8728caa45f1fdef0f4cd32df5b378e5aa42904bc..f931cf41b09f2e7059663243dd8c99cef21a2e98 100644 --- a/services/wordpress/wordpress-downloads.service.js +++ b/services/wordpress/wordpress-downloads.service.js @@ -4,7 +4,7 @@ const Joi = require('@hapi/joi') const { metric } = require('../text-formatters') const { downloadCount } = require('../color-formatters') const BaseWordpress = require('./wordpress-base') -const { BaseJsonService, NotFound } = require('..') +const { NotFound } = require('..') const dateSchema = Joi.object() .pattern(Joi.date().iso(), Joi.number().integer()) @@ -21,6 +21,29 @@ const extensionData = { }, } +const intervalMap = { + dd: { + limit: 1, + messageSuffix: '/day', + }, + dw: { + limit: 7, + messageSuffix: '/week', + }, + dm: { + limit: 30, + messageSuffix: '/month', + }, + dy: { + limit: 365, + messageSuffix: '/year', + }, + dt: { + limit: null, + messageSuffix: '', + }, +} + function DownloadsForExtensionType(extensionType) { const { capt, exampleSlug } = extensionData[extensionType] @@ -35,8 +58,8 @@ function DownloadsForExtensionType(extensionType) { static get route() { return { - base: `wordpress/${extensionType}/dt`, - pattern: ':slug', + base: `wordpress/${extensionType}`, + pattern: ':interval(dd|dw|dm|dy|dt)/:slug', } } @@ -44,8 +67,8 @@ function DownloadsForExtensionType(extensionType) { return [ { title: `WordPress ${capt} Downloads`, - namedParams: { slug: exampleSlug }, - staticPreview: this.render({ downloads: 200000 }), + namedParams: { interval: 'dm', slug: exampleSlug }, + staticPreview: this.render({ interval: 'dm', downloads: 200000 }), }, ] } @@ -54,19 +77,50 @@ function DownloadsForExtensionType(extensionType) { return { label: 'downloads' } } - static render({ downloads }) { + static render({ interval, downloads }) { + const { messageSuffix } = intervalMap[interval] + return { - message: metric(downloads), + message: `${metric(downloads)}${messageSuffix}`, color: downloadCount(downloads), } } - async handle({ slug }) { - const { downloaded: downloads } = await this.fetch({ - extensionType, - slug, - }) - return this.constructor.render({ downloads }) + async handle({ interval, slug }) { + const { limit } = intervalMap[interval] + let downloads + if (limit === null) { + const { downloaded: _downloads } = await this.fetch({ + extensionType, + slug, + }) + downloads = _downloads + } else { + const ext_type = extensionType === 'plugin' ? 'plugin' : 'themes' + const json = await this._requestJson({ + schema: dateSchema, + url: `https://api.wordpress.org/stats/${ext_type}/1.0/downloads.php`, + options: { + qs: { + slug, + limit, + }, + }, + }) + const size = Object.keys(json).length + downloads = Object.values(json).reduce( + (a, b) => parseInt(a) + parseInt(b) + ) + // This check is for non-existent and brand-new plugins both having new stats. + // Non-Existent plugins results are the same as a brandspanking new plugin with no downloads. + if (downloads <= 0 && size <= 1) { + throw new NotFound({ + prettyMessage: `${extensionType} not found or too new`, + }) + } + } + + return this.constructor.render({ interval, downloads }) } } } @@ -121,100 +175,7 @@ function InstallsForExtensionType(extensionType) { } } -function DownloadsForInterval(interval) { - const { base, messageSuffix = '', query, name } = { - day: { - base: 'wordpress/plugin/dd', - messageSuffix: '/day', - query: 1, - name: 'WordpressDownloadsDay', - }, - week: { - base: 'wordpress/plugin/dw', - messageSuffix: '/week', - query: 7, - name: 'WordpressDownloadsWeek', - }, - month: { - base: 'wordpress/plugin/dm', - messageSuffix: '/month', - query: 30, - name: 'WordpressDownloadsMonth', - }, - year: { - base: 'wordpress/plugin/dy', - messageSuffix: '/year', - query: 365, - name: 'WordpressDownloadsYear', - }, - }[interval] - - return class WordpressDownloads extends BaseJsonService { - static get name() { - return name - } - - static get category() { - return 'downloads' - } - - static get route() { - return { - base, - pattern: ':slug', - } - } - - static get examples() { - return [ - { - title: 'WordPress Plugin Downloads', - namedParams: { slug: 'bbpress' }, - staticPreview: this.render({ downloads: 30000 }), - }, - ] - } - - static get defaultBadgeData() { - return { label: 'downloads' } - } - - static render({ downloads }) { - return { - message: `${metric(downloads)}${messageSuffix}`, - color: downloadCount(downloads), - } - } - - async handle({ slug }) { - const json = await this._requestJson({ - schema: dateSchema, - url: `https://api.wordpress.org/stats/plugin/1.0/downloads.php`, - options: { - qs: { - slug, - limit: query, - }, - }, - }) - const size = Object.keys(json).length - const downloads = Object.values(json).reduce( - (a, b) => parseInt(a) + parseInt(b) - ) - // This check is for non-existent and brand-new plugins both having new stats. - // Non-Existent plugins results are the same as a brandspanking new plugin with no downloads. - if (downloads <= 0 && size <= 1) { - throw new NotFound({ prettyMessage: 'plugin not found or too new' }) - } - return this.constructor.render({ downloads }) - } - } -} - -const intervalServices = ['day', 'week', 'month', 'year'].map( - DownloadsForInterval -) const downloadServices = ['plugin', 'theme'].map(DownloadsForExtensionType) const installServices = ['plugin', 'theme'].map(InstallsForExtensionType) -const modules = [...intervalServices, ...downloadServices, ...installServices] +const modules = [...downloadServices, ...installServices] module.exports = modules diff --git a/services/wordpress/wordpress-downloads.tester.js b/services/wordpress/wordpress-downloads.tester.js index 1bdc79b20bb2b0a4048b80f80469f2e1e6377283..a455dbc8aea751c6f31a3242688f1929eabd9192 100644 --- a/services/wordpress/wordpress-downloads.tester.js +++ b/services/wordpress/wordpress-downloads.tester.js @@ -15,6 +15,7 @@ t.create('Plugin Downloads - Total') label: 'downloads', message: isMetric, }) + t.create('Plugin Downloads - Active') .get('/plugin/installs/akismet.json') .expectBadge({ @@ -43,12 +44,20 @@ t.create('Plugin Downloads - Month') message: isMetricOverTimePeriod, }) +t.create('Plugin Downloads - Year') + .get('/plugin/dy/akismet.json') + .expectBadge({ + label: 'downloads', + message: isMetricOverTimePeriod, + }) + t.create('Theme Downloads - Total') .get('/theme/dt/twentyseventeen.json') .expectBadge({ label: 'downloads', message: isMetric, }) + t.create('Theme Downloads - Active') .get('/theme/installs/twentyseventeen.json') .expectBadge({ @@ -56,12 +65,41 @@ t.create('Theme Downloads - Active') message: isMetric, }) +t.create('Theme Downloads - Day') + .get('/theme/dd/twentyseventeen.json') + .expectBadge({ + label: 'downloads', + message: isMetricOverTimePeriod, + }) + +t.create('Theme Downloads - Week') + .get('/theme/dw/twentyseventeen.json') + .expectBadge({ + label: 'downloads', + message: isMetricOverTimePeriod, + }) + +t.create('Theme Downloads - Month') + .get('/theme/dm/twentyseventeen.json') + .expectBadge({ + label: 'downloads', + message: isMetricOverTimePeriod, + }) + +t.create('Theme Downloads - Year') + .get('/theme/dy/twentyseventeen.json') + .expectBadge({ + label: 'downloads', + message: isMetricOverTimePeriod, + }) + t.create('Plugin Downloads - Total | Not Found') .get('/plugin/dt/100.json') .expectBadge({ label: 'downloads', message: 'not found', }) + t.create('Plugin Downloads - Active | Not Found') .get('/plugin/installs/100.json') .expectBadge({ @@ -90,15 +128,51 @@ t.create('Plugin Downloads - Month | Not Found') message: 'plugin not found or too new', }) +t.create('Plugin Downloads - Year | Not Found') + .get('/plugin/dy/100.json') + .expectBadge({ + label: 'downloads', + message: 'plugin not found or too new', + }) + t.create('Theme Downloads - Total | Not Found') .get('/theme/dt/100.json') .expectBadge({ label: 'downloads', message: 'not found', }) + t.create('Theme Downloads - Active | Not Found') .get('/theme/installs/100.json') .expectBadge({ label: 'active installs', message: 'not found', }) + +t.create('Theme Downloads - Day | Not Found') + .get('/theme/dd/100.json') + .expectBadge({ + label: 'downloads', + message: 'theme not found or too new', + }) + +t.create('Theme Downloads - Week | Not Found') + .get('/theme/dw/100.json') + .expectBadge({ + label: 'downloads', + message: 'theme not found or too new', + }) + +t.create('Theme Downloads - Month | Not Found') + .get('/theme/dm/100.json') + .expectBadge({ + label: 'downloads', + message: 'theme not found or too new', + }) + +t.create('Theme Downloads - Year | Not Found') + .get('/theme/dy/100.json') + .expectBadge({ + label: 'downloads', + message: 'theme not found or too new', + })