Implement train and timetable

Signed-off-by: Fred Boniface <fred@fjla.uk>
This commit is contained in:
Fred Boniface 2023-06-19 21:34:14 +01:00
parent 199a1760b7
commit a4d82b0aa7
8 changed files with 157 additions and 5 deletions

4
app.js
View File

@ -32,6 +32,8 @@ const pisRtr = require('./src/routes/pis.routes');
const trainRtr = require('./src/routes/train.routes'); const trainRtr = require('./src/routes/train.routes');
const pis2Rtr = require('./src/routes/pis2.routes'); // API Version 2 Routes const pis2Rtr = require('./src/routes/pis2.routes'); // API Version 2 Routes
const ref2Rtr = require('./src/routes/ref2.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 const miscRtr = require('./src/routes/misc.routes'); // Non-Public API Routes
// Set Server Configurations // Set Server Configurations
@ -66,7 +68,9 @@ app.use(limiter);
// 2023 Rationalisation Routes (/api/v2, /misc) // 2023 Rationalisation Routes (/api/v2, /misc)
app.use('/api/v2/pis', authenticate, pis2Rtr); // API Version 2 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/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.) app.use('/misc', miscRtr); // Non public-api endpoints (Stats, Issue, etc.)
// Unauthenticated Routes // Unauthenticated Routes

View File

@ -1,6 +1,6 @@
const version = { const version = {
api: ['/api/v1/','/api/v2'], api: ['/api/v1/','/api/v2'],
app: '2023.6.9' app: '2023.6.10'
}; };
module.exports = version; module.exports = version;

View File

@ -1,6 +1,6 @@
const ldb = require('../services/ldb.services'); const ldb = require('../services/ldb.services');
async function get(req, res, next){ async function get(req, res, next){ // API v1 only
try { try {
var id = req.params.id; var id = req.params.id;
res.json(await ldb.get(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 = { module.exports = {
get get,
getTrain,
getStation
}; };

View File

@ -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 = { module.exports = {
getByHeadcodeToday getByHeadcodeToday,
get
}; };

View File

@ -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;

View File

@ -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;

View File

@ -58,7 +58,8 @@ async function arrDepBoardStaff(CRS) {
crs: CRS.toUpperCase(), crs: CRS.toUpperCase(),
getNonPassengerServices: true, getNonPassengerServices: true,
time: await getDateTimeString(new Date), time: await getDateTimeString(new Date),
timeWindow: 120 timeWindow: 120,
services: 'PBS'
}; };
const api = new ldb(ldbsvKey,true); const api = new ldb(ldbsvKey,true);
return await api.call('GetArrivalDepartureBoardByCRS',options,false,false); 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() { async function getReasonCodeList() {
log.out('ldbService.getReasonCodeList: Fetching reason code list', 'eror'); log.out('ldbService.getReasonCodeList: Fetching reason code list', 'eror');
try { try {
@ -119,9 +135,18 @@ async function getDateTimeString(date) {
return format; 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 = { module.exports = {
get, get,
getServiceByRID, getServiceByRID,
getServicesByOther,
getReasonCodeList, getReasonCodeList,
getReasonCode getReasonCode
}; };

View File

@ -35,8 +35,46 @@ async function findByHeadcodeToday(headcode) {
return preparedData; 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 = { module.exports = {
findByHeadcodeToday, findByHeadcodeToday,
findByHeadcode
}; };
/* Internal Functions, not to be exported */ /* Internal Functions, not to be exported */