mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-14 00:01:03 +00:00
feat(collections): edit a saved place's provider ids, website, phone and price (#2646)
The update contract takes google_place_id, google_ftid, osm_id, website, phone, price and currency like saving does, website with the same normalisation and refusal. REST and update_collection_place share it, so an agent can correct a place instead of re-saving it and losing its labels, ratings, position and id. The assistant's change card names the new fields.
This commit is contained in:
@@ -171,6 +171,13 @@ export class CollectionPlacesRepository extends TrekRepository<CollectionPlaces>
|
||||
category_id: number | null;
|
||||
image_url: string | null;
|
||||
links: string | null;
|
||||
google_place_id: string | null;
|
||||
google_ftid: string | null;
|
||||
osm_id: string | null;
|
||||
website: string | null;
|
||||
phone: string | null;
|
||||
price: number | null;
|
||||
currency: string | null;
|
||||
collection_id: number;
|
||||
owner_id: number;
|
||||
}>,
|
||||
|
||||
@@ -77,6 +77,13 @@ const FIELD_OF: Readonly<Record<string, (typeof COLLECTION_CARD_FIELDS)[number]>
|
||||
category_id: 'category',
|
||||
links: 'link',
|
||||
image_url: 'photo',
|
||||
website: 'website',
|
||||
phone: 'phone',
|
||||
price: 'price',
|
||||
currency: 'price',
|
||||
google_place_id: 'mapEntry',
|
||||
google_ftid: 'mapEntry',
|
||||
osm_id: 'mapEntry',
|
||||
};
|
||||
|
||||
function fieldsOf(args: ToolArgs): CollectionCardDelta['fields'] {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionLink } from '@trek/shared';
|
||||
import type { CollectionLink, CollectionPlaceUpdateRequest } from '@trek/shared';
|
||||
|
||||
/**
|
||||
* Pure helpers of the collections domain, moved verbatim out of
|
||||
@@ -20,3 +20,31 @@ export function parseLinks(raw: unknown): CollectionLink[] | undefined {
|
||||
export function serializeLinks(links: CollectionLink[] | undefined): string | null {
|
||||
return links && links.length ? JSON.stringify(links) : null;
|
||||
}
|
||||
|
||||
/** The provider ids, contact and price columns of a saved place, as an update writes them. */
|
||||
type ListingWrite = Partial<{
|
||||
google_place_id: string | null;
|
||||
google_ftid: string | null;
|
||||
osm_id: string | null;
|
||||
website: string | null;
|
||||
phone: string | null;
|
||||
price: number | null;
|
||||
currency: string | null;
|
||||
}>;
|
||||
|
||||
/**
|
||||
* The fields saving a place accepts and editing it did not until #2646: each one
|
||||
* the update names, null clearing it, the rest left out so the stored value stays.
|
||||
* The website arrives normalised and checked by the contract, as on save.
|
||||
*/
|
||||
export function listingWriteOf(body: CollectionPlaceUpdateRequest): ListingWrite {
|
||||
const write: ListingWrite = {};
|
||||
if (body.google_place_id !== undefined) write.google_place_id = body.google_place_id ?? null;
|
||||
if (body.google_ftid !== undefined) write.google_ftid = body.google_ftid ?? null;
|
||||
if (body.osm_id !== undefined) write.osm_id = body.osm_id ?? null;
|
||||
if (body.website !== undefined) write.website = body.website ?? null;
|
||||
if (body.phone !== undefined) write.phone = body.phone ?? null;
|
||||
if (body.price !== undefined) write.price = body.price ?? null;
|
||||
if (body.currency !== undefined) write.currency = body.currency ?? null;
|
||||
return write;
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ export class CollectionsMcp {
|
||||
@Tool({
|
||||
name: 'update_collection_place',
|
||||
description:
|
||||
"Update a saved place's name, address, coordinates (lat/lng), description, notes, status, category, links, tags, labels, image, or move it to another collection (set collection_id). Moving a place out of a list needs the same role there as deleting it (owner or admin).",
|
||||
"Update a saved place's name, address, coordinates (lat/lng), description, notes, status, category, links, tags, labels, image, provider ids (google_place_id, google_ftid, osm_id), website, phone, price and currency, or move it to another collection (set collection_id). Only the fields you pass change; null clears one. A bare domain as website gets https://, any other scheme is refused. Moving a place out of a list needs the same role there as deleting it (owner or admin).",
|
||||
inputSchema: { placeId: idSchema, ...collectionPlaceUpdateRequestSchema.shape, links: linksInput },
|
||||
annotations: TOOL_ANNOTATIONS_WRITE,
|
||||
when: collectionsAddonOn,
|
||||
|
||||
@@ -75,7 +75,7 @@ import type {
|
||||
import { NotificationsService } from '../notifications/notifications.service';
|
||||
import { PlaceImportService, type ExportedCollectionFile } from '../place-import/place-import.service';
|
||||
import { UnitOfWork } from '../database/unit-of-work';
|
||||
import { parseLinks, serializeLinks } from './collections.helpers';
|
||||
import { listingWriteOf, parseLinks, serializeLinks } from './collections.helpers';
|
||||
|
||||
// Errors: a DomainError carrying a status; TrekExceptionFilter maps it to that code with an `{ error }` body.
|
||||
|
||||
@@ -872,7 +872,7 @@ export class CollectionsService {
|
||||
await this.assertCanEdit(userId, currentCollection);
|
||||
const prevImage = body.image_url !== undefined ? (await this.collectionPlaces.imageUrl(placeId)) ?? null : null;
|
||||
|
||||
const write: Parameters<CollectionPlacesRepository['updateFields']>[1] = {};
|
||||
const write: Parameters<CollectionPlacesRepository['updateFields']>[1] = listingWriteOf(body);
|
||||
if (body.name !== undefined) write.name = body.name;
|
||||
if (body.description !== undefined) write.description = body.description ?? null;
|
||||
if (body.notes !== undefined) write.notes = body.notes ?? null;
|
||||
|
||||
Reference in New Issue
Block a user