From 20354a926a30bd99307e405458cceb53efe5a9e4 Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Sat, 4 Nov 2023 18:26:22 +0530 Subject: [PATCH] refactor: evernote imports (#2619) [skip e2e] --- .../Service/SuperConverterServiceInterface.ts | 9 +++ .../EvernoteConverter.spec.ts | 8 ++- .../GoogleKeepConverter.spec.ts | 8 ++- packages/ui-services/src/Import/Importer.ts | 51 +++++++++++++++- .../Dependencies/WebDependencies.ts | 4 +- .../javascripts/Application/WebApplication.ts | 2 +- .../Components/ImportModal/ImportModal.tsx | 4 +- .../ImportModal}/ImportModalController.ts | 2 +- .../ImportModal/ImportModalFileItem.tsx | 2 +- .../Components/ImportModal/InitialPage.tsx | 18 +++--- .../Tools/HeadlessSuperConverter.tsx | 59 ++++++++++++++++++- 11 files changed, 145 insertions(+), 22 deletions(-) rename packages/web/src/javascripts/{Controllers => Components/ImportModal}/ImportModalController.ts (98%) diff --git a/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts b/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts index 8c9203505..ef49b550f 100644 --- a/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts +++ b/packages/files/src/Domain/Service/SuperConverterServiceInterface.ts @@ -1,6 +1,15 @@ +import { FileItem } from '@standardnotes/models' +import { GenerateUuid } from '@standardnotes/services' + export interface SuperConverterServiceInterface { isValidSuperString(superString: string): boolean convertSuperStringToOtherFormat: (superString: string, toFormat: 'txt' | 'md' | 'html' | 'json') => Promise convertOtherFormatToSuperString: (otherFormatString: string, fromFormat: 'txt' | 'md' | 'html' | 'json') => string getEmbeddedFileIDsFromSuperString(superString: string): string[] + uploadAndReplaceInlineFilesInSuperString( + superString: string, + uploadFile: (file: File) => Promise, + linkFile: (file: FileItem) => Promise, + generateUuid: GenerateUuid, + ): Promise } diff --git a/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.spec.ts b/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.spec.ts index 83151f43c..c38931ef7 100644 --- a/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.spec.ts +++ b/packages/ui-services/src/Import/EvernoteConverter/EvernoteConverter.spec.ts @@ -3,7 +3,7 @@ */ import { ContentType } from '@standardnotes/domain-core' -import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models' +import { DecryptedTransferPayload, FileItem, NoteContent, TagContent } from '@standardnotes/models' import { EvernoteConverter, EvernoteResource } from './EvernoteConverter' import { createTestResourceElement, enex, enexWithNoNoteOrTag } from './testData' import { PureCryptoInterface } from '@standardnotes/sncrypto-common' @@ -33,6 +33,12 @@ describe('EvernoteConverter', () => { convertOtherFormatToSuperString: (data: string) => data, convertSuperStringToOtherFormat: async (data: string) => data, getEmbeddedFileIDsFromSuperString: () => [], + uploadAndReplaceInlineFilesInSuperString: async ( + superString: string, + _uploadFile: (file: File) => Promise, + _linkFile: (file: FileItem) => Promise, + _generateUuid: GenerateUuid, + ) => superString, } const generateUuid = new GenerateUuid(crypto) diff --git a/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.spec.ts b/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.spec.ts index c0ca6324b..6bd936368 100644 --- a/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.spec.ts +++ b/packages/ui-services/src/Import/GoogleKeepConverter/GoogleKeepConverter.spec.ts @@ -6,7 +6,7 @@ import { jsonTextContentData, htmlTestData, jsonListContentData } from './testDa import { GoogleKeepConverter } from './GoogleKeepConverter' import { PureCryptoInterface } from '@standardnotes/sncrypto-common' import { GenerateUuid } from '@standardnotes/services' -import { SuperConverterServiceInterface } from '@standardnotes/snjs' +import { FileItem, SuperConverterServiceInterface } from '@standardnotes/snjs' describe('GoogleKeepConverter', () => { const crypto = { @@ -18,6 +18,12 @@ describe('GoogleKeepConverter', () => { convertOtherFormatToSuperString: (data: string) => data, convertSuperStringToOtherFormat: async (data: string) => data, getEmbeddedFileIDsFromSuperString: () => [], + uploadAndReplaceInlineFilesInSuperString: async ( + superString: string, + _uploadFile: (file: File) => Promise, + _linkFile: (file: FileItem) => Promise, + _generateUuid: GenerateUuid, + ) => superString, } const generateUuid = new GenerateUuid(crypto) diff --git a/packages/ui-services/src/Import/Importer.ts b/packages/ui-services/src/Import/Importer.ts index 444977c6e..5d5ea4d78 100644 --- a/packages/ui-services/src/Import/Importer.ts +++ b/packages/ui-services/src/Import/Importer.ts @@ -6,14 +6,23 @@ import { ItemManagerInterface, MutatorClientInterface, } from '@standardnotes/services' -import { NativeFeatureIdentifier } from '@standardnotes/features' +import { NativeFeatureIdentifier, NoteType } from '@standardnotes/features' import { AegisToAuthenticatorConverter } from './AegisConverter/AegisToAuthenticatorConverter' import { EvernoteConverter } from './EvernoteConverter/EvernoteConverter' import { GoogleKeepConverter } from './GoogleKeepConverter/GoogleKeepConverter' import { PlaintextConverter } from './PlaintextConverter/PlaintextConverter' import { SimplenoteConverter } from './SimplenoteConverter/SimplenoteConverter' import { readFileAsText } from './Utils' -import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models' +import { + DecryptedItemInterface, + DecryptedTransferPayload, + FileItem, + ItemContent, + NoteContent, + NoteMutator, + SNNote, + isNote, +} from '@standardnotes/models' import { HTMLConverter } from './HTMLConverter/HTMLConverter' import { SuperConverterServiceInterface } from '@standardnotes/snjs/dist/@types' import { SuperConverter } from './SuperConverter/SuperConverter' @@ -34,7 +43,22 @@ export class Importer { private mutator: MutatorClientInterface, private items: ItemManagerInterface, private superConverterService: SuperConverterServiceInterface, - _generateUuid: GenerateUuid, + private filesController: { + uploadNewFile( + fileOrHandle: File | FileSystemFileHandle, + options?: { + showToast?: boolean + note?: SNNote + }, + ): Promise + }, + private linkingController: { + linkItems( + item: DecryptedItemInterface, + itemToLink: DecryptedItemInterface, + ): Promise + }, + private _generateUuid: GenerateUuid, ) { this.aegisConverter = new AegisToAuthenticatorConverter(_generateUuid) this.googleKeepConverter = new GoogleKeepConverter(this.superConverterService, _generateUuid) @@ -140,6 +164,27 @@ export class Importer { return this.mutator.insertItem(note) }), ) + for (const item of insertedItems) { + if (!isNote(item)) { + continue + } + if (item.noteType !== NoteType.Super) { + continue + } + try { + const text = await this.superConverterService.uploadAndReplaceInlineFilesInSuperString( + item.text, + async (file) => await this.filesController.uploadNewFile(file, { showToast: true, note: item }), + async (file) => await this.linkingController.linkItems(item, file), + this._generateUuid, + ) + await this.mutator.changeItem(item, (mutator) => { + mutator.text = text + }) + } catch (error) { + console.error(error) + } + } return insertedItems } } diff --git a/packages/web/src/javascripts/Application/Dependencies/WebDependencies.ts b/packages/web/src/javascripts/Application/Dependencies/WebDependencies.ts index 54c461512..75710b3cf 100644 --- a/packages/web/src/javascripts/Application/Dependencies/WebDependencies.ts +++ b/packages/web/src/javascripts/Application/Dependencies/WebDependencies.ts @@ -34,7 +34,7 @@ import { SubscriptionController } from '@/Controllers/Subscription/SubscriptionC import { PurchaseFlowController } from '@/Controllers/PurchaseFlow/PurchaseFlowController' import { FilesController } from '@/Controllers/FilesController' import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController' -import { ImportModalController } from '@/Controllers/ImportModalController' +import { ImportModalController } from '@/Components/ImportModal/ImportModalController' import { ApplicationEventObserver } from '@/Event/ApplicationEventObserver' import { SearchOptionsController } from '@/Controllers/SearchOptionsController' import { LinkingController } from '@/Controllers/LinkingController' @@ -64,6 +64,8 @@ export class WebDependencies extends DependencyContainer { application.mutator, application.items, this.get(Web_TYPES.SuperConverter), + this.get(Web_TYPES.FilesController), + this.get(Web_TYPES.LinkingController), application.generateUuid, ) }) diff --git a/packages/web/src/javascripts/Application/WebApplication.ts b/packages/web/src/javascripts/Application/WebApplication.ts index 1519ff199..ca4a5ad48 100644 --- a/packages/web/src/javascripts/Application/WebApplication.ts +++ b/packages/web/src/javascripts/Application/WebApplication.ts @@ -65,7 +65,7 @@ import { PurchaseFlowController } from '@/Controllers/PurchaseFlow/PurchaseFlowC import { AccountMenuController } from '@/Controllers/AccountMenu/AccountMenuController' import { PreferencesController } from '@/Controllers/PreferencesController' import { NotesController } from '@/Controllers/NotesController/NotesController' -import { ImportModalController } from '@/Controllers/ImportModalController' +import { ImportModalController } from '@/Components/ImportModal/ImportModalController' import { SyncStatusController } from '@/Controllers/SyncStatusController' import { HistoryModalController } from '@/Controllers/NoteHistory/HistoryModalController' import { NavigationController } from '@/Controllers/Navigation/NavigationController' diff --git a/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx b/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx index c18c91d2f..98dbc6f49 100644 --- a/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx +++ b/packages/web/src/javascripts/Components/ImportModal/ImportModal.tsx @@ -4,7 +4,7 @@ import ImportModalFileItem from './ImportModalFileItem' import ImportModalInitialPage from './InitialPage' import Modal, { ModalAction } from '../Modal/Modal' import ModalOverlay from '../Modal/ModalOverlay' -import { ImportModalController } from '@/Controllers/ImportModalController' +import { ImportModalController } from '@/Components/ImportModal/ImportModalController' import { useApplication } from '../ApplicationProvider' import Switch from '../Switch/Switch' @@ -66,7 +66,7 @@ const ImportModal = ({ importModalController }: { importModalController: ImportM )} {files.length > 0 && ( -