From 666c84b5f78201e302b02977d3ee6a83ceefb0da Mon Sep 17 00:00:00 2001 From: Julian Schmidhuber Date: Sat, 2 Apr 2022 17:02:25 +0200 Subject: [PATCH] =?UTF-8?q?/journeys:=20expose=20loyaltyCard=20and=20first?= =?UTF-8?q?Class,=20rebuild=20API=20docs=20=E2=9C=85=F0=9F=93=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #9 closes #23 --- api.js | 19 ++++++++++++++++++- docs/api.md | 2 ++ lib/loyalty-cards.js | 36 ++++++++++++++++++++++++++++++++++++ package.json | 2 +- test/index.js | 37 ++++++++++++++++++++++++++++++++++++- 5 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 lib/loyalty-cards.js diff --git a/api.js b/api.js index 7118766..3dd138b 100644 --- a/api.js +++ b/api.js @@ -8,7 +8,9 @@ const withCache = require('cached-hafas-client') const redisStore = require('cached-hafas-client/stores/redis') const {join: pathJoin} = require('path') const serveStatic = require('serve-static') +const {parseBoolean} = require('hafas-rest-api/lib/parse') const pkg = require('./package.json') +const {loyaltyCardParser} = require('./lib/loyalty-cards') const stations = require('./routes/stations') const station = require('./routes/station') @@ -41,7 +43,21 @@ if (process.env.REDIS_URL) { ) } -const modifyRoutes = (routes) => { +const mapRouteParsers = (route, parsers) => { + if (route !== 'journeys') return parsers + return { + ...parsers, + loyaltyCard: loyaltyCardParser, + firstClass: { + description: 'Search for first-class options?', + type: 'boolean', + default: 'false', + parse: parseBoolean, + }, + } +} + +const modifyRoutes = (routes, hafas, config) => { routes['/stations/:id'] = station routes['/stations'] = stations return routes @@ -61,6 +77,7 @@ const config = { etags: 'strong', csp: `default-src 'none' style-src 'self' 'unsafe-inline' img-src https:`, healthCheck, + mapRouteParsers, modifyRoutes, } diff --git a/docs/api.md b/docs/api.md index 34756f7..1c6b621 100644 --- a/docs/api.md +++ b/docs/api.md @@ -381,6 +381,8 @@ parameter | description | type | default value `remarks` | Parse & return hints & warnings? | boolean | `true` `scheduledDays` | Parse & return dates each journey is valid on? | boolean | `false` `language` | Language of the results. | string | `en` +`loyaltyCard` | Type of loyalty card in use. See https://github.com/public-transport/hafas-client/blob/68ecd7c5e976dd2f51c5c64a81600e7e181a8996/p/db/loyalty-cards.js#L6-L11. | string | *none* +`firstClass` | Search for first-class options? | boolean | `false` `nationalExpress` | Include InterCityExpress (ICE)? | boolean | `true` `national` | Include InterCity & EuroCity (IC/EC)? | boolean | `true` `regionalExp` | Include RegionalExpress & InterRegio (RE/IR)? | boolean | `true` diff --git a/lib/loyalty-cards.js b/lib/loyalty-cards.js new file mode 100644 index 0000000..21a8883 --- /dev/null +++ b/lib/loyalty-cards.js @@ -0,0 +1,36 @@ +const {data: cards} = require('hafas-client/p/db/loyalty-cards') + +const DOCS_URL = 'https://github.com/public-transport/hafas-client/blob/68ecd7c5e976dd2f51c5c64a81600e7e181a8996/p/db/loyalty-cards.js#L6-L11' + +const typesByName = new Map([ + ['bahncard-1st-25', {type: cards.BAHNCARD, discount: 25, class: 1}], + ['bahncard-2nd-25', {type: cards.BAHNCARD, discount: 25, class: 2}], + ['bahncard-1st-50', {type: cards.BAHNCARD, discount: 50, class: 1}], + ['bahncard-2nd-50', {type: cards.BAHNCARD, discount: 50, class: 2}], + ['vorteilscard', {type: cards.VORTEILSCARD}], + ['halbtaxabo-railplus', {type: cards.HALBTAXABO, railplus: true}], + ['halbtaxabo', {type: cards.HALBTAXABO, railplus: false}], + ['voordeelurenabo-railplus', {type: cards.VOORDEELURENABO, railplus: true}], + ['voordeelurenabo', {type: cards.VOORDEELURENABO, railplus: false}], + ['shcard', {type: cards.SHCARD}], + ['generalabonnement', {type: cards.GENERALABONNEMENT}], +]) +const types = Array.from(typesByName.keys()) + +const parseLoyaltyCard = (key, val) => { + if (typesByName.has(val)) return typesByName.get(val) + throw new Error(key + ' must be one of ' + types.join(', ')) +} + +const loyaltyCardParser = { + description: `Type of loyalty card in use. See ${DOCS_URL}.`, + type: 'string', + enum: types, + defaultStr: '*none*', + parse: parseLoyaltyCard, +} + +module.exports = { + parseLoyaltyCard, + loyaltyCardParser, +} diff --git a/package.json b/package.json index cf9e277..153769b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "db-stations-autocomplete": "^2.2.0", "etag": "^1.8.1", "hafas-client-health-check": "^2.1.1", - "hafas-rest-api": "^3.7.0", + "hafas-rest-api": "^3.8.0", "ioredis": "^4.28.1", "serve-buffer": "^2.0.0", "serve-static": "^1.14.1" diff --git a/test/index.js b/test/index.js index c309e07..a00c7c8 100644 --- a/test/index.js +++ b/test/index.js @@ -1,6 +1,41 @@ 'use strict' const tape = require('tape') +const {loyaltyCards} = require('../lib/loyalty-cards') const {fetchWithTestApi} = require('./util') -// todo +const NO_JOURNEYS = { + // todo? + journeys: [], +} + +tape.test('/journeys?firstClass works', async (t) => { + await fetchWithTestApi({ + journeys: async (from, to, opt = {}) => { + t.equal(opt.firstClass, true, 'journeys() called with invalid opt.firstClass') + return NO_JOURNEYS + } + }, {}, '/journeys?from=123&to=234&firstClass=true') +}) + +tape.test('/journeys?loyaltyCard works', async (t) => { + await fetchWithTestApi({ + journeys: async (from, to, opt = {}) => { + t.deepEqual(opt.loyaltyCard, { + type: loyaltyCards.SHCARD, + }, 'journeys() called with invalid opt.loyaltyCard') + return NO_JOURNEYS + } + }, {}, '/journeys?from=123&to=234&loyaltyCard=shcard') + + await fetchWithTestApi({ + journeys: async (from, to, opt = {}) => { + t.deepEqual(opt.loyaltyCard, { + type: loyaltyCards.BAHNCARD, + discount: 50, + class: 2, + }, 'journeys() called with invalid opt.loyaltyCard') + return NO_JOURNEYS + } + }, {}, '/journeys?from=123&to=234&loyaltyCard=bahncard-2nd-50') +})