mirror of
https://github.com/badges/shields.git
synced 2025-04-18 19:44:04 +03:00
migrate some services from examples to openApi part 31; affects [packagecontrol discourse] (#9858)
* migrate some services from examples to openApi * update e2e test assertion
This commit is contained in:
parent
09c83d9d46
commit
a7f2396202
@ -25,7 +25,7 @@ describe('Frontend', function () {
|
||||
cy.contains('Build')
|
||||
cy.contains('Chat').click()
|
||||
|
||||
cy.contains('Discourse status')
|
||||
cy.contains('Discourse Status')
|
||||
cy.contains('Stack Exchange questions')
|
||||
})
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
import camelcase from 'camelcase'
|
||||
import Joi from 'joi'
|
||||
import { metric } from '../text-formatters.js'
|
||||
import { nonNegativeInteger, optionalUrl } from '../validators.js'
|
||||
import { BaseJsonService } from '../index.js'
|
||||
import { BaseJsonService, queryParams } from '../index.js'
|
||||
|
||||
const schemaSingular = Joi.object({
|
||||
topic_count: nonNegativeInteger,
|
||||
@ -24,17 +23,19 @@ const queryParamSchema = Joi.object({
|
||||
server: optionalUrl.required(),
|
||||
}).required()
|
||||
|
||||
function singular(variant) {
|
||||
return variant.slice(0, -1)
|
||||
}
|
||||
|
||||
const params = queryParams({
|
||||
name: 'server',
|
||||
example: 'https://meta.discourse.org',
|
||||
required: true,
|
||||
})
|
||||
|
||||
class DiscourseBase extends BaseJsonService {
|
||||
static category = 'chat'
|
||||
|
||||
static buildRoute(metric) {
|
||||
return {
|
||||
base: 'discourse',
|
||||
pattern: metric,
|
||||
queryParamSchema,
|
||||
}
|
||||
}
|
||||
|
||||
static defaultBadgeData = { label: 'discourse' }
|
||||
|
||||
async fetch({ server }) {
|
||||
@ -45,58 +46,61 @@ class DiscourseBase extends BaseJsonService {
|
||||
}
|
||||
}
|
||||
|
||||
function DiscourseMetricIntegrationFactory({ metricType }) {
|
||||
// We supply the singular form to more easily check against both schemas.
|
||||
// But, we use the plural form as the metric name for grammatical reasons.
|
||||
const metricName = `${metricType}s`
|
||||
return class DiscourseMetric extends DiscourseBase {
|
||||
// The space is needed so we get 'DiscourseTopics' rather than
|
||||
// 'Discoursetopics'. `camelcase()` removes it.
|
||||
static name = camelcase(`Discourse ${metricName}`, { pascalCase: true })
|
||||
static route = this.buildRoute(metricName)
|
||||
class DiscourseMetric extends DiscourseBase {
|
||||
static route = {
|
||||
base: 'discourse',
|
||||
pattern: ':variant(topics|users|posts|likes)',
|
||||
queryParamSchema,
|
||||
}
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: `Discourse ${metricName}`,
|
||||
namedParams: {},
|
||||
queryParams: {
|
||||
server: 'https://meta.discourse.org',
|
||||
},
|
||||
staticPreview: this.render({ stat: 100 }),
|
||||
},
|
||||
]
|
||||
static openApi = {
|
||||
'/discourse/topics': {
|
||||
get: { summary: 'Discourse Topics', parameters: params },
|
||||
},
|
||||
'/discourse/users': {
|
||||
get: { summary: 'Discourse Users', parameters: params },
|
||||
},
|
||||
'/discourse/posts': {
|
||||
get: { summary: 'Discourse Posts', parameters: params },
|
||||
},
|
||||
'/discourse/likes': {
|
||||
get: { summary: 'Discourse Likes', parameters: params },
|
||||
},
|
||||
}
|
||||
|
||||
static render({ stat }) {
|
||||
return {
|
||||
message: `${metric(stat)} ${metricName}`,
|
||||
color: 'brightgreen',
|
||||
}
|
||||
static render({ variant, stat }) {
|
||||
return {
|
||||
message: `${metric(stat)} ${variant}`,
|
||||
color: 'brightgreen',
|
||||
}
|
||||
}
|
||||
|
||||
async handle(_routeParams, { server }) {
|
||||
const data = await this.fetch({ server })
|
||||
// e.g. metricType == 'topic' --> try 'topic_count' then 'topics_count'
|
||||
let stat = data[`${metricType}_count`]
|
||||
if (stat === undefined) {
|
||||
stat = data[`${metricType}s_count`]
|
||||
}
|
||||
return this.constructor.render({ stat })
|
||||
async handle({ variant }, { server }) {
|
||||
const data = await this.fetch({ server })
|
||||
// e.g. variant == 'topics' --> try 'topic_count' then 'topics_count'
|
||||
let stat = data[`${singular(variant)}_count`]
|
||||
if (stat === undefined) {
|
||||
stat = data[`${variant}_count`]
|
||||
}
|
||||
return this.constructor.render({ variant, stat })
|
||||
}
|
||||
}
|
||||
|
||||
class DiscourseStatus extends DiscourseBase {
|
||||
static route = this.buildRoute('status')
|
||||
static examples = [
|
||||
{
|
||||
title: 'Discourse status',
|
||||
namedParams: {},
|
||||
queryParams: {
|
||||
server: 'https://meta.discourse.org',
|
||||
static route = {
|
||||
base: 'discourse',
|
||||
pattern: 'status',
|
||||
queryParamSchema,
|
||||
}
|
||||
|
||||
static openApi = {
|
||||
'/discourse/status': {
|
||||
get: {
|
||||
summary: 'Discourse Status',
|
||||
parameters: params,
|
||||
},
|
||||
staticPreview: this.render(),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
static render() {
|
||||
return {
|
||||
@ -113,11 +117,4 @@ class DiscourseStatus extends DiscourseBase {
|
||||
}
|
||||
}
|
||||
|
||||
const metricIntegrations = [
|
||||
{ metricType: 'topic' },
|
||||
{ metricType: 'user' },
|
||||
{ metricType: 'post' },
|
||||
{ metricType: 'like' },
|
||||
].map(DiscourseMetricIntegrationFactory)
|
||||
|
||||
export default [...metricIntegrations, DiscourseStatus]
|
||||
export default [DiscourseMetric, DiscourseStatus]
|
||||
|
@ -1,9 +1,7 @@
|
||||
import Joi from 'joi'
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { nonNegativeInteger } from '../validators.js'
|
||||
import { BaseJsonService } from '../index.js'
|
||||
|
||||
const keywords = ['sublime', 'sublimetext', 'packagecontrol']
|
||||
import { BaseJsonService, pathParams } from '../index.js'
|
||||
|
||||
const schema = Joi.object({
|
||||
installs: Joi.object({
|
||||
@ -20,92 +18,91 @@ const schema = Joi.object({
|
||||
}).required(),
|
||||
})
|
||||
|
||||
function DownloadsForInterval(downloadInterval) {
|
||||
const { base, interval, transform, name } = {
|
||||
day: {
|
||||
base: 'packagecontrol/dd',
|
||||
interval: 'day',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// use the downloads from yesterday
|
||||
downloads += platform.totals[1]
|
||||
})
|
||||
return downloads
|
||||
},
|
||||
name: 'PackageControlDownloadsDay',
|
||||
},
|
||||
week: {
|
||||
base: 'packagecontrol/dw',
|
||||
interval: 'week',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// total for the first 7 days
|
||||
for (let i = 0; i < 7; i++) {
|
||||
downloads += platform.totals[i]
|
||||
}
|
||||
})
|
||||
return downloads
|
||||
},
|
||||
name: 'PackageControlDownloadsWeek',
|
||||
},
|
||||
month: {
|
||||
base: 'packagecontrol/dm',
|
||||
interval: 'month',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// total for the first 30 days
|
||||
for (let i = 0; i < 30; i++) {
|
||||
downloads += platform.totals[i]
|
||||
}
|
||||
})
|
||||
return downloads
|
||||
},
|
||||
name: 'PackageControlDownloadsMonth',
|
||||
},
|
||||
total: {
|
||||
base: 'packagecontrol/dt',
|
||||
transform: resp => resp.installs.total,
|
||||
name: 'PackageControlDownloadsTotal',
|
||||
},
|
||||
}[downloadInterval]
|
||||
|
||||
return class PackageControlDownloads extends BaseJsonService {
|
||||
static name = name
|
||||
|
||||
static category = 'downloads'
|
||||
|
||||
static route = { base, pattern: ':packageName' }
|
||||
|
||||
static examples = [
|
||||
{
|
||||
title: 'Package Control',
|
||||
namedParams: { packageName: 'GitGutter' },
|
||||
staticPreview: renderDownloadsBadge({ downloads: 12000 }),
|
||||
keywords,
|
||||
},
|
||||
]
|
||||
|
||||
static defaultBadgeData = { label: 'downloads' }
|
||||
|
||||
async fetch({ packageName }) {
|
||||
const url = `https://packagecontrol.io/packages/${packageName}.json`
|
||||
return this._requestJson({ schema, url })
|
||||
}
|
||||
|
||||
async handle({ packageName }) {
|
||||
const data = await this.fetch({ packageName })
|
||||
return renderDownloadsBadge({
|
||||
downloads: transform(data),
|
||||
interval,
|
||||
const intervalMap = {
|
||||
dd: {
|
||||
label: 'day',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// use the downloads from yesterday
|
||||
downloads += platform.totals[1]
|
||||
})
|
||||
}
|
||||
}
|
||||
return downloads
|
||||
},
|
||||
},
|
||||
dw: {
|
||||
label: 'week',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// total for the first 7 days
|
||||
for (let i = 0; i < 7; i++) {
|
||||
downloads += platform.totals[i]
|
||||
}
|
||||
})
|
||||
return downloads
|
||||
},
|
||||
},
|
||||
dm: {
|
||||
label: 'month',
|
||||
transform: resp => {
|
||||
const platforms = resp.installs.daily.data
|
||||
let downloads = 0
|
||||
platforms.forEach(platform => {
|
||||
// total for the first 30 days
|
||||
for (let i = 0; i < 30; i++) {
|
||||
downloads += platform.totals[i]
|
||||
}
|
||||
})
|
||||
return downloads
|
||||
},
|
||||
},
|
||||
dt: {
|
||||
transform: resp => resp.installs.total,
|
||||
},
|
||||
}
|
||||
|
||||
export default ['day', 'week', 'month', 'total'].map(DownloadsForInterval)
|
||||
export default class PackageControlDownloads extends BaseJsonService {
|
||||
static category = 'downloads'
|
||||
|
||||
static route = {
|
||||
base: 'packagecontrol',
|
||||
pattern: ':interval(dd|dw|dm|dt)/:packageName',
|
||||
}
|
||||
|
||||
static openApi = {
|
||||
'/packagecontrol/{interval}/{packageName}': {
|
||||
get: {
|
||||
summary: 'Package Control Downloads',
|
||||
description:
|
||||
'Package Control is a package registry for Sublime Text packages',
|
||||
parameters: pathParams(
|
||||
{
|
||||
name: 'interval',
|
||||
example: 'dt',
|
||||
schema: { type: 'string', enum: this.getEnum('interval') },
|
||||
description: 'Daily, Weekly, Monthly, or Total downloads',
|
||||
},
|
||||
{ name: 'packageName', example: 'GitGutter' },
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
static defaultBadgeData = { label: 'downloads' }
|
||||
|
||||
async fetch({ packageName }) {
|
||||
const url = `https://packagecontrol.io/packages/${packageName}.json`
|
||||
return this._requestJson({ schema, url })
|
||||
}
|
||||
|
||||
async handle({ interval, packageName }) {
|
||||
const data = await this.fetch({ packageName })
|
||||
return renderDownloadsBadge({
|
||||
downloads: intervalMap[interval].transform(data),
|
||||
interval: intervalMap[interval].label,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user