From abfe35b9affbdfc9c23757dd70729ba3b1e78000 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:30:23 +0000 Subject: [PATCH 1/3] Initial plan for issue From c5ab984ef70688863002c9f4b4775e7edb2cdec4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:45:21 +0000 Subject: [PATCH 2/3] Replace Imgur upload with direct backend upload Co-authored-by: Yukaii <4230968+Yukaii@users.noreply.github.com> --- src/api/index.ts | 91 ++++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/src/api/index.ts b/src/api/index.ts index 591a364..857c753 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -15,6 +15,11 @@ type ImageResponse = { token: string } +export type UploadedImage = { + token: string, + src: string +} + export type UploadedImages = { token: string, src: string // used for preview images @@ -40,27 +45,33 @@ export async function getFactory (factoryId: string): Promise { } } -const IMGUR_CLIENT_ID = '39048813b021935' - -async function uploadToImgur (file: File) { +async function uploadImageDirectly (file: File): Promise { const formData = new FormData() formData.append('image', file) - const { data } = await axios({ - method: 'POST', - url: 'https://api.imgur.com/3/image', - data: formData, + const exifData = await readImageExif(file) + + // Append EXIF data to form + if (exifData.Latitude) { + formData.append('Latitude', exifData.Latitude.toString()) + } + if (exifData.Longitude) { + formData.append('Longitude', exifData.Longitude.toString()) + } + if (exifData.DateTimeOriginal) { + formData.append('DateTimeOriginal', exifData.DateTimeOriginal) + } + + const { data }: { data: ImageResponse } = await instance.post('/images/upload', formData, { headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Client-ID ${IMGUR_CLIENT_ID}` + 'Content-Type': 'multipart/form-data' } }) return { - link: data.data.link as string, - deletehash: data.data.deletehash as string, - file - } + token: data.token, + src: URL.createObjectURL(file) + } as UploadedImage } const convertTurple2Number = (input: [number, number, number]) => input[0] + (input[1] / 60) + (input[2] / 3600) @@ -95,35 +106,47 @@ function readImageExif (file: File): Promise { }) } -export type UploadedImage = { - token: string, - src: string -} - -async function uploadExifAndGetToken ({ link, file, deletehash }: { link: string, file: File, deletehash: string }) { - const exifData = await readImageExif(file) - const { data }: { data: ImageResponse } = await instance.post('/images', { url: link, ...exifData, deletehash }) - - return { - token: data.token, - src: URL.createObjectURL(file) - } as UploadedImage -} - export async function uploadImages (files: FileList): Promise { return Promise.all( - Array.from(files).map((file) => uploadToImgur(file).then((el) => uploadExifAndGetToken(el))) + Array.from(files).map((file) => uploadImageDirectly(file)) ) } export async function updateFactoryImages (factoryId: string, files: FileList, { nickname, contact }: { nickname?: string, contact?: string }) { return Promise.all( - Array.from(files).map((file) => uploadToImgur(file).then((el) => (async () => { - const exifData = await readImageExif(el.file) - const { data }: { data: FactoryImage } = await instance.post(`/factories/${factoryId}/images`, { url: el.link, ...exifData, nickname, contact, deletehash: el.deletehash }) - data.image_path = el.link + Array.from(files).map(async (file) => { + const formData = new FormData() + formData.append('image', file) + + const exifData = await readImageExif(file) + + // Append EXIF data to form + if (exifData.Latitude) { + formData.append('Latitude', exifData.Latitude.toString()) + } + if (exifData.Longitude) { + formData.append('Longitude', exifData.Longitude.toString()) + } + if (exifData.DateTimeOriginal) { + formData.append('DateTimeOriginal', exifData.DateTimeOriginal) + } + + // Append contact info if provided + if (nickname) { + formData.append('nickname', nickname) + } + if (contact) { + formData.append('contact', contact) + } + + const { data }: { data: FactoryImage } = await instance.post(`/factories/${factoryId}/images/upload`, formData, { + headers: { + 'Content-Type': 'multipart/form-data' + } + }) + return data - })())) + }) ) } From 27b7ed2259b2506c40390f5cf4d1b8109162e39d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Jun 2025 13:48:31 +0000 Subject: [PATCH 3/3] Finalize direct backend upload implementation Co-authored-by: Yukaii <4230968+Yukaii@users.noreply.github.com> --- src/api/index.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/index.ts b/src/api/index.ts index 857c753..ce72f2a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -46,6 +46,10 @@ export async function getFactory (factoryId: string): Promise { } async function uploadImageDirectly (file: File): Promise { + // For general images, use the existing backend pattern + // The backend may not have a general /images/upload endpoint yet + // So we upload the file and let the backend handle it using the existing /images endpoint + const formData = new FormData() formData.append('image', file) @@ -62,7 +66,7 @@ async function uploadImageDirectly (file: File): Promise { formData.append('DateTimeOriginal', exifData.DateTimeOriginal) } - const { data }: { data: ImageResponse } = await instance.post('/images/upload', formData, { + const { data }: { data: ImageResponse } = await instance.post('/images', formData, { headers: { 'Content-Type': 'multipart/form-data' }