From b5b6192b603b5ce60b913cc7138d30e46aafbe14 Mon Sep 17 00:00:00 2001 From: Mo Date: Fri, 2 Dec 2022 10:13:25 -0600 Subject: [PATCH] fix: fixes issue where files imported from another account could not be deleted (#2082) --- .../src/Domain/Files/FileService.spec.ts | 17 ++++++++++++++++ .../services/src/Domain/Files/FileService.ts | 20 ++++++++++++++++--- packages/utils/src/Domain/Utils/Utils.ts | 4 ++++ .../SuperEditor/SuperNoteImporter.tsx | 2 +- .../Utils/spaceSeparatedStrings.tsx | 3 --- 5 files changed, 39 insertions(+), 7 deletions(-) delete mode 100644 packages/web/src/javascripts/Utils/spaceSeparatedStrings.tsx diff --git a/packages/services/src/Domain/Files/FileService.spec.ts b/packages/services/src/Domain/Files/FileService.spec.ts index 08d75c7d1..3f7ed0181 100644 --- a/packages/services/src/Domain/Files/FileService.spec.ts +++ b/packages/services/src/Domain/Files/FileService.spec.ts @@ -145,6 +145,23 @@ describe('fileService', () => { expect(fileService['encryptedCache'].get(file.uuid)).toBeFalsy() }) + it('if file fails to delete, should present alert asking if they want to remove item', async () => { + const file = { + uuid: '1', + decryptedSize: 100_000, + } as jest.Mocked + + const alertMock = (alertService.confirm = jest.fn().mockReturnValue(true)) + const deleteItemMock = (itemManager.setItemToBeDeleted = jest.fn()) + + apiService.deleteFile = jest.fn().mockReturnValue({ error: true }) + + await fileService.deleteFile(file) + + expect(alertMock).toHaveBeenCalledTimes(1) + expect(deleteItemMock).toHaveBeenCalledTimes(1) + }) + it('should download file from network if no backup', async () => { const file = { uuid: '1', diff --git a/packages/services/src/Domain/Files/FileService.ts b/packages/services/src/Domain/Files/FileService.ts index b334c64cb..aaed40b57 100644 --- a/packages/services/src/Domain/Files/FileService.ts +++ b/packages/services/src/Domain/Files/FileService.ts @@ -11,7 +11,7 @@ import { isEncryptedPayload, } from '@standardnotes/models' import { PureCryptoInterface } from '@standardnotes/sncrypto-common' -import { UuidGenerator } from '@standardnotes/utils' +import { spaceSeparatedStrings, UuidGenerator } from '@standardnotes/utils' import { EncryptionProviderInterface, SNItemsKey } from '@standardnotes/encryption' import { DownloadAndDecryptFileOperation, @@ -33,7 +33,7 @@ import { readAndDecryptBackupFileUsingBackupService, BackupServiceInterface, } from '@standardnotes/files' -import { AlertService } from '../Alert/AlertService' +import { AlertService, ButtonType } from '../Alert/AlertService' import { ChallengeServiceInterface } from '../Challenge' import { InternalEventBusInterface } from '../Internal/InternalEventBusInterface' import { ItemManagerInterface } from '../Item/ItemManagerInterface' @@ -244,7 +244,21 @@ export class FileService extends AbstractService implements FilesClientInterface const result = await this.api.deleteFile(tokenResult) if (result.error) { - return ClientDisplayableError.FromError(result.error) + const deleteAnyway = await this.alertService.confirm( + spaceSeparatedStrings( + 'This file could not be deleted from the server, possibly because you are attempting to delete a file item', + 'that was imported from another account. Would you like to remove this file item from your account anyway?', + "If you're sure the file is yours and still exists on the server, do not choose this option,", + 'and instead try to delete it again.', + ), + 'Unable to Delete', + 'Delete Anyway', + ButtonType.Danger, + ) + + if (!deleteAnyway) { + return ClientDisplayableError.FromError(result.error) + } } await this.itemManager.setItemToBeDeleted(file) diff --git a/packages/utils/src/Domain/Utils/Utils.ts b/packages/utils/src/Domain/Utils/Utils.ts index ebbefe662..5340c8398 100644 --- a/packages/utils/src/Domain/Utils/Utils.ts +++ b/packages/utils/src/Domain/Utils/Utils.ts @@ -683,3 +683,7 @@ export function assert(value: unknown): asserts value { export function useBoolean(value: boolean | undefined, defaultValue: boolean): boolean { return value != undefined ? value : defaultValue } + +export function spaceSeparatedStrings(...strings: string[]): string { + return strings.join(' ') +} diff --git a/packages/web/src/javascripts/Components/NoteView/SuperEditor/SuperNoteImporter.tsx b/packages/web/src/javascripts/Components/NoteView/SuperEditor/SuperNoteImporter.tsx index fc2c89b5d..3605aaacc 100644 --- a/packages/web/src/javascripts/Components/NoteView/SuperEditor/SuperNoteImporter.tsx +++ b/packages/web/src/javascripts/Components/NoteView/SuperEditor/SuperNoteImporter.tsx @@ -10,7 +10,7 @@ import ModalDialogLabel from '@/Components/Shared/ModalDialogLabel' import Button from '@/Components/Button/Button' import ImportPlugin from './Plugins/ImportPlugin/ImportPlugin' import { NoteViewController } from '../Controller/NoteViewController' -import { spaceSeparatedStrings } from '../../../Utils/spaceSeparatedStrings' +import { spaceSeparatedStrings } from '@standardnotes/utils' const NotePreviewCharLimit = 160 diff --git a/packages/web/src/javascripts/Utils/spaceSeparatedStrings.tsx b/packages/web/src/javascripts/Utils/spaceSeparatedStrings.tsx deleted file mode 100644 index 66b7a77e6..000000000 --- a/packages/web/src/javascripts/Utils/spaceSeparatedStrings.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export function spaceSeparatedStrings(...strings: string[]): string { - return strings.join(' ') -}