diff --git a/packages/nc-gui/components/cell/attachment/utils.ts b/packages/nc-gui/components/cell/attachment/utils.ts index bd2a5e1748..e2c8e040d8 100644 --- a/packages/nc-gui/components/cell/attachment/utils.ts +++ b/packages/nc-gui/components/cell/attachment/utils.ts @@ -204,7 +204,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState( return updateModelValue(attachments.value) } else if (isPublic.value && isForm.value) { - attachments.value = [...attachments.value, ...imageUrls.map((item) => ({ ...item, title: item.fileName }))] + attachments.value = [...attachments.value, ...imageUrls] return updateModelValue(attachments.value) } @@ -289,7 +289,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState( [ { ...imageData, - ...(isPublic.value && isForm.value ? {} : { url: imageUrl }), + url: imageUrl, fileName: `image.${imageData?.mimetype?.split('/')[1]}`, title: `image.${imageData?.mimetype?.split('/')[1]}`, }, @@ -319,26 +319,10 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState( try { const response = await fetch(imageUrl) if (response.ok && response.headers.get('content-type')?.startsWith('image/')) { - const res = { + return { mimetype: response.headers.get('content-type') || undefined, size: +(response.headers.get('content-length') || 0) || undefined, - data: undefined, - } as { minetype?: string; size?: number; data?: any } - - if (isPublic.value && isForm.value) { - const blob = await response.blob() - - res.data = await new Promise((resolve, reject) => { - const reader = new FileReader() - reader.onloadend = () => { - resolve(reader.result) - } - reader.onerror = reject - reader.readAsDataURL(blob) - }) - } - - return res + } as { minetype?: string; size?: number } } throw new Error('Field to parse image url') } catch (err) { diff --git a/packages/nocodb/src/services/public-datas.service.ts b/packages/nocodb/src/services/public-datas.service.ts index f71a11707d..5cc9abe635 100644 --- a/packages/nocodb/src/services/public-datas.service.ts +++ b/packages/nocodb/src/services/public-datas.service.ts @@ -320,7 +320,19 @@ export class PublicDatasService { fields[fieldName].uidt === UITypes.Attachment ) { attachments[fieldName] = attachments[fieldName] || []; - const originalName = utf8ify(file.originalname); + let originalName = utf8ify(file.originalname); + + let c = 1; + while ( + path.extname(originalName) && + attachments[fieldName].some((att) => att?.title === originalName) + ) { + originalName = originalName.replace( + /(.+?)(\.[^.]+)$/, + `$1(${c++})$2`, + ); + } + const fileName = `${nanoid(18)}${path.extname(originalName)}`; const url = await storageAdapter.fileCreate( @@ -347,6 +359,65 @@ export class PublicDatasService { } } + // filter the uploadByUrl attachments + const uploadByUrlAttachments = []; + for (const [column, data] of Object.entries(insertObject)) { + if (fields[column].uidt === UITypes.Attachment && Array.isArray(data)) { + data.forEach((file, uploadIndex) => { + if (file?.url && !file?.file) { + uploadByUrlAttachments.push({ + ...file, + fieldName: column, + uploadIndex, + }); + } + }); + } + } + + for (const file of uploadByUrlAttachments) { + const filePath = sanitizeUrlPath([ + 'noco', + base.title, + model.title, + file.fieldName, + ]); + + attachments[file.fieldName] = attachments[file.fieldName] || []; + + const fileName = `${nanoid(18)}${path.extname( + file?.fileName || file.url.split('/').pop(), + )}`; + + const attachmentUrl: string | null = await storageAdapter.fileCreateByUrl( + slash(path.join('nc', 'uploads', ...filePath, fileName)), + file.url, + ); + + let attachmentPath: string | undefined; + + // if `attachmentUrl` is null, then it is local attachment + if (!attachmentUrl) { + // then store the attachment path only + // url will be constructed in `useAttachmentCell` + attachmentPath = `download/${filePath.join('/')}/${fileName}`; + } + + // add attachement in uploaded order + attachments[file.fieldName].splice( + file.uploadIndex ?? attachments[file.fieldName].length, + 0, + { + ...(attachmentUrl ? { url: attachmentUrl } : {}), + ...(attachmentPath ? { path: attachmentPath } : {}), + title: file.fileName, + mimetype: file.mimetype, + size: file.size, + icon: mimeIcons[path.extname(fileName).slice(1)] || undefined, + }, + ); + } + for (const [column, data] of Object.entries(attachments)) { insertObject[column] = JSON.stringify(data); }