From 3b3df1686c8a35bf9f9d501bc628685bc8fd9412 Mon Sep 17 00:00:00 2001 From: Elizabeth Cray Date: Thu, 16 Jul 2026 19:01:24 -0400 Subject: [PATCH] BROKEN: WIP data expansion --- .gitignore | 1 + README.md | 1 + basicauth_serve.js | 141 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 121 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index c2658d7..5f1ad05 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules/ +haze.json diff --git a/README.md b/README.md index eb20df1..bb7bdab 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,4 @@ curl "http://localhost:3000/locations?auth=BASE64_ENCODED_STRING" `basicauth_serve.js` does the same thing bus expects account details to be passed via basic HTTP auth, but does not work with QGIS. +This is from a limitation of express-basic-auth. diff --git a/basicauth_serve.js b/basicauth_serve.js index b1b63bc..54730e1 100644 --- a/basicauth_serve.js +++ b/basicauth_serve.js @@ -5,7 +5,7 @@ const { createHash } = require('crypto'); const app = express(); const port = 8355; -const geonJsonTemplate = { +const geoJsonTemplate = { type: "FeatureCollection", features: [], "marker-symbol-images": { @@ -13,6 +13,35 @@ const geonJsonTemplate = { "star-stroked": "data:image/svg+xml;utf8," } }; +const hazeTranslator = { + category: [ + "Urbex", + "Nature", + "Spontaneous" + ], + difficulty: [ + "Not Sure", + "Baby", + "Walk in the Park", + "Challenge", + "Madman", + "Deathwish" + ], + rating: [ + "Not Sure", + "Check it Out", + "Worth the Trip", + "Must See" + ], + level: [ + "Lost Soul", + "Roamer", + "Adventurer", + "Pathfinder", + "Trailblazer", + "Maven" + ] +}; app.use(auth({ authorizer: (username, password) => { return true; @@ -28,9 +57,11 @@ app.all('/locations.geojson', (req, res) => { // Query Haze API Websocket let hazePwHash = null; let hazeUser = null; + let hazeSocketCounter = 0; + let requestStartTime = new Date().getTime(); if (req.query.auth) { let paramAuth = Buffer.from(req.query.auth, 'base64').toString('utf-8'); - hawUser = paramAuth.split(":")[0]; + hazeUser = paramAuth.split(":")[0]; hazePwHash = paramAuth.split(":")[1]; } else { hazeUser = req.auth.user; @@ -41,6 +72,7 @@ app.all('/locations.geojson', (req, res) => { } } const haze = new WebSocket('wss://do.ecven.com:8120/explr'); + let locations = []; haze.addEventListener('message', (event) => { const data = JSON.parse(event.data); let haze_authToken = '', haze_username = ''; @@ -54,14 +86,14 @@ app.all('/locations.geojson', (req, res) => { "email": hazeUser } ], - "socketMessageId": 0 + "socketMessageId": hazeSocketCounter++ })); break; case "authenticateAccount_response": if (data['body']['response'] === 1) { haze_authToken = data['body']['authToken']; haze_username = data['body']['username']; - haze.send('{"event": "getMyLocationsRequest_request","body": [{"higlightImages": true}],"socketMessageId": 0}'); + haze.send('{"event": "getMyLocationsRequest_request","body": [{"higlightImages": true}],"socketMessageId": ' + hazeSocketCounter++ + '}'); } else { console.dir(req.query); res.status(401).json({ ...data, password: req.auth.password }); @@ -71,26 +103,37 @@ app.all('/locations.geojson', (req, res) => { break; case "getMyLocationsRequest_response": if (data['body']['response'] === 1) { - const hazeLocations = data['body']['locations'].map(location => { - return { - type: "Feature", - geometry: { - type: "Point", - coordinates: [location['coordinates']['longitude'], location['coordinates']['latitude']] - }, - properties: { - id: location['id'], - title: location['name'], - "marker-symbol": location['isUnconfirmedLocation'] === 1 ? "star-stroked" : "star", - } + // locations = data['body']['locations'].map(location => { + // return { + // id: location['id'], + // title: location['name'], + // completed: false + // }; + // }); + data['body']['locations'].forEach(location => { + locations[hazeSocketCounter++] = { + id: location['id'], + title: location['name'], + latitude: location['coordinates']['latitude'], + longitude: location['coordinates']['longitude'], + isExplored: location['explored'] > 0, + isConfirmed: location['isUnconfirmedLocation'] !== 1, + category: hazeTranslator.category[location['locationCategory']], + completed: false + } + }); + + // need to make the socketIDs dynamic and handle completed status before returning final payload + // FIX: Currently throwing response 2 "User does not have access to location." + locations.forEach((location, index) => { + if (location) { + haze.send(JSON.stringify({ + event: "getLocation_request", + body: locations.map(location => location.id), + socketMessageId: index + })); } }); - res.setHeader('Content-Type', 'application/json'); - haze.close(); - res.end(JSON.stringify({ - ...geonJsonTemplate, - features: hazeLocations - })); } else { console.dir(data); res.status(500).send('Failed to retrieve locations'); @@ -98,6 +141,60 @@ app.all('/locations.geojson', (req, res) => { res.end(); } break; + case "getLocation_response": + if (data['body']['response'] === 1) { + locations[data['socketMessageId']] = { + ...locations[data['socketMessageId']], + completed: true, + author: `${data['body']['location']['submittorUserDatas']['username']} (${data['body']['location']['submittorUserDatas']['email']})`, + rating: hazeTranslator.rating[data['body']['location']['locationRating']['overallRating']], + difficulty: hazeTranslator.difficulty[data['body']['location']['locationRating']['difficultyRating']], + level: hazeTranslator.level[data['body']['location']['locationRating']['levelRating']], + // TODO: use body.location.locationRating.ratingItemsList for location tags + comments: data['body']['location']['locationCommentsAndCommunityVotes'].map(comment => ({ + id: comment['id'], + text: comment['comment'], + rating: (comment['upvotes']*1)+(comment['downvotes']* -1), + author: comment['submittor']['username'], + })) + }; + let testTime = (new Date().getTime() - requestStartTime) > 30000; // 30s timeout + if (locations.every(location => location && location.completed) || testTime) { + res.setHeader('Content-Type', 'application/json'); + haze.close(); + res.end(JSON.stringify({ + ...geoJsonTemplate, + features: locations.map(location => ({ + type: "Feature", + geometry: { + type: "Point", + coordinates: [location['longitude'], location['latitude']] + }, + properties: { + id: location['id'], + title: location['name'], + "marker-symbol": location['isUnconfirmedLocation'] === 1 ? "star-stroked" : "star", + author: location['author'] || '', + explored: location['isExplored'] || false, + confirmed: location['isConfirmed'] || false, + category: location['category'] || '', + level: location['level'] || '', + rating: location['rating'] || '', + difficulty: location['difficulty'] || '', + comments: location['comments'] || [], + querySuccess: location['completed'] + } + })) + })); + } + } else { + console.dir(data); + // res.status(500).send('Failed to retrieve locations'); + // haze.close(); + // res.end(); + } + break; + default: console.dir(data); res.status(500).send('Unexpected response from Haze API');