1
0
mirror of https://github.com/badges/shields.git synced 2025-04-18 19:44:04 +03:00

Add [Hangar] Badges (#9800)

* Add Hangar service

* fix linting

* Added required changes

* Fix inconsistent openApi pattern

* Change hangar host
This commit is contained in:
Andrea Bonari 2024-01-16 21:16:04 +01:00 committed by GitHub
parent 0c18daa278
commit c5943c0f2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 252 additions and 0 deletions

View File

@ -0,0 +1,37 @@
import Joi from 'joi'
import { BaseJsonService } from '../index.js'
const description = `
<p><a href="https://hangar.papermc.io/">Hangar</a> is a plugin repository for the Paper, Waterfall and Folia platforms.</p>`
const resourceSchema = Joi.object({
stats: Joi.object({
views: Joi.number().required(),
downloads: Joi.number().required(),
recentViews: Joi.number().required(),
recentDownloads: Joi.number().required(),
stars: Joi.number().required(),
watchers: Joi.number().required(),
}).required(),
}).required()
class BaseHangarService extends BaseJsonService {
static _cacheLength = 3600
async fetch({
slug,
schema = resourceSchema,
url = `https://hangar.papermc.io/api/v1/projects/${slug}`,
}) {
return this._requestJson({
schema,
url,
httpErrors: {
401: 'Api session missing, invalid or expired',
403: 'Not enough permission to use this endpoint',
},
})
}
}
export { description, BaseHangarService }

View File

@ -0,0 +1,34 @@
import { pathParams } from '../index.js'
import { renderDownloadsBadge } from '../downloads.js'
import { BaseHangarService, description } from './hangar-base.js'
export default class HangarDownloads extends BaseHangarService {
static category = 'downloads'
static route = {
base: 'hangar/dt',
pattern: ':slug',
}
static openApi = {
'/hangar/dt/{slug}': {
get: {
summary: 'Hangar Downloads',
description,
parameters: pathParams({
name: 'slug',
example: 'Essentials',
}),
},
},
}
static defaultBadgeData = { label: 'downloads' }
async handle({ slug }) {
const {
stats: { downloads },
} = await this.fetch({ slug })
return renderDownloadsBadge({ downloads })
}
}

View File

@ -0,0 +1,13 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Essentials').get('/Essentials.json').expectBadge({
label: 'downloads',
message: isMetric,
})
t.create('Invalid Resource').get('/1.json').expectBadge({
label: 'downloads',
message: 'not found',
})

View File

@ -0,0 +1,43 @@
import { pathParams } from '../index.js'
import { metric } from '../text-formatters.js'
import { BaseHangarService, description } from './hangar-base.js'
export default class HangarStars extends BaseHangarService {
static category = 'social'
static route = {
base: 'hangar/stars',
pattern: ':slug',
}
static openApi = {
'/hangar/stars/{slug}': {
get: {
summary: 'Hangar Stars',
description,
parameters: pathParams({
name: 'slug',
example: 'Essentials',
}),
},
},
}
static defaultBadgeData = {
label: 'stars',
color: 'blue',
}
static render({ stars }) {
return {
message: metric(stars),
}
}
async handle({ slug }) {
const {
stats: { stars },
} = await this.fetch({ slug })
return this.constructor.render({ stars })
}
}

View File

@ -0,0 +1,13 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Essentials').get('/Essentials.json').expectBadge({
label: 'stars',
message: isMetric,
})
t.create('Invalid Resource').get('/1.json').expectBadge({
label: 'stars',
message: 'not found',
})

View File

@ -0,0 +1,43 @@
import { pathParams } from '../index.js'
import { metric } from '../text-formatters.js'
import { BaseHangarService, description } from './hangar-base.js'
export default class HangarViews extends BaseHangarService {
static category = 'other'
static route = {
base: 'hangar/views',
pattern: ':slug',
}
static openApi = {
'/hangar/views/{slug}': {
get: {
summary: 'Hangar Views',
description,
parameters: pathParams({
name: 'slug',
example: 'Essentials',
}),
},
},
}
static defaultBadgeData = {
label: 'views',
color: 'blue',
}
static render({ views }) {
return {
message: metric(views),
}
}
async handle({ slug }) {
const {
stats: { views },
} = await this.fetch({ slug })
return this.constructor.render({ views })
}
}

View File

@ -0,0 +1,13 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Essentials').get('/Essentials.json').expectBadge({
label: 'views',
message: isMetric,
})
t.create('Invalid Resource').get('/1.json').expectBadge({
label: 'views',
message: 'not found',
})

View File

@ -0,0 +1,43 @@
import { pathParams } from '../index.js'
import { metric } from '../text-formatters.js'
import { BaseHangarService, description } from './hangar-base.js'
export default class HangarWatchers extends BaseHangarService {
static category = 'social'
static route = {
base: 'hangar/watchers',
pattern: ':slug',
}
static openApi = {
'/hangar/watchers/{slug}': {
get: {
summary: 'Hangar Watchers',
description,
parameters: pathParams({
name: 'slug',
example: 'Essentials',
}),
},
},
}
static defaultBadgeData = {
label: 'watchers',
color: 'blue',
}
static render({ watchers }) {
return {
message: metric(watchers),
}
}
async handle({ slug }) {
const {
stats: { watchers },
} = await this.fetch({ slug })
return this.constructor.render({ watchers })
}
}

View File

@ -0,0 +1,13 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()
t.create('Essentials').get('/Essentials.json').expectBadge({
label: 'watchers',
message: isMetric,
})
t.create('Invalid Resource').get('/1.json').expectBadge({
label: 'watchers',
message: 'not found',
})