Skip to content
This repository has been archived by the owner on Sep 15, 2023. It is now read-only.

Commit

Permalink
LRT Escalator & Elevator Outages specific controller
Browse files Browse the repository at this point in the history
  • Loading branch information
WJXHenry committed Apr 23, 2019
1 parent a014271 commit d8b959b
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 0 deletions.
135 changes: 135 additions & 0 deletions src/controllers/lrt-escalator-outages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
const request = require('request-promise-native')
const uuid = require('uuid/v4')

/**
* LRT Escalator & Elevator Outages
*/
module.exports = async function(req, res) {
console.log('LRT Escalator & Elevator Outages Controller')
let key = 'lrt-escalator-outages' // Unique key for dataset storage
let url = 'https://data.edmonton.ca/resource/snws-u3zx.json' // The Socrata api endpoint
let queryBase = `${url}?$query=`

let storedData = await req.cache.getLatest(key)
let storedTimestamp
let filteredStoredColumnValues // The stored/previous column values to be compared to
if (storedData) {
storedTimestamp = storedData.created_at
filteredStoredColumnValues = JSON.parse(storedData.outages).map(device => {
return device.device_id
})
} else {
storedTimestamp = '1998-07-25T00:00:00.000Z' // This value is random
}

// Get all the columns (filter it by column later)
let getLatestUpdatedQuery = `${queryBase}SELECT lrt_station_name, device_id, lrt_device_location, device_type WHERE :updated_at >= '${storedTimestamp}' ORDER BY :updated_at DESC`
let getUpdatedTimestamp = `${queryBase}SELECT :updated_at ORDER BY :updated_at LIMIT 1`
let latestTimestamp
let latestColumnRows
let filteredLatestColumnValues // The current values of the column being monitored
try {
let rawJsonUpdatedAt = await request(getUpdatedTimestamp)
latestTimestamp = JSON.parse(rawJsonUpdatedAt)[0][':updated_at']
let rawJsonColumnValues = await request(getLatestUpdatedQuery)
latestColumnRows = JSON.parse(rawJsonColumnValues)
filteredLatestColumnValues = latestColumnRows.map(row => {
return row['device_id']
})
} catch (e) {
e.code = 500
throw e
}
// Ensure that the date is in ISO 8601 time format
latestTimestamp = timestampFormat(latestTimestamp)

let responseValues
if (
storedData &&
compareArr(filteredStoredColumnValues, filteredLatestColumnValues)
) {
console.log('Row values not changed. Returning old data')
responseValues = await req.cache.getAll(key, req.body['limit'])
} else {
console.log('Adding new rows')
let id = uuid()
// The unique difference (does not catch repeat values)
let fixed = arrDiffFixed(storedData, filteredLatestColumnValues)
let newRows = {
id,
created_at: latestTimestamp,
outages: JSON.stringify(latestColumnRows),
fixed: JSON.stringify(fixed),
meta: {
id,
timestamp: Math.round(new Date() / 1000)
}
}
req.cache.add(key, newRows)
responseValues = await req.cache.getAll(key, req.body['limit'])
}

res.status(200).send({
data: responseValues
})
}

/**
* Compares the elements of two arrays and returns TRUE arrays are same or FALSE
* if they are different
* @param {Array<String|Number>} arr1 The first array to compare
* @param {Array<String|Number>} arr2 The second array to compare
* @return {Boolean} Returns TRUE if the arrays are the same or FALSE otherwise
*/
function compareArr(arr1, arr2) {
arr1.sort()
arr2.sort()
let length
if (arr1.length !== arr2.length) {
return false
} else {
length = arr1.length
}
for (let i = 0; i < length; i++) {
if (arr1[i] !== arr2[i]) {
return false
}
}
return true
}

/**
* Returns an array of JSON objects of devices that are no longer in the dataset
* (devices that are fixed). The IDs that were stored that are no longer in 'latestDeviceIds'
* @param {Object} storedData The JSON object that is stored in the Redis cache
* @param {Array<String>} latestDeviceIds An array of device IDs representing
* escalator/elevator outages
*/
function arrDiffFixed(storedData, latestDeviceIds) {
let fixed = []
if (!storedData) return fixed
if (!latestDeviceIds) return stored
for (let element of JSON.parse(storedData.outages)) {
if (latestDeviceIds.indexOf(element.device_id) == -1) {
fixed.push(element)
}
}
return fixed
}

/**
* Converts timestamps to correctly formatted ISO 8601 time (currently only checks for epoch time)
* @param {String|Number} timestamp The timestamp to convert
* @return {String} The ISO 8601 formatted timestamp string
*/
function timestampFormat(timestamp) {
if (
!timestamp
.toString()
.match(/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}Z/)
) {
// Convert Epoch times to ISO 8601 time format
return new Date(timestamp * 1000).toISOString()
}
return timestamp
}
3 changes: 3 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const createAirQualityController = require('./controllers/aqhi-base')
const status = require('./controllers/status')
const test = require('./controllers/test-setup')
const airQualityStations = require('./controllers/air-quality-stations')
const lrtEscalatorOutages = require('./controllers/lrt-escalator-outages')

// Middleware
const logger = require('./middleware/logger')
Expand Down Expand Up @@ -72,6 +73,8 @@ let edmontonAirHealthIndex = createAirQualityController(req => {
}
})

router.post('/triggers/lrt_escalator_outages', lrtEscalatorOutages)

router.post('/triggers/light_the_bridge', lightTheBridge)

// We split the route here to allow for upgrading the API with 0 downtime.
Expand Down

0 comments on commit d8b959b

Please sign in to comment.