diff --git a/server.cjs b/server.cjs index d8160fc..bc882c2 100644 --- a/server.cjs +++ b/server.cjs @@ -573,17 +573,39 @@ function numberHeader(req, name, min, max) { return value } +const CITY_COORDINATE_OVERRIDES = new Map([ + ['GB|ENGLAND|MILTON KEYNES', { latitude: 52.0406, longitude: -0.7594 }], +]) + +function normalizedLocationKey(location) { + return [ + String(location.country || '').trim().toUpperCase(), + String(location.region || '').trim().toUpperCase(), + String(location.city || '').trim().toUpperCase(), + ].join('|') +} + +function normalizeLocationSignal(location) { + const override = CITY_COORDINATE_OVERRIDES.get(normalizedLocationKey(location)) + if (!override) return location + return { + ...location, + latitude: override.latitude, + longitude: override.longitude, + } +} + function locationFromHeaders(req) { if (!requestPeerIsTrusted(req) || TRUST_PROXY !== 'cloudflare') { - return { country: countryFromHeaders(req), region: '', city: '', latitude: null, longitude: null } + return normalizeLocationSignal({ country: countryFromHeaders(req), region: '', city: '', latitude: null, longitude: null }) } - return { + return normalizeLocationSignal({ country: countryFromHeaders(req), region: headerValue(req, 'cf-region', 120), city: headerValue(req, 'cf-ipcity', 120), latitude: numberHeader(req, 'cf-iplatitude', -90, 90), longitude: numberHeader(req, 'cf-iplongitude', -180, 180), - } + }) } function sanitizeAnalyticsValue(value, depth = 0) { @@ -1076,7 +1098,7 @@ function viewerDashboard() { city: row.city, latitude: row.latitude, longitude: row.longitude, - })) + })).map(normalizeLocationSignal) const activePageMap = new Map() for (const viewer of active) { @@ -1363,7 +1385,7 @@ function viewerDashboard() { group by country, region, city, latitude, longitude, timezone, language order by visitors desc, events desc limit 32 - `).all(daySince) + `).all(daySince).map(normalizeLocationSignal) const locations = db.prepare(` select @@ -1383,7 +1405,7 @@ function viewerDashboard() { group by country, region, city, latitude, longitude, timezone, language order by visitors desc, events desc limit 32 - `).all(thirtyDaysSince) + `).all(thirtyDaysSince).map(normalizeLocationSignal) const totals = db.prepare(` select