Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions services/atn/atn-base.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import Joi from 'joi'
import { nonNegativeInteger } from '../validators.js'
import { BaseJsonService } from '../index.js'

const description =
'[addons.thunderbird.net](https://addons.thunderbird.net) (ATN) publishes extensions for Mozilla Thunderbird'

const schema = Joi.object({
average_daily_users: nonNegativeInteger,
current_version: Joi.object({
version: Joi.string().required(),
}).required(),
ratings: Joi.object({
average: Joi.number().required(),
}).required(),
weekly_downloads: nonNegativeInteger,
}).required()

class BaseAtnService extends BaseJsonService {
static defaultBadgeData = { label: 'thunderbird add-on' }

addonUrl({ addonId }) {
return `https://addons.thunderbird.net/api/v3/addons/addon/${addonId}/`
}

async fetch({ addonId }) {
return this._requestJson({
schema,
url: this.addonUrl({ addonId }),
})
}
}

export { BaseAtnService, description }
36 changes: 36 additions & 0 deletions services/atn/atn-downloads.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { renderDownloadsBadge } from '../downloads.js'
import { pathParams } from '../index.js'
import { BaseAtnService, description } from './atn-base.js'

export default class AtnWeeklyDownloads extends BaseAtnService {
static category = 'downloads'
static route = { base: 'atn/dw', pattern: ':addonId' }

static openApi = {
'/atn/dw/{addonId}': {
get: {
summary: 'Thunderbird Add-on Downloads',
description,
parameters: pathParams({
name: 'addonId',
example: 'unicodify-text-transformer',
}),
},
},
}

static _cacheLength = 21600

static defaultBadgeData = { label: 'downloads' }

static render({ downloads }) {
return renderDownloadsBadge({ downloads, interval: 'week' })
}

async handle({ addonId }) {
const data = await this.fetch({ addonId })
return this.constructor.render({
downloads: data.weekly_downloads,
})
}
}
11 changes: 11 additions & 0 deletions services/atn/atn-downloads.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { createServiceTester } from '../tester.js'
import { isMetricOverTimePeriod } from '../test-validators.js'
export const t = await createServiceTester()

t.create('Weekly Downloads')
.get('/dictionary-german.json')
.expectBadge({ label: 'downloads', message: isMetricOverTimePeriod })

t.create('Weekly Downloads (not found)')
.get('/not-a-real-plugin.json')
.expectBadge({ label: 'downloads', message: 'not found' })
50 changes: 50 additions & 0 deletions services/atn/atn-rating.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { starRating } from '../text-formatters.js'
import { floorCount as floorCountColor } from '../color-formatters.js'
import { pathParams } from '../index.js'
import { BaseAtnService, description } from './atn-base.js'

export default class AtnRating extends BaseAtnService {
static category = 'rating'
static route = { base: 'atn', pattern: ':format(stars|rating)/:addonId' }

static openApi = {
'/atn/rating/{addonId}': {
get: {
summary: 'Thunderbird Add-on Rating',
description,
parameters: pathParams({
name: 'addonId',
example: 'unicodify-text-transformer',
}),
},
},
'/atn/stars/{addonId}': {
get: {
summary: 'Thunderbird Add-on Stars',
description,
parameters: pathParams({
name: 'addonId',
example: 'unicodify-text-transformer',
}),
},
},
}

static _cacheLength = 7200

static render({ format, rating }) {
return {
label: format,
message:
format === 'stars'
? starRating(rating)
: `${Math.round(rating * 10) / 10}/5`,
color: floorCountColor(rating, 2, 3, 4),
}
}

async handle({ format, addonId }) {
const data = await this.fetch({ addonId })
return this.constructor.render({ format, rating: data.ratings.average })
}
}
19 changes: 19 additions & 0 deletions services/atn/atn-rating.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Joi from 'joi'
import { isStarRating } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()

t.create('Rating')
.get('/rating/unicodify-text-transformer.json')
.expectBadge({
label: 'rating',
message: Joi.string().regex(/^\d(\.\d)?\/\d$/),
})

t.create('Stars')
.get('/stars/unicodify-text-transformer.json')
.expectBadge({ label: 'stars', message: isStarRating })

t.create('Rating (not found)')
.get('/rating/not-a-real-plugin.json')
.expectBadge({ label: 'thunderbird add-on', message: 'not found' })
26 changes: 26 additions & 0 deletions services/atn/atn-version.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { renderVersionBadge } from '../version.js'
import { pathParams } from '../index.js'
import { BaseAtnService, description } from './atn-base.js'

export default class AtnVersion extends BaseAtnService {
static category = 'version'
static route = { base: 'atn/v', pattern: ':addonId' }

static openApi = {
'/atn/v/{addonId}': {
get: {
summary: 'Thunderbird Add-on Version',
description,
parameters: pathParams({
name: 'addonId',
example: 'unicodify-text-transformer',
}),
},
},
}

async handle({ addonId }) {
const data = await this.fetch({ addonId })
return renderVersionBadge({ version: data.current_version.version })
}
}
12 changes: 12 additions & 0 deletions services/atn/atn-version.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { isVPlusDottedVersionAtLeastOne } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()

t.create('Version').get('/unicodify-text-transformer.json').expectBadge({
label: 'thunderbird add-on',
message: isVPlusDottedVersionAtLeastOne,
})

t.create('Version (not found)')
.get('/not-a-real-plugin.json')
.expectBadge({ label: 'thunderbird add-on', message: 'not found' })
34 changes: 34 additions & 0 deletions services/atn/atn.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { renderDownloadsBadge } from '../downloads.js'
import { pathParams } from '../index.js'
import { BaseAtnService, description } from './atn-base.js'

export default class AtnUsers extends BaseAtnService {
static category = 'downloads'
static route = { base: 'atn/users', pattern: ':addonId' }

static openApi = {
'/atn/users/{addonId}': {
get: {
summary: 'Thunderbird Add-on Users',
description,
parameters: pathParams({
name: 'addonId',
example: 'unicodify-text-transformer',
}),
},
},
}

static _cacheLength = 21600

static defaultBadgeData = { label: 'users' }

static render({ users: downloads }) {
return renderDownloadsBadge({ downloads, colorOverride: 'blue' })
}

async handle({ addonId }) {
const data = await this.fetch({ addonId })
return this.constructor.render({ users: data.average_daily_users })
}
}
10 changes: 10 additions & 0 deletions services/atn/atn.service.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { test, given } from 'sazerac'
import { BaseAtnService } from './atn-base.js'

describe('ATN service', function () {
test(BaseAtnService.prototype.addonUrl, () => {
given({ addonId: 'unicodify-text-transformer' }).expect(
'https://addons.thunderbird.net/api/v3/addons/addon/unicodify-text-transformer/',
)
})
})
11 changes: 11 additions & 0 deletions services/atn/atn.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { isMetric } from '../test-validators.js'
import { createServiceTester } from '../tester.js'
export const t = await createServiceTester()

t.create('Users')
.get('/unicodify-text-transformer.json')
.expectBadge({ label: 'users', message: isMetric })

t.create('Users (not found)')
.get('/not-a-real-plugin.json')
.expectBadge({ label: 'users', message: 'not found' })
Loading