Browse Source

Merge pull request #7695 from nocodb/nc-fix/duplicate-filename-suffix

Nc fix: handle duplicate filename suffix properly
pull/7696/head
Raju Udava 9 months ago committed by GitHub
parent
commit
a946bb2d27
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      packages/nc-gui/components/cell/attachment/utils.ts
  2. 8
      packages/nc-gui/composables/useMultiSelect/convertCellData.ts
  3. 12
      packages/nc-gui/composables/useMultiSelect/index.ts
  4. 15
      packages/nc-gui/utils/fileUtils.ts
  5. 31
      packages/nocodb-sdk/src/lib/helperFunctions.ts
  6. 22
      packages/nocodb/src/services/public-datas.service.ts

5
packages/nc-gui/components/cell/attachment/utils.ts

@ -1,4 +1,5 @@
import type { AttachmentReqType, AttachmentType } from 'nocodb-sdk' import type { AttachmentReqType, AttachmentType } from 'nocodb-sdk'
import { populateUniqueFileName } from 'nocodb-sdk'
import DOMPurify from 'isomorphic-dompurify' import DOMPurify from 'isomorphic-dompurify'
import RenameFile from './RenameFile.vue' import RenameFile from './RenameFile.vue'
import { import {
@ -161,7 +162,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
} else { } else {
const fileName = populateUniqueFileName( const fileName = populateUniqueFileName(
(file as AttachmentReqType).fileName ?? '', (file as AttachmentReqType).fileName ?? '',
[...attachments.value, ...imageUrls], [...attachments.value, ...imageUrls].map((fn) => fn?.title || fn?.fileName),
(file as File)?.type || (file as AttachmentReqType)?.mimetype || '', (file as File)?.type || (file as AttachmentReqType)?.mimetype || '',
) )
@ -225,7 +226,7 @@ export const [useProvideAttachmentCell, useAttachmentCell] = useInjectionState(
...uploadedFile, ...uploadedFile,
title: populateUniqueFileName( title: populateUniqueFileName(
uploadedFile?.title, uploadedFile?.title,
[...attachments.value, ...newAttachments], [...attachments.value, ...newAttachments].map((fn) => fn?.title || fn?.fileName),
uploadedFile?.mimetype, uploadedFile?.mimetype,
), ),
}) })

8
packages/nc-gui/composables/useMultiSelect/convertCellData.ts

@ -1,6 +1,6 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import type { AttachmentType, ColumnType, LinkToAnotherRecordType, SelectOptionsType } from 'nocodb-sdk' import type { AttachmentType, ColumnType, LinkToAnotherRecordType, SelectOptionsType } from 'nocodb-sdk'
import { UITypes } from 'nocodb-sdk' import { UITypes, populateUniqueFileName } from 'nocodb-sdk'
import type { AppInfo } from '~/composables/useGlobal' import type { AppInfo } from '~/composables/useGlobal'
import { isBt, isMm, parseProp } from '#imports' import { isBt, isMm, parseProp } from '#imports'
@ -203,7 +203,11 @@ export default function convertCellData(
for (const att of attachments) { for (const att of attachments) {
newAttachments.push({ newAttachments.push({
...att, ...att,
title: populateUniqueFileName(att?.title, [...oldAttachments, ...newAttachments], att?.mimetype), title: populateUniqueFileName(
att?.title,
[...oldAttachments, ...newAttachments].map((fn) => fn?.title || fn?.fileName),
att?.mimetype,
),
}) })
} }
return JSON.stringify([...oldAttachments, ...newAttachments]) return JSON.stringify([...oldAttachments, ...newAttachments])

12
packages/nc-gui/composables/useMultiSelect/index.ts

@ -11,7 +11,15 @@ import type {
UserFieldRecordType, UserFieldRecordType,
ViewType, ViewType,
} from 'nocodb-sdk' } from 'nocodb-sdk'
import { UITypes, dateFormats, isDateMonthFormat, isSystemColumn, isVirtualCol, timeFormats } from 'nocodb-sdk' import {
UITypes,
dateFormats,
isDateMonthFormat,
isSystemColumn,
isVirtualCol,
timeFormats,
populateUniqueFileName,
} from 'nocodb-sdk'
import { parse } from 'papaparse' import { parse } from 'papaparse'
import type { Cell } from './cellRange' import type { Cell } from './cellRange'
import { CellRange } from './cellRange' import { CellRange } from './cellRange'
@ -1253,7 +1261,7 @@ export function useMultiSelect(
...uploadedFile, ...uploadedFile,
title: populateUniqueFileName( title: populateUniqueFileName(
uploadedFile?.title, uploadedFile?.title,
[...handleParseAttachmentCellData(oldValue), ...newAttachments], [...handleParseAttachmentCellData(oldValue), ...newAttachments].map((fn) => fn?.title || fn?.fileName),
uploadedFile?.mimetype, uploadedFile?.mimetype,
), ),
}) })

15
packages/nc-gui/utils/fileUtils.ts

@ -77,18 +77,3 @@ export function extractImageSrcFromRawHtml(rawText: string) {
return imgElement.getAttribute('src') return imgElement.getAttribute('src')
} }
} }
export function populateUniqueFileName(fn: string, attachments: any[], mimeType: string) {
if (!mimeType) return fn
// If the image extension is not present, the while loop will go into an infinite loop. So, add the extension first if not present.
if (!fn?.endsWith(mimeType.split('/')[1])) {
fn = `${fn}.${mimeType.split('/')[1]}`
}
let c = 1
while (attachments.some((att) => att?.title === fn || att?.fileName === fn)) {
fn = fn.replace(/(.+?)(\.[^.]+)$/, `$1(${c++})$2`)
}
return fn
}

31
packages/nocodb-sdk/src/lib/helperFunctions.ts

@ -97,6 +97,36 @@ const getAvailableRollupForUiType = (type: string) => {
} }
}; };
function populateUniqueFileName(
fileName: string,
attachments: string[],
mimeType: string
) {
if (!mimeType) return fileName;
// If the file extension is not present, the while loop will go into an infinite loop. So, add the extension first if not present.
if (!fileName?.endsWith(`.${mimeType.split('/')[1]}`)) {
fileName = `${fileName}.${mimeType.split('/')[1]}`;
} else if (
fileName?.endsWith(`.${mimeType.split('/')[1]}`) &&
fileName.length === `.${mimeType.split('/')[1]}`.length
) {
fileName = `image.${mimeType.split('/')[1]}`;
}
const match = fileName.match(/^(.+?)(\((\d+)\))?(\.[^.]+)$/);
if (!match) return fileName;
let c = !isNaN(parseInt(match[3])) ? parseInt(match[3]) : 1;
while (attachments.some((fn) => fn === fileName)) {
fileName = `${match[1]}(${c++})${match[4]}`;
}
return fileName;
}
export { export {
filterOutSystemColumns, filterOutSystemColumns,
getSystemColumnsIds, getSystemColumnsIds,
@ -106,4 +136,5 @@ export {
extractRolesObj, extractRolesObj,
stringifyRolesObj, stringifyRolesObj,
getAvailableRollupForUiType, getAvailableRollupForUiType,
populateUniqueFileName,
}; };

22
packages/nocodb/src/services/public-datas.service.ts

@ -1,7 +1,12 @@
import path from 'path'; import path from 'path';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { ErrorMessages, UITypes, ViewTypes } from 'nocodb-sdk'; import {
ErrorMessages,
UITypes,
ViewTypes,
populateUniqueFileName,
} from 'nocodb-sdk';
import slash from 'slash'; import slash from 'slash';
import { nocoExecute } from 'nc-help'; import { nocoExecute } from 'nc-help';
@ -396,16 +401,11 @@ export class PublicDatasService {
attachments[fieldName] = attachments[fieldName] || []; attachments[fieldName] = attachments[fieldName] || [];
let originalName = utf8ify(file.originalname); let originalName = utf8ify(file.originalname);
let c = 1; originalName = populateUniqueFileName(
while ( originalName,
path.extname(originalName) && attachments[fieldName].map((att) => att?.title),
attachments[fieldName].some((att) => att?.title === originalName) file.mimetype,
) { );
originalName = originalName.replace(
/(.+?)(\.[^.]+)$/,
`$1(${c++})$2`,
);
}
const fileName = `${nanoid(18)}${path.extname(originalName)}`; const fileName = `${nanoid(18)}${path.extname(originalName)}`;

Loading…
Cancel
Save