From 5046e1a2e0453a0f01594d2470ba7bf1963dfe8b Mon Sep 17 00:00:00 2001 From: jubnl Date: Fri, 17 Apr 2026 15:33:05 +0200 Subject: [PATCH] fix(synology): wire shared-album passphrase through journey-entry add flow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread selectedAlbumPassphrase from ProviderPicker through onAdd → journeyApi.addProviderPhotos → POST /entries/:entryId/provider-photos → addProviderPhoto service → getOrCreateTrekPhoto so shared-album photos have their passphrase encrypted and persisted on trek_photos at add-time, enabling streamPhoto to forward it to Synology correctly (#689). --- client/src/api/client.ts | 4 +- client/src/pages/JourneyDetailPage.tsx | 8 ++-- server/src/routes/journey.ts | 7 +-- server/src/services/journeyService.ts | 4 +- server/tests/integration/journey.test.ts | 44 +++++++++++++++++++ .../unit/services/journeyService.test.ts | 21 +++++++++ 6 files changed, 77 insertions(+), 11 deletions(-) diff --git a/client/src/api/client.ts b/client/src/api/client.ts index 526a0d69..8ac67d13 100644 --- a/client/src/api/client.ts +++ b/client/src/api/client.ts @@ -331,8 +331,8 @@ export const journeyApi = { // Photos uploadPhotos: (entryId: number, formData: FormData) => apiClient.post(`/journeys/entries/${entryId}/photos`, formData, { headers: { 'Content-Type': undefined as any } }).then(r => r.data), - addProviderPhoto: (entryId: number, provider: string, assetId: string, caption?: string) => apiClient.post(`/journeys/entries/${entryId}/provider-photos`, { provider, asset_id: assetId, caption }).then(r => r.data), - addProviderPhotos: (entryId: number, provider: string, assetIds: string[], caption?: string) => apiClient.post(`/journeys/entries/${entryId}/provider-photos`, { provider, asset_ids: assetIds, caption }).then(r => r.data), + addProviderPhoto: (entryId: number, provider: string, assetId: string, caption?: string, passphrase?: string) => apiClient.post(`/journeys/entries/${entryId}/provider-photos`, { provider, asset_id: assetId, caption, ...(passphrase ? { passphrase } : {}) }).then(r => r.data), + addProviderPhotos: (entryId: number, provider: string, assetIds: string[], caption?: string, passphrase?: string) => apiClient.post(`/journeys/entries/${entryId}/provider-photos`, { provider, asset_ids: assetIds, caption, ...(passphrase ? { passphrase } : {}) }).then(r => r.data), linkPhoto: (entryId: number, photoId: number) => apiClient.post(`/journeys/entries/${entryId}/link-photo`, { photo_id: photoId }).then(r => r.data), updatePhoto: (photoId: number, data: Record) => apiClient.patch(`/journeys/photos/${photoId}`, data).then(r => r.data), deletePhoto: (photoId: number) => apiClient.delete(`/journeys/photos/${photoId}`).then(r => r.data), diff --git a/client/src/pages/JourneyDetailPage.tsx b/client/src/pages/JourneyDetailPage.tsx index 3454c4d9..a2004fdf 100644 --- a/client/src/pages/JourneyDetailPage.tsx +++ b/client/src/pages/JourneyDetailPage.tsx @@ -1021,7 +1021,7 @@ function GalleryView({ entries, journeyId, userId, trips, onPhotoClick, onRefres trips={trips} existingAssetIds={new Set(entries.flatMap(e => (e.photos || []).filter(p => p.asset_id).map(p => p.asset_id!)))} onClose={() => setShowPicker(false)} - onAdd={async (assetIds, entryId) => { + onAdd={async (assetIds, entryId, passphrase) => { let targetId = entryId if (!targetId) { try { @@ -1035,7 +1035,7 @@ function GalleryView({ entries, journeyId, userId, trips, onPhotoClick, onRefres } let added = 0 try { - const result = await journeyApi.addProviderPhotos(targetId, pickerProvider!, assetIds) + const result = await journeyApi.addProviderPhotos(targetId, pickerProvider!, assetIds, undefined, passphrase) added = result.added || 0 } catch {} if (added > 0) { @@ -1511,7 +1511,7 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on trips: JourneyTrip[] existingAssetIds: Set onClose: () => void - onAdd: (assetIds: string[], entryId: number | null) => Promise + onAdd: (assetIds: string[], entryId: number | null, passphrase?: string) => Promise }) { const { t } = useTranslation() const [filter, setFilter] = useState<'trip' | 'custom' | 'all' | 'album'>('trip') @@ -1884,7 +1884,7 @@ function ProviderPicker({ provider, userId, entries, trips, existingAssetIds, on {t('common.cancel')}