diff --git a/functions/src/api/routes/event/exportSchedulePdf.ts b/functions/src/api/routes/event/exportSchedulePdf.ts index 01eab701..7855a074 100644 --- a/functions/src/api/routes/event/exportSchedulePdf.ts +++ b/functions/src/api/routes/event/exportSchedulePdf.ts @@ -6,7 +6,7 @@ import { getFirebaseProjectId } from '../../../utils/getFirebaseProjectId' import { getServiceAPIKey } from '../../../serviceApi/serviceApiKeyPreHandler' import { getIndividualDays } from '../../../../../src/utils/dates/diffDays' import { uploadBufferToStorage } from '../file/utils/uploadBufferToStorage' -import { addPdfFileToEvent, getFilesNames, getUploadFilePath } from '../deploy/updateWebsiteActions/getFilesNames' +import { addPdfFileToEvent } from '../deploy/updateWebsiteActions/getFilesNames' import { getFileName } from '../../other/getFileName' const ExportPdfReply = Type.Object({ @@ -130,17 +130,8 @@ export const exportSchedulePdfRoute = (fastify: FastifyInstance, options: any, d return reply.status(400).send(publicFileUrlOrError) } - if (!event.files?.pdf) { - const updatedEvent = await EventDao.getEvent(fastify.firebase, eventId) - const eventFiles = await getFilesNames(fastify.firebase, updatedEvent) - const uploadFilePath = getUploadFilePath(eventFiles) - return reply.status(200).send({ - pdf: uploadFilePath.pdf, - }) - } - reply.status(200).send({ - pdf: getUploadFilePath(event.files).pdf, + pdf: publicFileUrlOrError, }) } catch (err) { const error = err as Error diff --git a/src/services/firebase.ts b/src/services/firebase.ts index bda28c4a..9faa1c3a 100644 --- a/src/services/firebase.ts +++ b/src/services/firebase.ts @@ -34,6 +34,22 @@ export const isStorageUrl = (url: string | null | undefined): boolean => { return url.startsWith(baseStorageUrl) || url.startsWith(alternativeStorageUrl) } +// Strip a full public storage URL down to its bucket-relative path. Firebase's +// ref(storage, ...) only understands gs:// or firebasestorage URLs, so a public +// googleapis.com URL must be reduced to a plain path first. +export const storageUrlToPath = (urlOrPath: string): string => { + if (urlOrPath.startsWith(alternativeStorageUrl)) { + return urlOrPath.slice(alternativeStorageUrl.length) + } + if (urlOrPath.startsWith(`${baseStorageUrl}/`)) { + return urlOrPath.slice(baseStorageUrl.length + 1) + } + return urlOrPath +} + +// Build the public URL for a bucket-relative storage path. +export const pathToStorageUrl = (path: string): string => `${alternativeStorageUrl}${path}` + let instanceApp: FirebaseApp = initializeApp(config) export const instanceFirestore: Firestore = getFirestore(instanceApp) export const storage = getStorage() diff --git a/src/utils/images/uploadImage.ts b/src/utils/images/uploadImage.ts index 278653fd..eceb081e 100644 --- a/src/utils/images/uploadImage.ts +++ b/src/utils/images/uploadImage.ts @@ -1,12 +1,34 @@ import { ref, uploadBytes } from 'firebase/storage' -import { storage } from '../../services/firebase' +import { pathToStorageUrl, storage, storageUrlToPath } from '../../services/firebase' import { v4 as uuidv4 } from 'uuid' +const MIME_EXTENSIONS: Record = { + 'image/jpeg': 'jpg', + 'image/jpg': 'jpg', + 'image/png': 'png', + 'image/webp': 'webp', + 'image/gif': 'gif', + 'image/svg+xml': 'svg', + 'image/avif': 'avif', + 'image/bmp': 'bmp', +} + +const getBlobExtension = (blob: Blob): string => { + const mime = blob.type.split(';')[0].trim().toLowerCase() + if (MIME_EXTENSIONS[mime]) { + return MIME_EXTENSIONS[mime] + } + const subtype = mime.split('/')[1] + return subtype ? subtype.replace('+xml', '') : 'jpg' +} + export const uploadImage = async (imageFolder: string, image: Blob): Promise => { - const fileName = uuidv4() + const fileName = `${uuidv4()}.${getBlobExtension(image)}` - const outputRef = ref(storage, `${imageFolder}${fileName}`) + // imageFolder may be a full public URL; reduce it to a bucket-relative path + const folderPath = storageUrlToPath(imageFolder) + const outputRef = ref(storage, `${folderPath}${fileName}`) - await uploadBytes(outputRef, image, {}) - return `${imageFolder}${fileName}` + await uploadBytes(outputRef, image, { contentType: image.type || undefined }) + return pathToStorageUrl(outputRef.fullPath) }