From a4d82b0aa74ad0f8a97f6ac36c4d739ca5fed0dc Mon Sep 17 00:00:00 2001 From: Fred Boniface Date: Mon, 19 Jun 2023 21:34:14 +0100 Subject: [PATCH] Implement train and timetable Signed-off-by: Fred Boniface --- app.js | 4 +++ src/configs/version.configs.js | 2 +- src/controllers/ldb.controllers.js | 48 +++++++++++++++++++++++++-- src/controllers/train.controllers.js | 26 ++++++++++++++- src/routes/live2.routes.js | 9 +++++ src/routes/timetable2.routes.js | 8 +++++ src/services/ldb.services.js | 27 ++++++++++++++- src/services/trainService.services.js | 38 +++++++++++++++++++++ 8 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 src/routes/live2.routes.js create mode 100644 src/routes/timetable2.routes.js diff --git a/app.js b/app.js index 37684ca..fd2873f 100644 --- a/app.js +++ b/app.js @@ -32,6 +32,8 @@ const pisRtr = require('./src/routes/pis.routes'); const trainRtr = require('./src/routes/train.routes'); const pis2Rtr = require('./src/routes/pis2.routes'); // API Version 2 Routes const ref2Rtr = require('./src/routes/ref2.routes'); // API Version 2 Routes +const live2Rtr = require('./src/routes/live2.routes'); // API Version 2 Routes +const tt2Rtr = require('./src/routes/timetable2.routes'); // API Version 2 const miscRtr = require('./src/routes/misc.routes'); // Non-Public API Routes // Set Server Configurations @@ -66,7 +68,9 @@ app.use(limiter); // 2023 Rationalisation Routes (/api/v2, /misc) app.use('/api/v2/pis', authenticate, pis2Rtr); // API Version 2 +app.use('/api/v2/live', live2Rtr); // API Version 2 app.use('/api/v2/ref', ref2Rtr); // API Version 2 +app.use('/api/v2/timetable', tt2Rtr); // API Version 2 app.use('/misc', miscRtr); // Non public-api endpoints (Stats, Issue, etc.) // Unauthenticated Routes diff --git a/src/configs/version.configs.js b/src/configs/version.configs.js index 7956bc7..6586f50 100644 --- a/src/configs/version.configs.js +++ b/src/configs/version.configs.js @@ -1,6 +1,6 @@ const version = { api: ['/api/v1/','/api/v2'], - app: '2023.6.9' + app: '2023.6.10' }; module.exports = version; \ No newline at end of file diff --git a/src/controllers/ldb.controllers.js b/src/controllers/ldb.controllers.js index 032a4c9..3d37540 100644 --- a/src/controllers/ldb.controllers.js +++ b/src/controllers/ldb.controllers.js @@ -1,6 +1,6 @@ const ldb = require('../services/ldb.services'); -async function get(req, res, next){ +async function get(req, res, next){ // API v1 only try { var id = req.params.id; res.json(await ldb.get(id)); @@ -11,6 +11,50 @@ async function get(req, res, next){ } } +async function getTrain(req, res, next) { // API v2 Only + let type = req.params.searchType; + let id = req.params.id; + try { + switch (type.toLowerCase()) { + case 'rid': + res.json(await ldb.getServiceByRID(id)); + break; + case 'uid': + case 'headcode': + case 'rsid': + res.json(await ldb.getServicesByOther(id)); + break; + default: + res.status(404); + res.json({status: 'error', message:'Invalid search type'}); + } + } catch (err) { + console.error('Unknown Error', err.message); + err.status = 500; + next(err); + } +} + +async function getStation(req, res, next) { // API v2 Only + let type = req.params.type; + let id = req.params.id; + try { + if (type == 'staff') { + res.json(await ldb.get(id, true)); + next(); + } else { + res.json(await ldb.get(id, false)); + next(); + } + } catch (err) { + console.error('Unknown Error', err.message); + err.status = 500; + next(err); + } +} + module.exports = { - get + get, + getTrain, + getStation }; \ No newline at end of file diff --git a/src/controllers/train.controllers.js b/src/controllers/train.controllers.js index 9102a82..5cfef33 100644 --- a/src/controllers/train.controllers.js +++ b/src/controllers/train.controllers.js @@ -11,6 +11,30 @@ async function getByHeadcodeToday(req, res, next){ } } +async function get(req, res, next) { + let date = req.params.date; + let searchType = req.params.searchType; + let id = req.params.id; + try { + switch (searchType) { + case 'headcode': + res.json(await train.findByHeadcode(date, id)); + break; + default: + res.status(404).json({ + status:'error', + message:`Invalid search type "${searchType}"` + } + ); + } + } catch (err) { + console.error(err.message); + err.status = 500; + next(err); + } +} + module.exports = { - getByHeadcodeToday + getByHeadcodeToday, + get }; \ No newline at end of file diff --git a/src/routes/live2.routes.js b/src/routes/live2.routes.js new file mode 100644 index 0000000..705d185 --- /dev/null +++ b/src/routes/live2.routes.js @@ -0,0 +1,9 @@ +const express = require('express'); +const router = express.Router(); +const ldbCtr = require('../controllers/ldb.controllers'); + +// PIS +router.get('/station/:id/:type', ldbCtr.getStation); +router.get('/train/:searchType/:id', ldbCtr.getTrain); + +module.exports = router; \ No newline at end of file diff --git a/src/routes/timetable2.routes.js b/src/routes/timetable2.routes.js new file mode 100644 index 0000000..9728428 --- /dev/null +++ b/src/routes/timetable2.routes.js @@ -0,0 +1,8 @@ +const express = require('express'); +const router = express.Router(); +const ttCtr = require('../controllers/train.controllers'); + +// PIS +router.get('/train/:date/:searchType/:id', ttCtr.get); + +module.exports = router; \ No newline at end of file diff --git a/src/services/ldb.services.js b/src/services/ldb.services.js index e7f05ac..da0a32a 100644 --- a/src/services/ldb.services.js +++ b/src/services/ldb.services.js @@ -58,7 +58,8 @@ async function arrDepBoardStaff(CRS) { crs: CRS.toUpperCase(), getNonPassengerServices: true, time: await getDateTimeString(new Date), - timeWindow: 120 + timeWindow: 120, + services: 'PBS' }; const api = new ldb(ldbsvKey,true); return await api.call('GetArrivalDepartureBoardByCRS',options,false,false); @@ -85,6 +86,21 @@ async function getServiceByRID(rid) { } } +async function getServicesByOther(id) { + log.out(`ldbService.getServiceByOther: Finding services: ${id}`, 'dbug'); + try { + const options = { + serviceID: id, + sdd: getDateString(new Date) + }; + const api = new ldb(ldbsvKey,true); + return await api.call('QueryServices', options, false, false); + } catch (err) { + log.out(`ldbService.getServiceByOther: Error: ${err}`, 'EROR'); + return false; + } +} + async function getReasonCodeList() { log.out('ldbService.getReasonCodeList: Fetching reason code list', 'eror'); try { @@ -119,9 +135,18 @@ async function getDateTimeString(date) { return format; } +async function getDateString(date) { + const year = date.getFullYear(), + month = String(date.getMonth() + 1).padStart(2,'0'), + day = String(date.getDate()).padStart(2,'0'); + const format = `${year}-${month}-${day}`; + return format; +} + module.exports = { get, getServiceByRID, + getServicesByOther, getReasonCodeList, getReasonCode }; \ No newline at end of file diff --git a/src/services/trainService.services.js b/src/services/trainService.services.js index 1ec4259..6b367c9 100644 --- a/src/services/trainService.services.js +++ b/src/services/trainService.services.js @@ -35,8 +35,46 @@ async function findByHeadcodeToday(headcode) { return preparedData; } +async function findByHeadcode(date, headcode) { + const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); + log.out('trainServiceServices.findByHeadcode: Searching for headcode ' + + sanitizedHeadcode, 'dbug'); + let searchDate; + if (date === 'now') { + searchDate = new Date(); + } else { + searchDate = new Date(date); + } + const dayMap = ['su', 'm', 't', 'w', 'th', 'f', 's']; + const shortDay = dayMap[searchDate.getDay()]; // Fetch short day from map + const query = { + headcode: sanitizedHeadcode, + scheduleStartDate: {$lte: searchDate}, + scheduleEndDate: {$gte: searchDate}, + daysRun: {$in: [shortDay]} + }; + const queryData = await db.query('timetable', query); + let trainData = await parseTrains(queryData); + let preparedData = []; + for (let trainService in trainData) { + // Search for PIS Code for each service + const tiplocList = await getPublicStops(trainData[trainService]['stops']); + //console.log(tiplocList.length); console.log(tiplocList); + if (tiplocList.length) { + const pisDetail = await pis.findByTiplocArray(tiplocList); + trainData[trainService]['pis'] = pisDetail?.[0]?.['code'] ?? 'None'; + } else { + trainData[trainService]['pis'] = '0015'; // Not in Service code + // '0015' is a string otherwise it is interpreted as octal 13. + } + preparedData.push(trainData[trainService]); + } + return preparedData; +} + module.exports = { findByHeadcodeToday, + findByHeadcode }; /* Internal Functions, not to be exported */