-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathindex.ts
More file actions
224 lines (189 loc) · 6.38 KB
/
Copy pathindex.ts
File metadata and controls
224 lines (189 loc) · 6.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
import axios from 'axios'
import { FactoryPostData, FactoryData, FactoriesResponse, FactoryImage, ReportRecord } from '@/types'
import EXIF from '@disfactory/exif-js'
import { currentBaseURL } from '@/lib/apiConfig'
import { watch } from 'vue'
const instance = axios.create({
headers: {
'Content-Type': 'application/json'
}
})
// Update base URL whenever currentBaseURL changes
const updateBaseURL = () => {
instance.defaults.baseURL = currentBaseURL.value
}
// Set initial base URL and watch for changes
updateBaseURL()
watch(currentBaseURL, updateBaseURL)
type ImageResponse = {
token: string
}
export type UploadedImages = {
token: string,
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 || ''
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')
}
}
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')
}
}
const IMGUR_CLIENT_ID = '39048813b021935'
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,
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Client-ID ${IMGUR_CLIENT_ID}`
}
})
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)
}
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] }
type AfterExifData = { Latitude?: number, Longitude?: number, DateTimeOriginal?: string }
function readImageExif (file: File): Promise<AfterExifData> {
const fileReader = new FileReader()
return new Promise((resolve) => {
fileReader.onload = (e: ProgressEvent<FileReader>) => {
if (!e.target) {
resolve({})
return
}
const data: ExifData = EXIF.readFromBinaryFile(e.target.result)
const result: AfterExifData = {}
if (data.GPSLatitude) {
result.Latitude = convertTurple2Number(data.GPSLatitude)
}
if (data.GPSLongitude) {
result.Longitude = convertTurple2Number(data.GPSLongitude)
}
if (data.DateTimeOriginal) {
result.DateTimeOriginal = data.DateTimeOriginal
}
resolve(result)
}
fileReader.readAsArrayBuffer(file)
})
}
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<UploadedImages> {
return Promise.all(
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) => 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
return data
})()))
)
}
export async function createFactory (factory: FactoryPostData): Promise<FactoryData> {
try {
const { data }: { data: FactoryData } = await instance.post('/factories', JSON.stringify(factory))
return data
} catch (err) {
console.error(err)
throw new TypeError('Create factory failed')
}
}
// !FIXME: add more factory fields
type UpdatableFactoryFields = {
name: string,
nickname: string,
contact: string,
others: string,
images: string[]
}
export async function updateFactory (factoryId: string, factoryData: Partial<UpdatableFactoryFields>): Promise<FactoryData> {
try {
const { data }: { data: FactoryData } = await instance.put(`/factories/${factoryId}`, JSON.stringify(factoryData))
return data
} catch (err) {
console.error(err)
throw new TypeError('Update factory failed')
}
}
export async function getFactoryReportRecords (factoryId: string) {
try {
const { data }: { data: ReportRecord[] } = await instance.get(`/factories/${factoryId}/report_records`)
return data
} catch (err) {
console.error(err)
throw new TypeError('Fetch factory error')
}
}