-
Notifications
You must be signed in to change notification settings - Fork 17
feat: support backend image upload provider #198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,8 @@ | ||
| VUE_APP_BASE_URL=https://staging.disfactory.tw/api | ||
| VUE_APP_IMGUR_FALLBACK_URL=https://api.disfactory.tw/imgur | ||
|
|
||
| # Image upload configuration | ||
| # Set to 'backend' to use the backend filesystem upload, or 'imgur' to use Imgur (default) | ||
| VUE_APP_IMAGE_UPLOAD_PROVIDER=imgur | ||
| # Backend upload URL (only used when VUE_APP_IMAGE_UPLOAD_PROVIDER=backend) | ||
| VUE_APP_IMAGE_UPLOAD_URL=https://api.disfactory.tw/api/upload |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |
|
|
||
| // Update base URL whenever currentBaseURL changes | ||
| const updateBaseURL = () => { | ||
| instance.defaults.baseURL = currentBaseURL.value | ||
| } | ||
|
|
||
| // Set initial base URL and watch for changes | ||
|
|
@@ -28,10 +28,15 @@ | |
| src: string // used for preview images | ||
| }[] | ||
|
|
||
| // Image upload provider configuration | ||
| type ImageUploadProvider = 'imgur' | 'backend' | ||
| const IMAGE_UPLOAD_PROVIDER: ImageUploadProvider = (process.env.VUE_APP_IMAGE_UPLOAD_PROVIDER as ImageUploadProvider) || 'imgur' | ||
| const IMAGE_UPLOAD_URL = process.env.VUE_APP_IMAGE_UPLOAD_URL || '' | ||
|
Check warning on line 34 in src/api/index.ts
|
||
|
|
||
| export async function getFactories (range: number, lng: number, lat: number): Promise<FactoriesResponse> { | ||
| try { | ||
| const { data } = await instance.get(`/factories?range=${range}&lng=${lng}&lat=${lat}`) | ||
| return data | ||
| } catch (err) { | ||
| console.error(err) | ||
| throw new TypeError('Get factory failed') | ||
|
|
@@ -40,8 +45,8 @@ | |
|
|
||
| export async function getFactory (factoryId: string): Promise<FactoryData> { | ||
| try { | ||
| const { data } = await instance.get(`/factories/${factoryId}`) | ||
| return data | ||
| } catch (err) { | ||
| console.error(err) | ||
| throw new TypeError('Get factory failed') | ||
|
|
@@ -50,11 +55,17 @@ | |
|
|
||
| const IMGUR_CLIENT_ID = '39048813b021935' | ||
|
|
||
| async function uploadToImgur (file: File) { | ||
| type ImageUploadResult = { | ||
| link: string, | ||
| deletehash: string, | ||
| file: File | ||
| } | ||
|
|
||
| async function uploadToImgur (file: File): Promise<ImageUploadResult> { | ||
| const formData = new FormData() | ||
| formData.append('image', file) | ||
|
|
||
| const { data } = await axios({ | ||
| method: 'POST', | ||
| url: 'https://api.imgur.com/3/image', | ||
| data: formData, | ||
|
|
@@ -65,12 +76,48 @@ | |
| }) | ||
|
|
||
| return { | ||
| link: data.data.link as string, | ||
| deletehash: data.data.deletehash as string, | ||
| file | ||
| } | ||
| } | ||
|
|
||
| async function uploadToBackend (file: File): Promise<ImageUploadResult> { | ||
| const formData = new FormData() | ||
| formData.append('image', file) | ||
|
|
||
| // Use the configured backend upload URL, or construct from current base URL | ||
| const uploadUrl = IMAGE_UPLOAD_URL || `${currentBaseURL.value}/upload` | ||
|
|
||
| const { data } = await axios({ | ||
| method: 'POST', | ||
| url: uploadUrl, | ||
| data: formData, | ||
| headers: { | ||
| 'Content-Type': 'multipart/form-data' | ||
| } | ||
| }) | ||
|
|
||
| // Backend returns Imgur-compatible response format | ||
| if (!data.success) { | ||
| throw new Error(data.data?.error || 'Image upload failed') | ||
| } | ||
|
|
||
| return { | ||
| link: data.data.link as string, | ||
| deletehash: data.data.deletehash as string, | ||
| file | ||
| } | ||
| } | ||
|
|
||
| // Upload image using configured provider | ||
| async function uploadImage (file: File): Promise<ImageUploadResult> { | ||
| if (IMAGE_UPLOAD_PROVIDER === 'backend') { | ||
| return uploadToBackend(file) | ||
| } | ||
| return uploadToImgur(file) | ||
| } | ||
|
Comment on lines
+85
to
+119
|
||
|
|
||
| const convertTurple2Number = (input: [number, number, number]) => input[0] + (input[1] / 60) + (input[2] / 3600) | ||
|
|
||
| type ExifData = { DateTimeOriginal?: string, GPSLatitude?: [number, number, number], GPSLongitude?: [number, number, number] } | ||
|
|
@@ -120,13 +167,13 @@ | |
|
|
||
| export async function uploadImages (files: FileList): Promise<UploadedImages> { | ||
| return Promise.all( | ||
| Array.from(files).map((file) => uploadToImgur(file).then((el) => uploadExifAndGetToken(el))) | ||
| Array.from(files).map((file) => uploadImage(file).then((el) => uploadExifAndGetToken(el))) | ||
| ) | ||
| } | ||
|
|
||
| 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 () => { | ||
| Array.from(files).map((file) => uploadImage(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 | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The environment variable
VUE_APP_IMAGE_UPLOAD_PROVIDERis cast toImageUploadProvidertype without validation. If an invalid value (e.g., 'typo' or 'cloudinary') is provided, it will be assigned toIMAGE_UPLOAD_PROVIDERand only fall back to 'imgur' if the value is falsy. This could lead to unexpected behavior in theuploadImagefunction.Consider adding validation:
This ensures only valid provider values are used.