From 9feaca9d0b584d0337eb8395b20c0781a7ea4e5f Mon Sep 17 00:00:00 2001 From: vjrj Date: Fri, 17 Jul 2026 18:31:59 +0200 Subject: [PATCH] fix: fire ids leaked into URLs as ObjectID("...") on Mongo 7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fire collections use idGeneration:'MONGO', so _id is a Mongo.ObjectID whose toString() is ObjectID(""), not the bare hex. Interpolating _id into a URL produced /fire/archive/ObjectID("c0..."), which no route matches -> the fire-detail page 404'd. New hexId() helper returns the 24-char hex for an ObjectID (and passes plain strings through); applied at the three string-context sites: the map-marker click URL (MarkListeners), the active->archive redirect, and the comments referenceId (Fires.js). Left falsePositives.insert untouched — its check() expects a Meteor.Collection.ObjectID, so it takes the object. Verified in browser: /fire/archive/ and /fire/active/ render the detail page (map + comments), URL stays clean hex, no ObjectID( anywhere. --- imports/api/Common/id.js | 15 +++++++++++++++ imports/ui/components/Maps/MarkListeners.js | 5 ++++- imports/ui/pages/Fires/Fires.js | 5 +++-- 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 imports/api/Common/id.js diff --git a/imports/api/Common/id.js b/imports/api/Common/id.js new file mode 100644 index 0000000..d419982 --- /dev/null +++ b/imports/api/Common/id.js @@ -0,0 +1,15 @@ +/* + * Fire/collection docs use `idGeneration: 'MONGO'`, so their `_id` is a + * `Mongo.ObjectID`, whose `.toString()` yields `ObjectID("")` — NOT the + * bare hex. Interpolating an `_id` straight into a URL or any string therefore + * produces `.../fire/archive/ObjectID("...")`, which the routes can't match. + * + * Use `hexId()` wherever an id becomes part of a string (URLs, comment + * reference ids, DOM ids). It returns the 24-char hex for an ObjectID and + * passes plain-string ids through unchanged. Do NOT use it for DDP method + * args whose `check()` expects `Meteor.Collection.ObjectID` — pass the object. + */ +export const hexId = id => + (id && typeof id.toHexString === 'function' ? id.toHexString() : id); + +export default hexId; diff --git a/imports/ui/components/Maps/MarkListeners.js b/imports/ui/components/Maps/MarkListeners.js index 5a85b44..19ffc39 100644 --- a/imports/ui/components/Maps/MarkListeners.js +++ b/imports/ui/components/Maps/MarkListeners.js @@ -1,4 +1,7 @@ +import { hexId } from '/imports/api/Common/id'; + export const onMarkClick = (history, nasa, id) => { // console.log('onClick fired'); - history.push(`/fire/${nasa ? 'active' : 'alert'}/${id}`); + // hexId: `id` is a Mongo.ObjectID whose toString() is `ObjectID("...")`. + history.push(`/fire/${nasa ? 'active' : 'alert'}/${hexId(id)}`); }; diff --git a/imports/ui/pages/Fires/Fires.js b/imports/ui/pages/Fires/Fires.js index 4c79cf5..7790aeb 100644 --- a/imports/ui/pages/Fires/Fires.js +++ b/imports/ui/pages/Fires/Fires.js @@ -18,6 +18,7 @@ import FiresCollection from '/imports/api/Fires/Fires'; import FireList from '/imports/ui/components/Maps/FireList'; import FromNow from '/imports/ui/components/FromNow/FromNow'; import { dateLongFormat, dateYYYYMMDD } from '/imports/api/Common/dates'; +import { hexId } from '/imports/api/Common/id'; import CommentsBox from '/imports/ui/components/Comments/CommentsBox'; import FalsePositiveTypes from '/imports/api/FalsePositives/FalsePositiveTypes'; import FalsePositivesCollection, { falsePositivesRemap } from '/imports/api/FalsePositives/FalsePositives'; @@ -41,7 +42,7 @@ class Fire extends React.Component { // console.log(`Next when ${nextProps.when}`); if (nextProps.fire && (nextProps.alert || nextProps.active || nextProps.fromHash)) { // change url to archive with new _id - nextProps.history.replace(`/fire/archive/${nextProps.fire._id}`); + nextProps.history.replace(`/fire/archive/${hexId(nextProps.fire._id)}`); } this.setState({ loading: nextProps.loading, @@ -232,7 +233,7 @@ class Fire extends React.Component {
- +
}