place-contrib: community hours in the details' own shape, and no origin rows for collection copies

Community opening hours laid over OSM details now go through the same parser
as OSM's own, so they arrive as one line per day with open-now and the periods,
and a community description lands in the details' summary. A place copied from
a collection no longer records its values as an import: without an origin row a
value is never sent anyway, and a later edit marks only the fields it changes.
This commit is contained in:
Maurice
2026-10-30 21:04:15 +01:00
parent f01ffc2c67
commit 04458bee12
8 changed files with 19 additions and 23 deletions
-1
View File
@@ -491,7 +491,6 @@ export async function createPluginRpcHostParts(
usersRepo,
buildPlaceImportService(),
places,
placeOriginsStub(),
);
// After accommodations: a hotel booking writes the stay's day stop through it.
const reservations = new ReservationsService(
@@ -120,9 +120,6 @@ const removeIfUnreferenced = (id: string) => photoCache.removeIfUnreferenced(id)
// (part B) finished the conversion: `DatabaseService` is GONE from the constructor
// entirely (savePlace onward was its last use) — the trip/place/tag/user
// repositories below are Task 2's own additions.
// The origin bookkeeping after a copy; its own suite is place-origins.service.test.ts.
const originsForSpy = { recordImported: vi.fn(async () => undefined) };
beforeAll(async () => {
tripsRepoForSpy = await createTestTripsRepo(testDb);
permissionsForSpy = new PermissionsService(await createTestAppSettingsRepo(testDb), await createTestUnitOfWork(testDb));
@@ -137,7 +134,6 @@ beforeAll(async () => {
await createTestTagsRepo(testDb), await createTestUsersRepo(testDb),
buildPlaceImportService(),
placesHooks as never,
originsForSpy as never,
);
photoCache = new PlacePhotoCacheService(
makeStorageFixture('photos/google/').storage,
@@ -508,8 +504,6 @@ describe('copyToTrip', () => {
const res = await svc.copyToTrip(u.id, { trip_id: trip.id, place_ids: [p1.id, p2.id] }, copyEvents(trip.id));
expect(res.copied).toBe(1);
expect(res.skipped.map((s) => s.name)).toEqual(['Pantheon']);
// What was copied is the collection's, so it is recorded as an import, never as typed.
expect(originsForSpy.recordImported).toHaveBeenLastCalledWith(res.created.map((c) => c.id));
const inserted = (await findRow(await orm(), Places, { trip: trip.id, name: 'Colosseum' }))!;
expect(inserted.reservation_status).toBe('none'); // itinerary column took the table default
@@ -40,11 +40,12 @@ describe('community values on OSM details', () => {
expect(got.website).toMatch(/^https:\/\/www\.skybldg\.co\.jp\/?$/);
expect(got).toMatchObject({
phone: '+81 6 6440 3855',
opening_hours: 'Mo-Su 09:30-22:30',
description: 'A tower of two linked blocks.',
summary: 'A tower of two linked blocks.',
community_version: 3,
name: 'Umeda Sky Building',
});
expect(got.opening_hours).toEqual(expect.arrayContaining(['Monday: 09:30-22:30', 'Sunday: 09:30-22:30']));
expect(got.opening_periods).toBeTruthy();
expect(got.email).toBeUndefined();
});
+3 -6
View File
@@ -1925,13 +1925,10 @@ describe('getPlaceDetails (fetch stubbed)', () => {
expect(place.lat).toBeCloseTo(48.85);
expect(place.lng).toBeCloseTo(2.29);
expect(place.source).toBe('openstreetmap');
// Overpass first, then Nominatim, then the community values for the element
// from the TREK index, which answer nothing here and leave the details as they are.
// Overpass, then Nominatim, then the element's community values, of which none are published here.
expect(fetchMock).toHaveBeenCalledTimes(3);
const overpassUrl = fetchMock.mock.calls[0][0] as string;
const nominatimUrl = fetchMock.mock.calls[1][0] as string;
expect(overpassUrl).toContain('overpass');
expect(nominatimUrl).toContain('nominatim');
expect(fetchMock.mock.calls[0][0] as string).toContain('overpass');
expect(fetchMock.mock.calls[1][0] as string).toContain('nominatim');
expect(String(fetchMock.mock.calls[2][0])).toContain('/v1/community?keys=osm%3Away%2F5');
});
+1 -1
View File
@@ -320,7 +320,7 @@ it("OSM-PHOTON-021: an element in TREK's own details layer asks no Overpass, and
const details = await osm.elementDetails('way:518071791', 'en');
expect(details).toMatchObject({
website: 'https://example.org',
opening_hours: '24/7',
opening_hours: expect.arrayContaining(['Monday: 00:00-24:00']),
phone: '+49 30 1234567',
community_version: 2,
lat: 52.5163,