Skip to content

Commit

Permalink
refactor: importing (again)
Browse files Browse the repository at this point in the history
  • Loading branch information
amanharwara committed Dec 8, 2023
1 parent 63e69b5 commit 45512af
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class AegisToAuthenticatorConverter implements Converter {
return false
}

convert: Converter['convert'] = async (file, { createNote, readFileAsText }) => {
convert: Converter['convert'] = async (file, { insertNote: createNote, readFileAsText }) => {
const content = await readFileAsText(file)

const entries = this.parseEntries(content)
Expand Down
26 changes: 18 additions & 8 deletions packages/ui-services/src/Import/Converter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NoteType } from '@standardnotes/features'
import { DecryptedTransferPayload, ItemContent, NoteContent, TagContent } from '@standardnotes/models'
import { DecryptedItemInterface, ItemContent, NoteContent, SNNote, SNTag } from '@standardnotes/models'

export interface Converter {
getImportType(): string
Expand All @@ -12,17 +12,21 @@ export interface Converter {
convert(
file: File,
dependencies: {
createNote: CreateNoteFn
createTag: CreateTagFn
insertNote: InsertNoteFn
insertTag: InsertTagFn
canUseSuper: boolean
convertHTMLToSuper: (html: string) => string
convertMarkdownToSuper: (markdown: string) => string
readFileAsText: (file: File) => Promise<string>
linkItems(
item: DecryptedItemInterface<ItemContent>,
itemToLink: DecryptedItemInterface<ItemContent>,
): Promise<void>
},
): Promise<DecryptedTransferPayload<ItemContent>[]>
): Promise<void>
}

export type CreateNoteFn = (options: {
export type InsertNoteFn = (options: {
createdAt: Date
updatedAt: Date
title: string
Expand All @@ -33,10 +37,16 @@ export type CreateNoteFn = (options: {
trashed?: boolean
editorIdentifier?: NoteContent['editorIdentifier']
useSuperIfPossible: boolean
}) => DecryptedTransferPayload<NoteContent>
}) => Promise<SNNote>

export type CreateTagFn = (options: {
export type InsertTagFn = (options: {
createdAt: Date
updatedAt: Date
title: string
}) => DecryptedTransferPayload<TagContent>
references: SNTag['references']
}) => Promise<SNTag>

export type LinkItemsFn = (
item: DecryptedItemInterface<ItemContent>,
itemToLink: DecryptedItemInterface<ItemContent>,
) => Promise<void>
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('EvernoteConverter', () => {
references: [],
},
}) as unknown as DecryptedTransferPayload<NoteContent>,
createTag: ({ title }) =>
insertTag: ({ title }) =>
({
content_type: ContentType.TYPES.Tag,
content: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DecryptedTransferPayload, NoteContent, TagContent } from '@standardnotes/models'
import { SNTag } from '@standardnotes/models'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import utc from 'dayjs/plugin/utc'
Expand Down Expand Up @@ -35,14 +35,13 @@ export class EvernoteConverter implements Converter {

convert: Converter['convert'] = async (
file,
{ createNote, createTag, canUseSuper, convertHTMLToSuper, readFileAsText },
{ insertNote, insertTag, linkItems, canUseSuper, convertHTMLToSuper, readFileAsText },
) => {
const content = await readFileAsText(file)

const xmlDoc = this.loadXMLString(content, 'xml')
const xmlNotes = xmlDoc.getElementsByTagName('note')
const notes: DecryptedTransferPayload<NoteContent>[] = []
const tags: DecryptedTransferPayload<TagContent>[] = []
const tags: SNTag[] = []

function findTag(title: string | null) {
return tags.filter(function (tag) {
Expand Down Expand Up @@ -103,7 +102,7 @@ export class EvernoteConverter implements Converter {
const createdAtDate = created ? dayjs.utc(created, dateFormat).toDate() : new Date()
const updatedAtDate = updated ? dayjs.utc(updated, dateFormat).toDate() : createdAtDate

const note = createNote({
const note = await insertNote({
createdAt: createdAtDate,
updatedAt: updatedAtDate,
title: !title ? `Imported note ${index + 1} from Evernote` : title,
Expand All @@ -115,29 +114,21 @@ export class EvernoteConverter implements Converter {
for (const tagXml of Array.from(xmlTags)) {
const tagName = tagXml.childNodes[0].nodeValue
let tag = findTag(tagName)

if (!tag) {
const now = new Date()
tag = createTag({
tag = await insertTag({
createdAt: now,
updatedAt: now,
title: tagName || `Imported tag ${index + 1} from Evernote`,
references: [],
})
tags.push(tag)
}

note.content.references.push({ content_type: tag.content_type, uuid: tag.uuid })
tag.content.references.push({ content_type: note.content_type, uuid: note.uuid })
await linkItems(note, tag)
}

notes.push(note)
}

const allItems: DecryptedTransferPayload[] = [...notes, ...tags]
if (allItems.length === 0) {
throw new Error('Could not parse any notes or tags from Evernote file.')
}

return allItems
}

getXmlStringFromContentElement(contentElement: Element) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DecryptedTransferPayload, NoteContent } from '@standardnotes/models'
import { Converter, CreateNoteFn } from '../Converter'
import { Converter, InsertNoteFn } from '../Converter'

type Content =
| {
Expand Down Expand Up @@ -45,7 +45,7 @@ export class GoogleKeepConverter implements Converter {

convert: Converter['convert'] = async (
file,
{ createNote, canUseSuper, convertHTMLToSuper, convertMarkdownToSuper, readFileAsText },
{ insertNote: createNote, canUseSuper, convertHTMLToSuper, convertMarkdownToSuper, readFileAsText },
) => {
const content = await readFileAsText(file)

Expand All @@ -67,7 +67,7 @@ export class GoogleKeepConverter implements Converter {
tryParseAsHtml(
data: string,
file: { name: string },
createNote: CreateNoteFn,
createNote: InsertNoteFn,
convertHTMLToSuper: (html: string) => string,
canUseSuper: boolean,
): DecryptedTransferPayload<NoteContent> {
Expand Down Expand Up @@ -152,7 +152,7 @@ export class GoogleKeepConverter implements Converter {

tryParseAsJson(
data: string,
createNote: CreateNoteFn,
createNote: InsertNoteFn,
convertMarkdownToSuper: (md: string) => string,
): DecryptedTransferPayload<NoteContent> | null {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class HTMLConverter implements Converter {
return true
}

convert: Converter['convert'] = async (file, { createNote, convertHTMLToSuper, readFileAsText }) => {
convert: Converter['convert'] = async (file, { insertNote: createNote, convertHTMLToSuper, readFileAsText }) => {
const content = await readFileAsText(file)

const { name } = parseFileName(file.name)
Expand Down
97 changes: 41 additions & 56 deletions packages/ui-services/src/Import/Importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ import {
NoteContent,
NoteMutator,
SNNote,
SNTag,
TagContent,
isNote,
} from '@standardnotes/models'
import { HTMLConverter } from './HTMLConverter/HTMLConverter'
import { SuperConverter } from './SuperConverter/SuperConverter'
import { Converter, CreateNoteFn, CreateTagFn } from './Converter'
import { Converter, InsertNoteFn, InsertTagFn, LinkItemsFn } from './Converter'
import { SuperConverterServiceInterface } from '@standardnotes/files'
import { ContentType } from '@standardnotes/domain-core'

Expand All @@ -50,6 +52,7 @@ export class Importer {
linkItems(
item: DecryptedItemInterface<ItemContent>,
itemToLink: DecryptedItemInterface<ItemContent>,
sync: boolean,
): Promise<void>
},
private _generateUuid: GenerateUuid,
Expand Down Expand Up @@ -88,16 +91,16 @@ export class Importer {
return null
}

createNote: CreateNoteFn = ({
insertNote: InsertNoteFn = async ({
createdAt,
updatedAt,
title,
text,
noteType,
editorIdentifier,
trashed,
archived,
pinned,
trashed = false,
archived = false,
pinned = false,
useSuperIfPossible,
}) => {
if (noteType === NoteType.Super && !this.isEntitledToSuper()) {
Expand All @@ -114,14 +117,9 @@ export class Importer {

const shouldUseSuper = useSuperIfPossible && this.isEntitledToSuper()

return {
created_at: createdAt,
created_at_timestamp: createdAt.getTime(),
updated_at: updatedAt,
updated_at_timestamp: updatedAt.getTime(),
uuid: this._generateUuid.execute().getValue(),
content_type: ContentType.TYPES.Note,
content: {
const note = this.items.createTemplateItem<NoteContent, SNNote>(
ContentType.TYPES.Note,
{
title,
text,
references: [],
Expand All @@ -131,24 +129,35 @@ export class Importer {
pinned,
editorIdentifier: shouldUseSuper ? NativeFeatureIdentifier.TYPES.SuperEditor : editorIdentifier,
},
}
{
created_at: createdAt,
updated_at: updatedAt,
},
)

return await this.mutator.insertItem(note)
}

createTag: CreateTagFn = ({ createdAt, updatedAt, title }) => {
return {
uuid: this._generateUuid.execute().getValue(),
content_type: ContentType.TYPES.Tag,
created_at: createdAt,
created_at_timestamp: createdAt.getTime(),
updated_at: updatedAt,
updated_at_timestamp: updatedAt.getTime(),
content: {
title: title,
insertTag: InsertTagFn = async ({ createdAt, updatedAt, title, references }) => {
const tag = this.items.createTemplateItem<TagContent, SNTag>(
ContentType.TYPES.Tag,
{
title,
expanded: false,
iconString: '',
references: [],
references,
},
}
{
created_at: createdAt,
updated_at: updatedAt,
},
)

return await this.mutator.insertItem(tag)
}

linkItems: LinkItemsFn = async (item, itemToLink) => {
await this.linkingController.linkItems(item, itemToLink, false)
}

isEntitledToSuper = (): boolean => {
Expand All @@ -175,7 +184,7 @@ export class Importer {
return this.superConverterService.convertOtherFormatToSuperString(markdown, 'md')
}

async getPayloadsFromFile(file: File, type: string): Promise<DecryptedTransferPayload[]> {
async importFromFile(file: File, type: string): Promise<DecryptedTransferPayload[]> {
const isEntitledToSuper = this.isEntitledToSuper()

if (type === 'super' && !isEntitledToSuper) {
Expand All @@ -195,44 +204,20 @@ export class Importer {
throw new Error('Content is not valid')
}

return await converter.convert(file, {
createNote: this.createNote,
createTag: this.createTag,
await converter.convert(file, {
insertNote: this.insertNote,
insertTag: this.insertTag,
canUseSuper: isEntitledToSuper,
convertHTMLToSuper: this.convertHTMLToSuper,
convertMarkdownToSuper: this.convertMarkdownToSuper,
readFileAsText,
linkItems: this.linkItems,
})
}

return []
}

async importFromTransferPayloads(payloads: DecryptedTransferPayload[]) {
const insertedItems = await Promise.all(
payloads.map(async (payload) => {
const content = payload.content as NoteContent
const note = this.items.createTemplateItem(
payload.content_type,
{
text: content.text,
title: content.title,
noteType: content.noteType,
editorIdentifier: content.editorIdentifier,
references: content.references,
},
{
created_at: payload.created_at,
updated_at: payload.updated_at,
uuid: payload.uuid,
},
)
return this.mutator.insertItem(note)
}),
)
return insertedItems
}

async uploadAndReplaceInlineFilesInInsertedItems(insertedItems: DecryptedItemInterface<ItemContent>[]) {
for (const item of insertedItems) {
if (!isNote(item)) {
Expand All @@ -245,7 +230,7 @@ export class Importer {
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),
async (file) => await this.linkingController.linkItems(item, file, false),
this._generateUuid,
)
await this.mutator.changeItem<NoteMutator>(item, (mutator) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ export class PlaintextConverter implements Converter {
return file.type === 'text/plain' || file.type === 'text/markdown'
}

convert: Converter['convert'] = async (file, { createNote, convertMarkdownToSuper, readFileAsText }) => {
convert: Converter['convert'] = async (file, { insertNote, convertMarkdownToSuper, readFileAsText }) => {
const content = await readFileAsText(file)

const { name } = parseFileName(file.name)

const createdAtDate = file.lastModified ? new Date(file.lastModified) : new Date()
const updatedAtDate = file.lastModified ? new Date(file.lastModified) : new Date()

return [
createNote({
createdAt: createdAtDate,
updatedAt: updatedAtDate,
title: name,
text: convertMarkdownToSuper(content),
useSuperIfPossible: true,
}),
]
await insertNote({
createdAt: createdAtDate,
updatedAt: updatedAtDate,
title: name,
text: convertMarkdownToSuper(content),
useSuperIfPossible: true,
})

return []
}
}
Loading

0 comments on commit 45512af

Please sign in to comment.