diff --git a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts index 09de034fd9..2ce071699d 100644 --- a/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +++ b/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts @@ -10,7 +10,10 @@ import { UserfeedbackApiService, UsersApiService, } from '@geonetwork-ui/data-access/gn4' -import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' +import { + PlatformServiceInterface, + UploadEvent, +} from '@geonetwork-ui/common/domain/platform.service.interface' import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' import { Keyword, @@ -26,6 +29,7 @@ import { ThesaurusApiResponse, } from '@geonetwork-ui/api/metadata-converter' import { KeywordType } from '@geonetwork-ui/common/domain/model/thesaurus' +import { noDuplicateFileName } from '@geonetwork-ui/util/shared' const minApiVersion = '4.2.2' @@ -288,34 +292,51 @@ export class Gn4PlatformService implements PlatformServiceInterface { ) } - attachFileToRecord(recordUuid: string, file: File) { + attachFileToRecord(recordUuid: string, file: File): Observable { let sizeBytes = -1 - return this.recordsApiService - .putResource(recordUuid, file, 'public', undefined, 'events', true) - .pipe( - map((event) => { - if (event.type === HttpEventType.UploadProgress) { - sizeBytes = event.total - return { - type: 'progress', - progress: event.total - ? Math.round((100 * event.loaded) / event.total) - : 0, - } as const - } - if (event.type === HttpEventType.Response) { - return { - type: 'success', - attachment: { - url: new URL(event.body.url), - fileName: event.body.filename, - }, - sizeBytes, - } as const - } - return undefined - }), - filter((event) => !!event) - ) + + this.recordsApiService + .getAssociatedResources(recordUuid) + .subscribe((res) => console.log(res)) + + // Check if the ressource already exist on the server and rename it if that's the case + return this.getRecordAttachments(recordUuid).pipe( + map((recordAttachement) => recordAttachement.map((r) => r.fileName)), + switchMap((fileNames) => { + const fileName = noDuplicateFileName(file.name, fileNames) + + console.log(fileName) + file = new File([file], fileName, { type: file.type }) + + return this.recordsApiService + .putResource(recordUuid, file, 'public', undefined, 'events', true) + .pipe( + map((event) => { + if (event.type === HttpEventType.UploadProgress) { + sizeBytes = event.total + return { + type: 'progress', + progress: event.total + ? Math.round((100 * event.loaded) / event.total) + : 0, + } as UploadEvent + } + if (event.type === HttpEventType.Response) { + return { + type: 'success', + attachment: { + url: new URL(event.body.url), + fileName: event.body.filename, + }, + sizeBytes, + } as UploadEvent + } + return undefined + }), + filter((event) => !!event), + catchError(() => undefined) // todo + ) + }) + ) } } diff --git a/libs/common/domain/src/lib/platform.service.interface.ts b/libs/common/domain/src/lib/platform.service.interface.ts index 06aac0d206..008c0f24bc 100644 --- a/libs/common/domain/src/lib/platform.service.interface.ts +++ b/libs/common/domain/src/lib/platform.service.interface.ts @@ -8,7 +8,7 @@ export interface RecordAttachment { url: URL fileName: string } -type UploadEvent = +export type UploadEvent = | { type: 'progress' progress: number // in percent diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts index fd8edfe947..2a804ff0ee 100644 --- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts @@ -12,9 +12,8 @@ import { ImageInputComponent } from '@geonetwork-ui/ui/inputs' import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface' import { NotificationsService } from '@geonetwork-ui/feature/notifications' import { TranslateService } from '@ngx-translate/core' -import { Subscription, switchMap } from 'rxjs' +import { Subscription } from 'rxjs' import { MAX_UPLOAD_SIZE_MB } from '../../../../fields.config' -import { map } from 'rxjs/operators' @Component({ selector: 'gn-ui-form-field-overviews', @@ -54,26 +53,7 @@ export class FormFieldOverviewsComponent { handleFileChange(file: File) { this.uploadProgress = 0 this.uploadSubscription = this.platformService - .getRecordAttachments(this.metadataUuid) - .pipe( - map((recordAttachement) => recordAttachement.map((r) => r.fileName)), - switchMap((fileNames) => { - let fileToUpload = file - - if (fileNames.includes(file.name)) { - const fileNameParts = file.name.split('.') - const extension = fileNameParts.pop() - const baseName = fileNameParts.join('.') - const newFileName = `${baseName}_${Date.now()}.${extension}` - - fileToUpload = new File([file], newFileName, { type: file.type }) - } - return this.platformService.attachFileToRecord( - this.metadataUuid, - fileToUpload - ) - }) - ) + .attachFileToRecord(this.metadataUuid, file) .subscribe({ next: (event) => { if (event.type === 'progress') { diff --git a/libs/util/shared/src/lib/utils/index.ts b/libs/util/shared/src/lib/utils/index.ts index d3bfe45bdb..301dce35e5 100644 --- a/libs/util/shared/src/lib/utils/index.ts +++ b/libs/util/shared/src/lib/utils/index.ts @@ -3,6 +3,7 @@ export * from './event' export * from './fuzzy-filter' export * from './geojson' export * from './image-resize' +export * from './no-duplicate-file-name' export * from './parse' export * from './remove-whitespace' export * from './sort-by' diff --git a/libs/util/shared/src/lib/utils/no-duplicate-file-name.spec.ts b/libs/util/shared/src/lib/utils/no-duplicate-file-name.spec.ts new file mode 100644 index 0000000000..c173ff72e7 --- /dev/null +++ b/libs/util/shared/src/lib/utils/no-duplicate-file-name.spec.ts @@ -0,0 +1,45 @@ +import { noDuplicateFileName } from './no-duplicate-file-name' + +describe('noDuplicateFileName', () => { + it('should return the original file name if it does not exist in the fileNameList', () => { + const fileName = 'testfile.txt' + const fileNameList = ['otherfile.txt', 'anotherfile.txt'] + + const result = noDuplicateFileName(fileName, fileNameList) + + expect(result).toBe(fileName) + }) + + it('should return a new file name with a timestamp if the file name exists in the fileNameList', () => { + const fileName = 'testfile.txt' + const fileNameList = ['testfile.txt', 'otherfile.txt'] + + const result = noDuplicateFileName(fileName, fileNameList) + + // Check if the new file name starts with the base name and contains a timestamp + const regex = /testfile_\d+\.txt/ + expect(result).toMatch(regex) + }) + + it('should handle file names without an extension', () => { + const fileName = 'testfile' + const fileNameList = ['testfile'] + + const result = noDuplicateFileName(fileName, fileNameList) + + // Check if the new file name has a timestamp appended with no extension + const regex = /testfile_\d+/ + expect(result).toMatch(regex) + }) + + it('should handle file names with multiple dots correctly', () => { + const fileName = 'test.file.name.txt' + const fileNameList = ['test.file.name.txt'] + + const result = noDuplicateFileName(fileName, fileNameList) + + // Check if the new file name with multiple dots contains a timestamp + const regex = /test\.file\.name_\d+\.txt/ + expect(result).toMatch(regex) + }) +}) diff --git a/libs/util/shared/src/lib/utils/no-duplicate-file-name.ts b/libs/util/shared/src/lib/utils/no-duplicate-file-name.ts new file mode 100644 index 0000000000..a026156779 --- /dev/null +++ b/libs/util/shared/src/lib/utils/no-duplicate-file-name.ts @@ -0,0 +1,23 @@ +export function noDuplicateFileName( + fileName: string, + fileNameList: string[] +): string { + if (fileNameList.includes(fileName)) { + const fileNameParts = fileName.split('.') + let extension = '' + let baseName = fileName + + if (fileNameParts.length > 1) { + extension = fileNameParts.pop() as string + baseName = fileNameParts.join('.') + } + + if (extension) { + fileName = `${baseName}_${Date.now()}.${extension}` + } else { + fileName = `${baseName}_${Date.now()}` + } + } + + return fileName +}