diff --git a/services/redmine/redmine.service.js b/services/redmine/redmine.service.js
index ff42d98695..1c23d8fd55 100644
--- a/services/redmine/redmine.service.js
+++ b/services/redmine/redmine.service.js
@@ -1,19 +1,77 @@
'use strict'
-const xml2js = require('xml2js')
-const LegacyService = require('../legacy-service')
-const { makeBadgeData: getBadgeData } = require('../../lib/badge-data')
const { starRating } = require('../../lib/text-formatters')
const { floorCount: floorCountColor } = require('../../lib/color-formatters')
-module.exports = class Redmine extends LegacyService {
+const Joi = require('joi')
+const BaseXmlService = require('../base-xml')
+
+const schema = Joi.object({
+ 'redmine-plugin': Joi.object({
+ 'ratings-average': Joi.number()
+ .min(0)
+ .required(),
+ }).required(),
+})
+
+class BaseRedminePluginRating extends BaseXmlService {
+ async fetch({ plugin }) {
+ const url = `https://www.redmine.org/plugins/${plugin}.xml`
+ return this._requestXml({ schema, url })
+ }
+
static get category() {
return 'rating'
}
+ static render({ rating }) {
+ throw new Error(`render() function not implemented for ${this.name}`)
+ }
+
+ async handle({ plugin }) {
+ const data = await this.fetch({ plugin })
+ const rating = data['redmine-plugin']['ratings-average']
+ return this.constructor.render({ rating })
+ }
+}
+
+class RedminePluginRating extends BaseRedminePluginRating {
static get route() {
return {
- base: 'redmine/plugin',
+ base: 'redmine/plugin/rating',
+ pattern: ':plugin',
+ }
+ }
+
+ static get defaultBadgeData() {
+ return { label: 'redmine' }
+ }
+
+ static get examples() {
+ return [
+ {
+ title: 'Plugin on redmine.org',
+ namedParams: { plugin: 'redmine_xlsx_format_issue_exporter' },
+ staticExample: this.render({ rating: 5 }),
+ keywords: ['redmine', 'plugin'],
+ },
+ ]
+ }
+
+ static render({ rating }) {
+ return {
+ label: 'rating',
+ message: `${rating.toFixed(1)}/5.0`,
+ color: floorCountColor(rating, 2, 3, 4),
+ }
+ }
+}
+
+class RedminePluginStars extends BaseRedminePluginRating {
+ static get route() {
+ return {
+ base: 'redmine/plugin/stars',
+ pattern: ':plugin',
}
}
@@ -21,60 +79,20 @@ module.exports = class Redmine extends LegacyService {
return [
{
title: 'Plugin on redmine.org',
- previewUrl: 'rating/redmine_xlsx_format_issue_exporter',
- keywords: ['redmine', 'plugin'],
- },
- {
- title: 'Plugin on redmine.org',
- previewUrl: 'stars/redmine_xlsx_format_issue_exporter',
+ namedParams: { plugin: 'redmine_xlsx_format_issue_exporter' },
+ staticExample: this.render({ rating: 5 }),
keywords: ['redmine', 'plugin'],
},
]
}
- static registerLegacyRouteHandler({ camp, cache }) {
- camp.route(
- /^\/redmine\/plugin\/(rating|stars)\/(.*)\.(svg|png|gif|jpg|json)$/,
- cache((data, match, sendBadge, request) => {
- const type = match[1]
- const plugin = match[2]
- const format = match[3]
- const options = {
- method: 'GET',
- uri: `https://www.redmine.org/plugins/${plugin}.xml`,
- }
-
- const badgeData = getBadgeData(type, data)
- request(options, (err, res, buffer) => {
- if (err != null) {
- badgeData.text[1] = 'inaccessible'
- sendBadge(format, badgeData)
- return
- }
-
- // eslint-disable-next-line handle-callback-err
- xml2js.parseString(buffer.toString(), (err, data) => {
- try {
- const rating = data['redmine-plugin']['ratings-average'][0]._
- badgeData.colorscheme = floorCountColor(rating, 2, 3, 4)
-
- switch (type) {
- case 'rating':
- badgeData.text[1] = `${rating}/5.0`
- break
- case 'stars':
- badgeData.text[1] = starRating(Math.round(rating))
- break
- }
-
- sendBadge(format, badgeData)
- } catch (e) {
- badgeData.text[1] = 'invalid'
- sendBadge(format, badgeData)
- }
- })
- })
- })
- )
+ static render({ rating }) {
+ return {
+ label: 'stars',
+ message: starRating(Math.round(rating)),
+ color: floorCountColor(rating, 2, 3, 4),
+ }
}
}
+
+module.exports = { RedminePluginRating, RedminePluginStars }
diff --git a/services/redmine/redmine.tester.js b/services/redmine/redmine.tester.js
index d6a1ac95c7..b06cd1460d 100644
--- a/services/redmine/redmine.tester.js
+++ b/services/redmine/redmine.tester.js
@@ -9,16 +9,6 @@ module.exports = t
t.create('plugin rating')
.get('/plugin/rating/redmine_xlsx_format_issue_exporter.json')
- .intercept(nock =>
- nock('https://www.redmine.org')
- .get('/plugins/redmine_xlsx_format_issue_exporter.xml')
- .reply(
- 200,
- '' +
- '1.23456' +
- ''
- )
- )
.expectJSONTypes(
Joi.object().keys({
name: 'rating',
@@ -28,16 +18,6 @@ t.create('plugin rating')
t.create('plugin stars')
.get('/plugin/stars/redmine_xlsx_format_issue_exporter.json')
- .intercept(nock =>
- nock('https://www.redmine.org')
- .get('/plugins/redmine_xlsx_format_issue_exporter.xml')
- .reply(
- 200,
- '' +
- '1.23456' +
- ''
- )
- )
.expectJSONTypes(
Joi.object().keys({
name: 'stars',
@@ -47,22 +27,9 @@ t.create('plugin stars')
t.create('plugin not found')
.get('/plugin/rating/plugin_not_found.json')
- .intercept(nock =>
- nock('https://www.redmine.org')
- .get('/plugins/plugin_not_found.xml')
- .reply(404, '')
- )
.expectJSONTypes(
Joi.object().keys({
- name: 'rating',
- value: 'invalid',
+ name: 'redmine',
+ value: 'not found',
})
)
-
-t.create('connection error')
- .get('/plugin/rating/redmine_xlsx_format_issue_exporter.json')
- .networkOff()
- .expectJSON({
- name: 'rating',
- value: 'inaccessible',
- })