diff --git a/functions/index.js b/functions/index.js index c40b6e0..d60d7fc 100644 --- a/functions/index.js +++ b/functions/index.js @@ -8,28 +8,6 @@ admin.initializeApp(); const axios = require('axios'); const parseString = require('xml2js').parseString; -// function to fetch live train data from the Firestore database -exports.getLiveTrainData = functions.https.onRequest((request, response) => { - response.set('Access-Control-Allow-Origin', '*'); - response.set('Access-Control-Allow-Credentials', 'true'); - let jsonData = []; - - cors(request, response, () => { - // fetch the "liveTrainData" collection - admin.firestore().collection('liveTrainData').get().then((snapshot) => { - if (snapshot.empty) { - response.status(404).send({data: "Error fetching live train data from the database"}); - return; - } - // iterate through each of the collection's documents - snapshot.forEach(doc => { - jsonData.push(doc.data()); - }); - response.json({data: jsonData}); - }) - }); -}) - // function to fetch station data from the Firestore database exports.getStationData = functions.https.onRequest((request, response) => { response.set('Access-Control-Allow-Origin', '*'); @@ -40,7 +18,7 @@ exports.getStationData = functions.https.onRequest((request, response) => { // fetch the "stations" collection admin.firestore().collection('stations').get().then((snapshot) => { if (snapshot.empty) { - response.status(404).send({data: "Error fetching station data from the database"}) + response.send({data: "Error fetching station data from the database"}) return; } // iterate through each of the collection's documents @@ -94,50 +72,97 @@ exports.postStationData = functions.https.onRequest((request, response) => { }) }) -// function to populate the Firestore database with live train data from Irish Rail -exports.postLiveTrainData = functions.https.onRequest((request, response) => { +// function to fetch live train data from the Firestore database +exports.getLiveTrainData = functions.https.onRequest((request, response) => { response.set('Access-Control-Allow-Origin', '*'); response.set('Access-Control-Allow-Credentials', 'true'); + let jsonData = []; cors(request, response, () => { - axios.get('http://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML') - .then((res) => { - // XML to JSON - parseString(res.data, function(err, result) { - let jsonStr = JSON.stringify(result); - let jsonObj = JSON.parse(jsonStr); - let jsonData = jsonObj.ArrayOfObjTrainPositions.objTrainPositions; + // fetch the "liveTrainData" collection + admin.firestore().collection('liveTrainData').get().then((snapshot) => { + if (snapshot.empty) { + response.status(404).send({data: "Error fetching live train data from the database"}); + return; + } + // iterate through each of the collection's documents + snapshot.forEach(doc => { + jsonData.push(doc.data()); + }); + response.json({data: jsonData}); + }) + }); +}) - // batch delete all of the "liveTrainData" collections's documents - var db = admin.firestore(); - admin.firestore().collection('liveTrainData').get().then((snapshot) => { - var batchDelete = db.batch(); - snapshot.forEach(doc => { - batchDelete.delete(doc.ref); - }); +// function to populate the Firestore database with live train data from Irish Rail +exports.postLiveTrainData = functions.https.onRequest((request, response) => { + // helper function to parse train objects + function parseJSON(result) { + let jsonStr = JSON.stringify(result); + let jsonObj = JSON.parse(jsonStr); + let jsonData = jsonObj.ArrayOfObjTrainPositions.objTrainPositions; + return jsonData; + } + + // helper function to write to the database + function batchWriteDB(request, response, db, jsonData, trainTypeCode) { + response.set('Access-Control-Allow-Origin', '*'); + response.set('Access-Control-Allow-Credentials', 'true'); - batchDelete.commit().then(function() { - // batch write all train JSON objects to the "liveTrainData" collection - var batchWrite = db.batch(); - - jsonData.forEach((doc) => { - // ignore trains with longitudes or latitudes equal zero - if (!(doc["TrainLongitude"] == 0 || doc["TrainLatitude"] == 0)) { - // set the train's code as the document ID - var docID = db.collection('liveTrainData').doc(doc["TrainCode"][0]); - batchWrite.set(docID, doc); - } - }); + cors(request, response, () => { + var batchWrite = db.batch(); + jsonData.forEach((doc) => { + // ignore trains with longitudes or latitudes equal zero + if (!(doc["TrainLongitude"] == 0 || doc["TrainLatitude"] == 0)) { + doc["TrainType"] = [trainTypeCode] + var docID = db.collection('liveTrainData').doc(doc["TrainCode"][0]); + batchWrite.set(docID, doc); + } + }); + batchWrite.commit() + }) + } - batchWrite.commit().then(function () { - response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"}); - }); + response.set('Access-Control-Allow-Origin', '*'); + response.set('Access-Control-Allow-Credentials', 'true'); + cors(request, response, () => { + // fetch mainland trains + axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=M').then(res => { + // XML to JSON + parseString(res.data, function(err, result) { + let jsonData = parseJSON(result) + + // batch delete all of the liveTrainData collections's documents + var db = admin.firestore(); + admin.firestore().collection('liveTrainData').get().then((snapshot) => { + var batchDelete = db.batch(); + snapshot.forEach(doc => { + batchDelete.delete(doc.ref); + }); + + batchDelete.commit().then(function() { + // batch write all station JSON objects to the liveTrainData collection + batchWriteDB(request, response, db, jsonData, "M"); + + // fetch suburban trains + axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=S').then(res => { + parseString(res.data, function(err, result) { + let jsonData = parseJSON(result) + batchWriteDB(request, response, db, jsonData, "S"); + + // fetch dart trains + axios.get('https://api.irishrail.ie/realtime/realtime.asmx/getCurrentTrainsXML_WithTrainType?TrainType=D').then(res => { + parseString(res.data, function(err, result) { + let jsonData = parseJSON(result) + batchWriteDB(request, response, db, jsonData, "D"); + response.send({data: "Successfully fetched and uploaded live train data from Irish Rail"}); }) + }) }) }) }) - .catch((error) => {; - response.send({data: "Error fetching data from the IrishRail API"}); - }) - }); + }) + }) + }) + }) }) \ No newline at end of file diff --git a/functions/package-lock.json b/functions/package-lock.json index 634926f..7a3c1ba 100644 --- a/functions/package-lock.json +++ b/functions/package-lock.json @@ -9,6 +9,7 @@ "axios": "^1.3.3", "chai": "^4.3.7", "chai-http": "^4.3.0", + "cors": "^2.8.5", "firebase": "^9.17.1", "firebase-admin": "^11.5.0", "firebase-functions": "^4.2.0", diff --git a/functions/package.json b/functions/package.json index c7c283b..3192bf0 100644 --- a/functions/package.json +++ b/functions/package.json @@ -17,6 +17,7 @@ "axios": "^1.3.3", "chai": "^4.3.7", "chai-http": "^4.3.0", + "cors": "^2.8.5", "firebase": "^9.17.1", "firebase-admin": "^11.5.0", "firebase-functions": "^4.2.0", diff --git a/functions/test/index.test.js b/functions/test/index.test.js index d8e5961..ce172dc 100644 --- a/functions/test/index.test.js +++ b/functions/test/index.test.js @@ -6,7 +6,7 @@ const expect = chai.expect; describe('Firebase cloud function tests', function() { this.timeout(100000); - it('Test getting live train data', async() => { + it('Test getting live train data from the database', async() => { const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') .get('/getLiveTrainData') expect(result.statusCode).to.equal(200); @@ -18,6 +18,20 @@ describe('Firebase cloud function tests', function() { expect(result.body.data[0]).haveOwnProperty('TrainLongitude'); expect(result.body.data[0]).haveOwnProperty('TrainCode'); expect(result.body.data[0]).haveOwnProperty('TrainDate'); + expect(result.body.data[0]).haveOwnProperty('TrainType'); + }), + + this.timeout(100000); + it('Test getting station data from the database', async() => { + const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') + .get('/getStationData') + expect(result.statusCode).to.equal(200); + expect(result.body.data).to.be.an('Array'); + expect(result.body.data[0]).haveOwnProperty('StationDesc'); + expect(result.body.data[0]).haveOwnProperty('StationLatitude'); + expect(result.body.data[0]).haveOwnProperty('StationLongitude'); + expect(result.body.data[0]).haveOwnProperty('StationCode'); + expect(result.body.data[0]).haveOwnProperty('StationId'); }), this.timeout(100000); @@ -27,19 +41,6 @@ describe('Firebase cloud function tests', function() { expect(result.statusCode).to.equal(200); }), - this.timeout(100000); - it('test getting station data', async() => { - const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') - .get('/getStationData') - expect(result.statusCode).to.equal(200); - expect(result.body.data).to.be.an('Array'); - expect(result.body.data[0]).haveOwnProperty('StationDesc'); - expect(result.body.data[0]).haveOwnProperty('StationLatitude'); - expect(result.body.data[0]).haveOwnProperty('StationLongitude'); - expect(result.body.data[0]).haveOwnProperty('StationCode'); - expect(result.body.data[0]).haveOwnProperty('StationId'); - }) - this.timeout(100000); it('Test updating the database with live station data', async() => { const result = await chai.request('https://us-central1-irishrailtracker.cloudfunctions.net') diff --git a/package-lock.json b/package-lock.json index a52ed87..35360be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "ol": "^7.2.2", "vue": "^3.2.45", "vue-loading-overlay": "^6.0.3", + "vue-router": "^4.1.6", "vue3-openlayers": "^0.1.71" }, "devDependencies": { @@ -1121,6 +1122,11 @@ "@vue/shared": "3.2.45" } }, + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, "node_modules/@vue/reactivity": { "version": "3.2.45", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", @@ -2201,6 +2207,20 @@ "vue": "^3.2.0" } }, + "node_modules/vue-router": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz", + "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==", + "dependencies": { + "@vue/devtools-api": "^6.4.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/vue3-openlayers": { "version": "0.1.71", "resolved": "https://registry.npmjs.org/vue3-openlayers/-/vue3-openlayers-0.1.71.tgz", diff --git a/package.json b/package.json index fef980b..0974d79 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "ol": "^7.2.2", "vue": "^3.2.45", "vue-loading-overlay": "^6.0.3", + "vue-router": "^4.1.6", "vue3-openlayers": "^0.1.71" }, "devDependencies": { diff --git a/src/App.vue b/src/App.vue index 166abed..ccbcd97 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,9 +1,8 @@ \ No newline at end of file diff --git a/src/pages/MapPage.vue b/src/pages/MapPage.vue new file mode 100644 index 0000000..cdef6c2 --- /dev/null +++ b/src/pages/MapPage.vue @@ -0,0 +1,364 @@ + + + + + \ No newline at end of file diff --git a/src/router/routes.js b/src/router/routes.js new file mode 100644 index 0000000..0716a20 --- /dev/null +++ b/src/router/routes.js @@ -0,0 +1,7 @@ +function loadPage(component) { + return () => import(`@/pages/${component}.vue`) +} +export default [ + {path: "/", component:loadPage("MapPage")}, + {path: "/insights", component:loadPage("InsightsPage")} +] \ No newline at end of file diff --git a/src/store/store.js b/src/store/store.js new file mode 100644 index 0000000..627fa79 --- /dev/null +++ b/src/store/store.js @@ -0,0 +1,17 @@ +import { reactive } from 'vue' + +export const store = reactive({ + insights: {}, + latestTrain: {}, + earliestTrain: {}, + + setInsights(insights) { + this.insights = insights + }, + setLatestTrain(latestTrain) { + this.latestTrain = latestTrain + }, + setEarliestTrain(earliestTrain) { + this.earliestTrain = earliestTrain + } +}) \ No newline at end of file