Skip to content

Commit

Permalink
osmApi: refactor – break up osmApi.ts (#884)
Browse files Browse the repository at this point in the history
  • Loading branch information
zbycz authored Jan 10, 2025
1 parent 537ead8 commit c41f739
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 184 deletions.
2 changes: 1 addition & 1 deletion pages/api/og-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
ImageDefFromCenter,
ImageDefFromTag,
} from '../../src/services/types';
import { fetchWithMemberFeatures } from '../../src/services/osm/osmApi';
import { getImageFromApi } from '../../src/services/images/getImageFromApi';
import { getLogo, ProjectLogo } from '../../src/server/images/logo';
import { ImageType } from '../../src/services/images/getImageDefs';
Expand All @@ -21,6 +20,7 @@ import { svg2png } from '../../src/server/images/svg2png';
import { Size } from '../../src/components/FeaturePanel/FeatureImages/types';
import { getApiId } from '../../src/services/helpers';
import { renderStyledHtml } from '../../src/server/images/renderStyledHtml';
import { fetchWithMemberFeatures } from '../../src/services/osm/fetchWithMemberFeatures';

const Svg = ({ children, size }) => (
<UserThemeProvider userThemeCookie={undefined}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EditDataItem, Members } from '../useEditItems';
import { getApiId, getShortId } from '../../../../services/helpers';
import { getOsmElement } from '../../../../services/osm/osmApi';
import { getOsmElement } from '../../../../services/osm/quickFetchFeature';
import { useEditContext } from '../EditContext';
import { useFeatureEditData } from './FeatureEditSection/SingleFeatureEditContext';
import React from 'react';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
useTheme,
} from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { fetchParentFeatures } from '../../../../services/osm/osmApi';
import { fetchParentFeatures } from '../../../../services/osm/fetchParentFeatures';
import { getApiId, getShortId } from '../../../../services/helpers';
import { FeatureRow } from './FeatureRow';
import { t } from '../../../../services/intl';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import React from 'react';
import { EditDataItem } from '../useEditItems';
import { useEditContext } from '../EditContext';
import { getApiId, getShortId } from '../../../../services/helpers';
import { getFullFeatureWithMemberFeatures } from '../../../../services/osm/osmApi';

import { getFullFeatureWithMemberFeatures } from '../../../../services/osm/getFullFeatureWithMemberFeatures';

const CharacterCountContainer = styled.div`
position: absolute;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useEditContext } from './EditContext';
import { createNoteText } from './createNoteText';
import { t } from '../../../services/intl';
import { saveChanges } from '../../../services/osm/osmApiAuth';
import { insertOsmNote } from '../../../services/osm/osmApi';
import { insertOsmNote } from '../../../services/osm/insertOsmNote';
import { useSnackbar } from '../../utils/SnackbarContext';
import { getShortId } from '../../../services/helpers';

Expand Down
2 changes: 1 addition & 1 deletion src/components/Map/behaviour/maptilerFix.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Feature, OsmId } from '../../../services/types';
import { getShortId } from '../../../services/helpers';
import { quickFetchFeature } from '../../../services/osm/osmApi';
import { quickFetchFeature } from '../../../services/osm/quickFetchFeature';
import { MapGeoJSONFeature } from 'maplibre-gl';

const isFarAway = (feature: Feature, skeleton: Feature) =>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Map/behaviour/useOnMapClicked.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createMapEventHook, isMobileDevice } from '../../helpers';
import pickBy from 'lodash/pickBy';
import { addFeatureCenterToCache } from '../../../services/osm/osmApi';
import { addFeatureCenterToCache } from '../../../services/osm/featureCenterToCache';
import { getOsmappLink, getShortId } from '../../../services/helpers';
import {
getRoundedPosition,
Expand Down
2 changes: 1 addition & 1 deletion src/components/SearchBox/onSelectedFactory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Router, { NextRouter } from 'next/router';
import { getApiId, getShortId, getUrlOsmId } from '../../services/helpers';
import { addFeatureCenterToCache } from '../../services/osm/osmApi';
import { addFeatureCenterToCache } from '../../services/osm/featureCenterToCache';
import { getOverpassSource } from '../../services/mapStorage';
import { performOverpassSearch } from '../../services/overpass/overpassSearch';
import { t } from '../../services/intl';
Expand Down
3 changes: 2 additions & 1 deletion src/services/osm/__tests__/osmApi.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { addFeatureCenterToCache, fetchFeature } from '../osmApi';
import { fetchFeature } from '../osmApi';
import { addFeatureCenterToCache } from '../featureCenterToCache';
import * as helpers from '../../../components/helpers';
import * as fetch from '../../fetch';
import {
Expand Down
13 changes: 13 additions & 0 deletions src/services/osm/featureCenterToCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { LonLat } from '../types';
import { publishDbgObject } from '../../utils';

/**
* This holds coords of clicked ways/relations (from vector map), these are often different than those computed by us
* TODO: we should probably store just the last one, but this cant get too big, right?
*/
export const featureCenterCache: Record<string, LonLat> = {};

export const addFeatureCenterToCache = (shortId: string, center: LonLat) => {
featureCenterCache[shortId] = center;
publishDbgObject('featureCenterCache', featureCenterCache);
};
15 changes: 15 additions & 0 deletions src/services/osm/fetchParentFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { OsmId } from '../types';
import { fetchJson } from '../fetch';
import { getOsmParentUrl } from './urls';
import { addSchemaToFeature } from '../tagging/idTaggingScheme';
import { osmToFeature } from './osmToFeature';

const getOsmParentPromise = async (apiId: OsmId) => {
const { elements } = await fetchJson(getOsmParentUrl(apiId));
return { elements };
};

export const fetchParentFeatures = async (apiId: OsmId) => {
const { elements } = await getOsmParentPromise(apiId);
return elements.map((element) => addSchemaToFeature(osmToFeature(element)));
};
26 changes: 26 additions & 0 deletions src/services/osm/fetchWithMemberFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Feature, OsmId } from '../types';
import { fetchJson } from '../fetch';
import { getOsmFullUrl, getOsmUrl } from './urls';
import { addSchemaToFeature } from '../tagging/idTaggingScheme';
import { osmToFeature } from './osmToFeature';
import { getItemsMap, getMemberFeatures } from './helpers';
import { mergeMemberImageDefs } from '../images/getImageDefs';

export const fetchWithMemberFeatures = async (apiId: OsmId) => {
if (apiId.type !== 'relation') {
const wayOrNodeResponse = await fetchJson(getOsmUrl(apiId));
const wayOrNode = wayOrNodeResponse.elements[0];
return addSchemaToFeature(osmToFeature(wayOrNode));
}

const full = await fetchJson(getOsmFullUrl(apiId));
const map = getItemsMap(full.elements);
const relation = map.relation[apiId.id];

const out: Feature = {
...addSchemaToFeature(osmToFeature(relation)),
memberFeatures: getMemberFeatures(relation.members, map),
};
mergeMemberImageDefs(out);
return out;
};
15 changes: 15 additions & 0 deletions src/services/osm/getCountryCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Feature } from '../types';
import { resolveCountryCode } from 'next-codegrid';
import * as Sentry from '@sentry/nextjs';

export const getCountryCode = async (
feature: Feature,
): Promise<string | null> => {
try {
return await resolveCountryCode(feature.center); // takes 0-100ms for first resolution, then instant
} catch (e) {
console.warn('countryCode left empty – resolveCountryCode():', e); // eslint-disable-line no-console
Sentry.captureException(e, { extra: { feature } });
}
return null;
};
21 changes: 21 additions & 0 deletions src/services/osm/getFullFeatureWithMemberFeatures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { OsmId } from '../types';
import { fetchSchemaTranslations } from '../tagging/translations';
import { fetchJson } from '../fetch';
import { OsmResponse } from './types';
import { getOsmUrlOrFull } from './urls';
import { getItemsMap, getMemberFeatures } from './helpers';
import { addSchemaToFeature } from '../tagging/idTaggingScheme';
import { osmToFeature } from './osmToFeature';

export const getFullFeatureWithMemberFeatures = async (apiId: OsmId) => {
await fetchSchemaTranslations();
const full = await fetchJson<OsmResponse>(getOsmUrlOrFull(apiId));
const itemsMap = getItemsMap(full.elements);
const feature = addSchemaToFeature(
osmToFeature(itemsMap[apiId.type][apiId.id]),
);
return {
...feature,
memberFeatures: getMemberFeatures(feature.members, itemsMap),
};
};
39 changes: 39 additions & 0 deletions src/services/osm/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { OsmElement } from './types';
import { Feature } from '../types';
import { addSchemaToFeature } from '../tagging/idTaggingScheme';
import { osmToFeature } from './osmToFeature';

export const getItemsMap = (elements: OsmElement[]) => {
const itemsMap = {
node: {} as Record<number, OsmElement<'node'>>,
way: {} as Record<number, OsmElement<'way'>>,
relation: {} as Record<number, OsmElement<'relation'>>,
};
elements.forEach((element) => {
itemsMap[element.type][element.id] = element;
});
return itemsMap;
};

export const getMemberFeatures = (
members: Feature['members'],
itemsMap: ReturnType<typeof getItemsMap>,
) =>
(members ?? [])
.map(({ type, ref, role }) => {
const element = itemsMap[type][ref];
if (!element) {
return null;
}

const feature = addSchemaToFeature(osmToFeature(element));
feature.osmMeta.role = role;

// TODO this code is not used, but it had some meaning, leaving for now :)
// feature.center = element.center
// ? [element.center.lon, element.center.lat] // from overpass "out center"
// : feature.center;

return feature;
})
.filter(Boolean);
29 changes: 29 additions & 0 deletions src/services/osm/insertOsmNote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Position, SuccessInfo } from '../types';
import { fetchJson } from '../fetch';
import { API_SERVER, OSM_WEBSITE } from './consts';

export const insertOsmNote = async (
point: Position,
text: string,
): Promise<SuccessInfo> => {
const [lon, lat] = point;

const body = new URLSearchParams();
body.append('lat', `${lat}`);
body.append('lon', `${lon}`);
body.append('text', text);

// {"type":"Feature","geometry":{"type":"Point","coordinates":[14.3244982,50.0927863]},"properties":{"id":26569,"url":"https://master.apis.dev.openstreetmap.org/api/0.6/notes/26569.json","comment_url":"https://master.apis.dev.openstreetmap.org/api/0.6/notes/26569/comment.json","close_url":"https://master.apis.dev.openstreetmap.org/api/0.6/notes/26569/close.json","date_created":"2021-04-17 10:37:44 UTC","status":"open","comments":[{"date":"2021-04-17 10:37:44 UTC","action":"opened","text":"way/39695868! Place was marked permanently closed.From https://osmapp.org/way/39695868","html":"\u003cp\u003eway/39695868! Place was marked permanently closed.From \u003ca href=\"https://osmapp.org/way/39695868\" rel=\"nofollow noopener noreferrer\"\u003ehttps://osmapp.org/way/39695868\u003c/a\u003e\u003c/p\u003e"}]}}
const reply = await fetchJson(`${API_SERVER}/api/0.6/notes.json`, {
nocache: true,
method: 'POST',
body,
});

const noteId = reply.properties.id;
return {
type: 'note',
text,
url: `${OSM_WEBSITE}/note/${noteId}`,
};
};
Loading

0 comments on commit c41f739

Please sign in to comment.