diff --git a/.env.example b/.env.example index f974264..d53b548 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,8 @@ DB_HOST=dbhosthere DB_USER=dbuserhere DB_PASSWORD=dbpasshere WEBSITE_ACCESS_TOKEN=access restriction token +HERALD_TOKEN=randomstringhere PORT=8080 TZ=America/New_York CHOREBOT_VERIFICATION_TOKEN=chorebot token here +ENV=dev diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml new file mode 100644 index 0000000..0a49c2d --- /dev/null +++ b/.github/workflows/dev.yaml @@ -0,0 +1,18 @@ +name: deploy headsup dev + +on: + push: + branches: + - dev +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: executing remote ssh commands using password + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.TIEMS_DEV1_URL }} + username: ${{ secrets.TIEMS_DEV1_SSH_USERNAME }} + password: ${{ secrets.TIEMS_DEV1_SSH_PASSWORD }} + script: ${{ secrets.TIEMS_DEV1_SSH_SCRIPT }} headsup diff --git a/README.md b/README.md index 5d0714a..1b57faf 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://cloud.drone.io/api/badges/rpiambulance/headsup/status.svg)](https://cloud.drone.io/rpiambulance/headsup) +[![deploy headsup](https://github.com/techinems/headsup/actions/workflows/main.yml/badge.svg)](https://github.com/techinems/headsup/actions/workflows/main.yml) [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/made-with-javascript.svg)](https://forthebadge.com) diff --git a/package-lock.json b/package-lock.json index 24cf2b6..3eb8dcb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "headsup", - "version": "1.4.3", + "version": "1.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "headsup", - "version": "1.4.3", + "version": "1.5.0", "license": "MIT", "dependencies": { "express": "^4.18.2", diff --git a/package.json b/package.json index bd76e1d..f1c8a23 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "headsup", - "version": "1.4.3", + "version": "1.5.0", "description": "RPIA's digital whiteboard system", "main": "server.js", "scripts": { diff --git a/public/css/style-dark.min.css.map b/public/css/style-dark.min.css.map new file mode 100644 index 0000000..fae0dbe --- /dev/null +++ b/public/css/style-dark.min.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["style-dark.scss"],"names":[],"mappings":"AAAA,KACE,iCACA,sBACA,WAGF,GACE,0CAGF,QACE,yBACA,eACA,WACA,eAEA,eACE,YAGF,kBACE,iBAGF,cACE,iBACA,WAKJ,SACE,gBAGF,iBACE,yBACA,eACA,WACA,mBACA,cAIA,oCACE,eAGF,uBACE,iBACA,UACA,oBACA,gBACA,6CAEA,kCACE,gBACA,gBACA,iBAGF,8BACE,cACA,eACA,WACA,yBACA,cAGF,6BACE,eACA,cACA,gBAGF,2BACE,iBACA,eACA,WAGF,+BACE,yBACA,WACA,eAEA,uCACE,YAGF,sCACE,YAMR,aACE,2CACA,cAEA,0BACE,kBACA,gBAGF,4BACE,kBACA,gBAIJ,QACE,eAGF,SACE,eACA,UACA,oBACA,gBACA,6CAEA,oBACE,gBACA,gBACA","file":"style-dark.min.css"} \ No newline at end of file diff --git a/public/css/style-dark.scss b/public/css/style-dark.scss index c20cecf..8d0276a 100644 --- a/public/css/style-dark.scss +++ b/public/css/style-dark.scss @@ -126,4 +126,4 @@ hr { margin-bottom: 0; padding-bottom: 0; } -} +} \ No newline at end of file diff --git a/public/css/style-dispatch.min.css b/public/css/style-dispatch.min.css new file mode 100644 index 0000000..240d08c --- /dev/null +++ b/public/css/style-dispatch.min.css @@ -0,0 +1 @@ +@keyframes dispatchBackground{from{background-color:#4a0000}to{background-color:#5a0000}}body{height:100vh;animation:dispatchBackground .5s infinite cubic-bezier(0, 1, 1, 1) alternate;color:#fff;font-weight:700}#dispatch{font-size:100px;text-transform:capitalize}#dispatch-filler{height:200px;font-size:60px;color:#e5e5e5}#determinant{border-radius:100px;text-transform:uppercase}.alpha{background:#9bda9b;color:#000}.bravo{background:#ece68d;color:#000}.charlie{background:#f09442;color:#020004}.delta{background:#b10000;color:#fff}.echo{background:#000;color:#ff1f1f}/*# sourceMappingURL=style-dispatch.min.css.map */ diff --git a/public/css/style-dispatch.min.css.map b/public/css/style-dispatch.min.css.map new file mode 100644 index 0000000..3ac928a --- /dev/null +++ b/public/css/style-dispatch.min.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["style-dispatch.scss"],"names":[],"mappings":"AAAA,8BACE,KACE,yBAEF,GACE,0BAIJ,KACE,aAEA,6EACA,WACA,gBAGF,UACE,gBACA,0BAGF,iBACE,aACA,eACA,cAGF,aACE,oBACA,yBAGF,OACE,mBACA,WAGF,OACE,mBACA,WAGF,SACE,mBACA,cAGF,OACE,mBACA,WAGF,MACE,gBACA","file":"style-dispatch.min.css"} \ No newline at end of file diff --git a/public/css/style-dispatch.scss b/public/css/style-dispatch.scss new file mode 100644 index 0000000..507367b --- /dev/null +++ b/public/css/style-dispatch.scss @@ -0,0 +1,58 @@ +@keyframes dispatchBackground { + from{ + background-color: #4a0000; + } + to{ + background-color: #5a0000; + } +} + +body { + height: 100vh; + // background-color: #952525; + animation: dispatchBackground .5s infinite cubic-bezier(0, 1, 1, 1) alternate; + color: white; + font-weight: 700; +} + +#dispatch{ + font-size: 100px; + text-transform: capitalize; +} + +#dispatch-filler { + height: 200px; + font-size: 60px; + color: #e5e5e5; +} + +#determinant { + border-radius: 100px; + text-transform: uppercase; +} + +.alpha { + background: #9bda9b; + color: black; +} + +.bravo { + background: #ece68d; + color: black; +} + +.charlie { + background: #f09442; + color: #020004; +} + +.delta { + background: #b10000; + color: #fff; +} + +.echo { + background: #000; + color: #ff1f1f; +} + diff --git a/public/css/style.min.css.map b/public/css/style.min.css.map new file mode 100644 index 0000000..690c527 --- /dev/null +++ b/public/css/style.min.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["style.scss"],"names":[],"mappings":"AAAA,KACE,iCAGF,QACE,sBACA,eACA,WACA,eAEA,eACE,YAGF,kBACE,iBAIJ,MACE,iBACA,WAGF,SACE,gBAGF,iBACE,yBACA,eACA,WACA,mBACA,cAIA,oCACE,eAGF,uBACE,iBACA,UACA,oBACA,gBACA,uCAEA,kCACE,gBACA,gBACA,iBAGF,8BACE,cACA,eACA,WACA,yBACA,cAGF,6BACE,eACA,cACA,gBAGF,2BACE,iBACA,eACA,WAGF,+BACE,yBACA,WACA,eAEA,uCACE,YAGF,sCACE,YAMR,aACE,qCACA,cAEA,0BACE,kBACA,gBAGF,4BACE,kBACA,gBAIJ,QACE,eAGF,SACE,eACA,UACA,oBACA,gBACA,uCAEA,oBACE,gBACA,gBACA","file":"style.min.css"} \ No newline at end of file diff --git a/public/css/style.scss b/public/css/style.scss index 1ca5a18..608c6d6 100644 --- a/public/css/style.scss +++ b/public/css/style.scss @@ -119,4 +119,4 @@ body { margin-bottom: 0; padding-bottom: 0; } -} +} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 5e03e3b..0a75f6b 100644 --- a/public/index.html +++ b/public/index.html @@ -8,7 +8,7 @@ - + @@ -27,63 +27,91 @@ -
-
-
Today's crew
-
-
- Crew chief - + +
+
+
+
Today's crew
+
+
+ Crew chief + +
+
+
+
+ Driver + +
-
-
-
- Driver - +
+
+ Attendant + +
-
-
-
- Attendant - +
+
+ Attendant + +
-
-
-
- Attendant - +
+
+ Duty supervisor + +
-
-
- Duty supervisor - -
+
+
Calls to date
+
+
+
Dispatch mishaps
+
-
-
Calls to date
-
-
-
Dispatch mishaps
-
-
-
-
-
-
-
-
-
Chores
+
+
+
+
+
+
Chores
Notes
- + +
+ + + + +
diff --git a/public/js/admin.js b/public/js/admin.js index f7a6dfa..8d24936 100644 --- a/public/js/admin.js +++ b/public/js/admin.js @@ -86,7 +86,10 @@ async function addCall() { } async function postToServer(endpoint, body) { - const response = await fetch(endpoint, { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString); + const token = urlParams.get('token'); + const response = await fetch(endpoint + '?token=' + token, { method: 'POST', headers: { 'Content-Type': 'application/json' diff --git a/public/js/whiteboard.js b/public/js/whiteboard.js index 31a0fc0..a61a85f 100644 --- a/public/js/whiteboard.js +++ b/public/js/whiteboard.js @@ -1,137 +1,233 @@ /* global moment, io, SunCalc */ -const longitude = -73.675770; -const latitude = 42.729270; +const longitude = -73.67577; +const latitude = 42.72927; // 30 minutes in milliseconds (60000 ms in 1 min) -const thirtyMinutes = 60000 * 30; +//Time Constants(in Milliseconds) +const oneMinute = 60000; +const thirtyMinutes = oneMinute * 30; +const threeMinutes = oneMinute * 3; + +let dispatchTimeoutID = ""; function cleanRadioNum(id, rn) { - return id > 0 ? rn : ''; + return id > 0 ? rn : ""; } function checkRiderNum(id, rn, radioNums) { - if (id > 0 && rn == 0) { - return radioNums.pop(); - } else { - return rn; - } + if (id > 0 && rn == 0) { + return radioNums.pop(); + } else { + return rn; + } } function updateCrew(crewResponse) { - let crew = crewResponse; - if (!crew.success) { - console.error('Failed to fetch!'); - } else { - const riderRadioNums = [993, 992]; - // Sets the rider's radionums to 992 and 993 if they don't have one - crew.attendant.rn = checkRiderNum(crew.attendant.id, crew.attendant.rn, riderRadioNums); - crew.observer.rn = checkRiderNum(crew.observer.id, crew.observer.rn, riderRadioNums); - document.querySelector('#cc').innerHTML = crew.cc.name; - document.querySelector('#cc-rn').innerHTML = cleanRadioNum(crew.cc.id, crew.cc.rn); - document.querySelector('#driver').innerHTML = crew.driver.name; - document.querySelector('#driver-rn').innerHTML = cleanRadioNum(crew.driver.id, crew.driver.rn); - document.querySelector('#rider1').innerHTML = crew.attendant.name; - document.querySelector('#rider1-rn').innerHTML = cleanRadioNum(crew.attendant.id, crew.attendant.rn); - document.querySelector('#rider2').innerHTML = crew.observer.name; - document.querySelector('#rider2-rn').innerHTML = cleanRadioNum(crew.observer.id, crew.observer.rn); - document.querySelector('#dutysup').innerHTML = crew.dutysup.name; - document.querySelector('#dutysup-rn').innerHTML = cleanRadioNum(crew.dutysup.id, crew.dutysup.rn); - } + let crew = crewResponse; + if (!crew.success) { + console.error("Failed to fetch!"); + } else { + const riderRadioNums = [993, 992]; + // Sets the rider's radionums to 992 and 993 if they don't have one + crew.attendant.rn = checkRiderNum( + crew.attendant.id, + crew.attendant.rn, + riderRadioNums + ); + crew.observer.rn = checkRiderNum( + crew.observer.id, + crew.observer.rn, + riderRadioNums + ); + document.querySelector("#cc").innerHTML = crew.cc.name; + document.querySelector("#cc-rn").innerHTML = cleanRadioNum( + crew.cc.id, + crew.cc.rn + ); + document.querySelector("#driver").innerHTML = crew.driver.name; + document.querySelector("#driver-rn").innerHTML = cleanRadioNum( + crew.driver.id, + crew.driver.rn + ); + document.querySelector("#rider1").innerHTML = crew.attendant.name; + document.querySelector("#rider1-rn").innerHTML = cleanRadioNum( + crew.attendant.id, + crew.attendant.rn + ); + document.querySelector("#rider2").innerHTML = crew.observer.name; + document.querySelector("#rider2-rn").innerHTML = cleanRadioNum( + crew.observer.id, + crew.observer.rn + ); + document.querySelector("#dutysup").innerHTML = crew.dutysup.name; + document.querySelector("#dutysup-rn").innerHTML = cleanRadioNum( + crew.dutysup.id, + crew.dutysup.rn + ); + } } function updateNotes(noteResponse) { - document.querySelector('#notes').innerHTML = ''; - const notes = noteResponse.data; - for (const note of notes) { - const p = document.createElement('p'); - p.textContent = note.note; - document.querySelector('#notes').appendChild(p); - } + document.querySelector("#notes").innerHTML = ""; + const notes = noteResponse.data; + for (const note of notes) { + const p = document.createElement("p"); + p.textContent = note.note; + document.querySelector("#notes").appendChild(p); + } } -function updateCallCount({data}) { - document.querySelector('#total-count').innerHTML = data; +function updateCallCount({ data }) { + document.querySelector("#total-count").innerHTML = data; } -function updateMishapCount({data}) { - document.querySelector('#total-mishaps').innerHTML = data; +function updateMishapCount({ data }) { + document.querySelector("#total-mishaps").innerHTML = data; } function updateDate() { - const todaysDate = moment(); - document.querySelector('#date').innerHTML = todaysDate.format('D MMM YY'); - document.querySelector('#time').innerHTML = todaysDate.format('HH:mm'); - - const times = SunCalc.getTimes(new Date(), latitude, longitude); - const now = Date.now(); - // if the current time falls between 30 minutes after sunrise and - // 30 minutes after sunset, then we use the light stylesheet, otherwise - // use the dark stylesheet. After updating the media attribute, all - // styles are re-applied on the page. - - // default to light mode - if (document.getElementById('stylesheet-light').media == document.getElementById('stylesheet-dark').media) { - document.getElementById('stylesheet-light').media = ''; - document.getElementById('stylesheet-dark').media = 'none'; - } - - const isCurrentlyDay = (times.sunrise.getTime() + thirtyMinutes) <= now - && now < (times.sunset.getTime() + thirtyMinutes) - - const isDarkMode = ( - (document.getElementById('stylesheet-light').media == 'none') && - (document.getElementById('stylesheet-dark').media == '') - ) - - if (isCurrentlyDay && isDarkMode) { - document.getElementById('stylesheet-light').media = ''; - document.getElementById('stylesheet-dark').media = 'none'; - } else if(!isCurrentlyDay && !isDarkMode) { - document.getElementById('stylesheet-light').media = 'none'; - document.getElementById('stylesheet-dark').media = ''; - } + const todaysDate = moment(); + document.querySelector("#date").innerHTML = todaysDate.format("D MMM YY"); + document.querySelector("#time").innerHTML = todaysDate.format("HH:mm"); + + const times = SunCalc.getTimes(new Date(), latitude, longitude); + const now = Date.now(); + // if the current time falls between 30 minutes after sunrise and + // 30 minutes after sunset, then we use the light stylesheet, otherwise + // use the dark stylesheet. After updating the media attribute, all + // styles are re-applied on the page. + + // default to light mode + if ( + document.getElementById("stylesheet-light").media == + document.getElementById("stylesheet-dark").media + ) { + document.getElementById("stylesheet-light").media = ""; + document.getElementById("stylesheet-dark").media = "none"; + } + + const isCurrentlyDay = + times.sunrise.getTime() + thirtyMinutes <= now && + now < times.sunset.getTime() + thirtyMinutes; + + const isDarkMode = + document.getElementById("stylesheet-light").media == "none" && + document.getElementById("stylesheet-dark").media == ""; + + if (isCurrentlyDay && isDarkMode) { + document.getElementById("stylesheet-light").media = ""; + document.getElementById("stylesheet-dark").media = "none"; + } else if (!isCurrentlyDay && !isDarkMode) { + document.getElementById("stylesheet-light").media = "none"; + document.getElementById("stylesheet-dark").media = ""; + } } function updateChores(choreList) { - const choreDiv = document.querySelector('#chores'); - choreDiv.innerHTML = ''; - if (choreList.length === 0) { - choreDiv.innerHTML = 'No chores tonight!'; - } else { - const ul = document.createElement('ul'); - for (const chore of choreList) { - const li = document.createElement('li'); - li.innerText = chore; - ul.appendChild(li); - } - choreDiv.appendChild(ul); + const choreDiv = document.querySelector("#chores"); + choreDiv.innerHTML = ""; + if (choreList.length === 0) { + choreDiv.innerHTML = "No chores tonight!"; + } else { + const ul = document.createElement("ul"); + for (const chore of choreList) { + const li = document.createElement("li"); + li.innerText = chore; + ul.appendChild(li); } + choreDiv.appendChild(ul); + } +} + +function clearDispatch() { + dispatchTimeoutID = ""; + document.getElementById("dispatch").hidden = true; + document.getElementById("display").hidden = false; + + document.getElementById("stylesheet-dispatch").media = "none"; + + document.getElementById("determinant").textContent = ""; + document.getElementById("complaint").textContent = ""; + document.getElementById("location").textContent = ""; + + document.getElementById("determinant").className = "determinant mt-3 mb-3"; +} + +function handleDispatch(determinant, complaint, location) { + if (dispatchTimeoutID != "") { + clearTimeout(dispatchTimeoutID); + clearDispatch(); + } + + switch (determinant) { + case "Alpha": + document.getElementById("determinant").classList.add("alpha"); + break; + case "Bravo": + document.getElementById("determinant").classList.add("bravo"); + break; + case "Charlie": + document.getElementById("determinant").classList.add("charlie"); + break; + case "Delta": + document.getElementById("determinant").classList.add("delta"); + break; + case "Echo": + document.getElementById("determinant").classList.add("echo"); + break; + } + + const dispatchTime = moment(); + + document.getElementById( + "dispatch-time" + ).textContent = `Dispatched at: ${dispatchTime.format("HH:mm:ss")}`; + + document.getElementById("determinant").textContent = determinant; + document.getElementById("complaint").textContent = complaint; + document.getElementById("location").textContent = location; + + document.getElementById("stylesheet-dispatch").media = ""; + + document.getElementById("display").hidden = true; + document.getElementById("dispatch").hidden = false; + + dispatchTimeoutID = setTimeout(clearDispatch, threeMinutes); } updateDate(); const socket = io.connect(); -socket.on('notes', (noteResponse) => { - updateNotes(noteResponse); +socket.on("notes", (noteResponse) => { + updateNotes(noteResponse); +}); + +socket.on("crews", (crewResponse) => { + updateCrew(crewResponse); }); -socket.on('crews', (crewResponse) => { - updateCrew(crewResponse); +socket.on("calls", (callResponse) => { + updateCallCount(callResponse); }); -socket.on('calls', (callResponse) => { - updateCallCount(callResponse); +socket.on("mishaps", (mishapResponse) => { + updateMishapCount(mishapResponse); }); -socket.on('mishaps', (mishapResponse) => { - updateMishapCount(mishapResponse); +socket.on("chores", (choreResponse) => { + updateChores(choreResponse.chores); }); -socket.on('chores', (choreResponse) => { - updateChores(choreResponse.chores); +socket.on("dispatch", (dispatchResponse) => { + console.log(dispatchResponse); + handleDispatch( + dispatchResponse["CALL TYPE"].determinant, + dispatchResponse["CALL TYPE"].complaint, + dispatchResponse.LOCATION + ); }); // Refreshes the page allowing us to update the UI without ever touching the tv -socket.on('refresh', () => window.location.reload()); +socket.on("refresh", () => window.location.reload()); setInterval(() => updateDate(), 2000); diff --git a/server.js b/server.js index ac9a9ac..cff2202 100644 --- a/server.js +++ b/server.js @@ -17,12 +17,13 @@ const pool = mariadb.createPool({ user: process.env.DB_USER, password: process.env.DB_PASSWORD, connectionLimit: 10, - charset: 'utf8mb4' + charset: 'utf8mb4', }); // Initialize express app const PORT = process.env.PORT || 8080; const WEBSITE_ACCESS_TOKEN = process.env.WEBSITE_ACCESS_TOKEN; +const HERALD_TOKEN = process.env.HERALD_TOKEN; // app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); @@ -61,29 +62,49 @@ app.get('/notes', async (_, res) => { }); app.post('/call/create', async (req, res) => { - await calls.createCall(pool, req.body); - const response_data = await calls.getTotalCalls(pool); - io.emit('calls', response_data); - res.send(response_data); + if (WEBSITE_ACCESS_TOKEN !== req.query.token) { + res.sendStatus(403); + } + else { + await calls.createCall(pool, req.body); + const response_data = await calls.getTotalCalls(pool); + io.emit('calls', response_data); + res.send(response_data); + } }); app.post('/note/create', async (req, res) => { - const response_data = await notes.createNote(pool, req.body.note); - io.emit('notes', await notes.getNotes(pool)); - res.send(response_data); + if (WEBSITE_ACCESS_TOKEN !== req.query.token) { + res.sendStatus(403); + } + else { + const response_data = await notes.createNote(pool, req.body.note); + io.emit('notes', await notes.getNotes(pool)); + res.send(response_data); + } }); app.post('/note/delete', async (req, res) => { - const response_data = await notes.deleteNote(pool, req.body.note); - io.emit('notes', await notes.getNotes(pool)); - res.send(response_data); + if (WEBSITE_ACCESS_TOKEN !== req.query.token) { + res.sendStatus(403); + } + else { + const response_data = await notes.deleteNote(pool, req.body.note); + io.emit('notes', await notes.getNotes(pool)); + res.send(response_data); + } }); app.post('/mishap/create', async (req, res) => { - await mishap.createMishap(pool, req.body.mishap); - const response_data = await mishap.getTotalMishaps(pool); - io.emit('mishaps', response_data); - res.send(response_data); + if (WEBSITE_ACCESS_TOKEN !== req.query.token) { + res.sendStatus(403); + } + else { + await mishap.createMishap(pool, req.body.mishap); + const response_data = await mishap.getTotalMishaps(pool); + io.emit('mishaps', response_data); + res.send(response_data); + } }); app.get('/mishap', async (_, res) => { @@ -93,7 +114,17 @@ app.get('/mishap', async (_, res) => { app.post('/chores', (req, res) => { io.emit('chores', req.body); - res.send({success: true}); + res.send({ success: true }); +}); + +app.post('/dispatch', (req, res) => { + if (HERALD_TOKEN !== req.query.token) { + res.sendStatus(403); + } else { + console.log('received herald dispatch'); + io.emit('dispatch', req.body); + res.send({ success: true }); + } }); io.on('connection', async () => { diff --git a/src/crews.js b/src/crews.js index 2727770..9b1c80c 100644 --- a/src/crews.js +++ b/src/crews.js @@ -1,6 +1,8 @@ const { execQuery } = require('./db'); const moment = require('moment'); +const DEV = process.env.ENV == 'dev'; + function getQuery(role) { return `SELECT c.${role} AS id, @@ -28,7 +30,7 @@ function cleanName(member) { return { id: 0, name: '', - rn: 0 + rn: 0, }; } @@ -49,14 +51,51 @@ function cleanQueryResult(results) { } exports.getCrew = async (pool) => { + if (DEV) { + const crew = { + success: true, + 'cc': { + id: 1, + name: 'C. Chief', + rn: '901' + }, + 'driver': { + id:2, + name: 'D. Driver', + rn: '902' + }, + 'attendant': { + id:3, + name: 'A. Attendant', + rn: '903' + }, + 'observer': { + id:4, + name: 'O. Observer', + rn: '904' + }, + 'dutysup': { + id:5, + name: 'D. Supervisor', + rn: '910' + }, + }; + return crew; + } try { const date = buildDate(); const crew = { success: true }; - const positions = [ 'cc', 'driver', 'attendant', 'observer', 'dutysup' ]; + const positions = ['cc', 'driver', 'attendant', 'observer', 'dutysup']; - for ( const p of positions ) { - let result = await execQuery(pool, getQuery(p), date, cleanQueryResult, process.env.CREWS_DB_NAME); + for (const p of positions) { + let result = await execQuery( + pool, + getQuery(p), + date, + cleanQueryResult, + process.env.CREWS_DB_NAME + ); crew[p] = cleanName(result); }