Add [CratesUserDownloads] service and tester (#10619)
* add jsdoc for crates fetch func * add BaseCratesUserService for user stats api route part of solution for #10614 * Add CratesUserDownloads service and tester This commit adds the CratesUserDownloads service and tester files. The CratesUserDownloads service shows the user total downloads at Crates.io. as requested by #10614 * render userid in code block * add non-exsistent user CratesUserDownloads test userid for API usage is int32, therefor to minimize chance of user taking the id used the max value for int32 is used. * fixed typo
This commit is contained in:
@@ -24,9 +24,21 @@ const versionResponseSchema = Joi.object({
|
||||
version: versionSchema.required(),
|
||||
}).required()
|
||||
|
||||
const userStatsSchema = Joi.object({
|
||||
total_downloads: nonNegativeInteger.required(),
|
||||
}).required()
|
||||
|
||||
class BaseCratesService extends BaseJsonService {
|
||||
static defaultBadgeData = { label: 'crates.io' }
|
||||
|
||||
/**
|
||||
* Fetches data from the crates.io API.
|
||||
*
|
||||
* @param {object} options - The options for the request
|
||||
* @param {string} options.crate - The crate name.
|
||||
* @param {string} [options.version] - The crate version number (optional).
|
||||
* @returns {Promise<object>} the JSON response from the API.
|
||||
*/
|
||||
async fetch({ crate, version }) {
|
||||
const url = version
|
||||
? `https://crates.io/api/v1/crates/${crate}/${version}`
|
||||
@@ -54,7 +66,23 @@ class BaseCratesService extends BaseJsonService {
|
||||
}
|
||||
}
|
||||
|
||||
class BaseCratesUserService extends BaseJsonService {
|
||||
static defaultBadgeData = { label: 'crates.io' }
|
||||
|
||||
/**
|
||||
* Fetches data from the crates.io API.
|
||||
*
|
||||
* @param {object} options - The options for the request
|
||||
* @param {string} options.userId - The user ID.
|
||||
* @returns {Promise<object>} the JSON response from the API.
|
||||
*/
|
||||
async fetch({ userId }) {
|
||||
const url = `https://crates.io/api/v1/users/${userId}/stats`
|
||||
return this._requestJson({ schema: userStatsSchema, url })
|
||||
}
|
||||
}
|
||||
|
||||
const description =
|
||||
'[Crates.io](https://crates.io/) is a package registry for Rust.'
|
||||
|
||||
export { BaseCratesService, description }
|
||||
export { BaseCratesService, BaseCratesUserService, description }
|
||||
|
||||
32
services/crates/crates-user-downloads.service.js
Normal file
32
services/crates/crates-user-downloads.service.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { renderDownloadsBadge } from '../downloads.js'
|
||||
import { pathParams } from '../index.js'
|
||||
import { BaseCratesUserService, description } from './crates-base.js'
|
||||
|
||||
export default class CratesUserDownloads extends BaseCratesUserService {
|
||||
static category = 'downloads'
|
||||
static route = {
|
||||
base: 'crates',
|
||||
pattern: 'udt/:userId',
|
||||
}
|
||||
|
||||
static openApi = {
|
||||
'/crates/udt/{userId}': {
|
||||
get: {
|
||||
summary: 'Crates.io User Total Downloads',
|
||||
description,
|
||||
parameters: pathParams({
|
||||
name: 'userId',
|
||||
example: '3027',
|
||||
description:
|
||||
'The user ID can be found using `https://crates.io/api/v1/users/{username}`',
|
||||
}),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
async handle({ userId }) {
|
||||
const json = await this.fetch({ userId })
|
||||
const { total_downloads: downloads } = json
|
||||
return renderDownloadsBadge({ downloads, labelOverride: 'downloads' })
|
||||
}
|
||||
}
|
||||
16
services/crates/crates-user-downloads.tester.js
Normal file
16
services/crates/crates-user-downloads.tester.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { isMetric } from '../test-validators.js'
|
||||
import { createServiceTester } from '../tester.js'
|
||||
export const t = await createServiceTester()
|
||||
|
||||
t.create('total user downloads')
|
||||
.get('/udt/3027.json')
|
||||
.expectBadge({ label: 'downloads', message: isMetric })
|
||||
|
||||
// non-existent user returns 0 downloads with 200 OK status code rather than 404.
|
||||
t.create('total user downloads (user not found)')
|
||||
.get('/udt/2147483647.json') // 2147483647 is the maximum valid user id as API uses i32
|
||||
.expectBadge({ label: 'downloads', message: '0' })
|
||||
|
||||
t.create('total user downloads (invalid)')
|
||||
.get('/udt/999999999999999999999999.json')
|
||||
.expectBadge({ label: 'crates.io', message: 'invalid' })
|
||||
Reference in New Issue
Block a user