feat(web): extract ui-services package

This commit is contained in:
Karol Sójko
2022-08-04 15:13:30 +02:00
parent c72a407095
commit 7e251262d7
161 changed files with 1105 additions and 824 deletions

View File

@@ -6,25 +6,42 @@ import {
ChallengeValidation,
ChallengePrompt,
ChallengeReason,
MutatorClientInterface,
} from '@standardnotes/services'
import { BackupFile, EncryptionProvider } from '@standardnotes/encryption'
import { EncryptionProvider } from '@standardnotes/encryption'
import { ClientDisplayableError } from '@standardnotes/responses'
import { ContentType, ProtocolVersion, compareVersions } from '@standardnotes/common'
import { ItemManager, TransactionalMutation } from '../Items'
import { MutatorClientInterface } from './MutatorClientInterface'
import { ItemManager } from '../Items'
import { PayloadManager } from '../Payloads/PayloadManager'
import { SNComponentManager } from '../ComponentManager/ComponentManager'
import { SNProtectionService } from '../Protection/ProtectionService'
import { SNSyncService } from '../Sync'
import { Strings } from '../../Strings'
import { TagsToFoldersMigrationApplicator } from '@Lib/Migrations/Applicators/TagsToFolders'
import * as Models from '@standardnotes/models'
import { Challenge, ChallengeService } from '../Challenge'
import {
BackupFile,
BackupFileDecryptedContextualPayload,
ComponentContent,
CopyPayloadWithContentOverride,
CreateDecryptedBackupFileContextPayload,
CreateDecryptedMutatorForItem,
CreateEncryptedBackupFileContextPayload,
DecryptedItemInterface,
DecryptedItemMutator,
DecryptedPayloadInterface,
EncryptedItemInterface,
FileItem,
isDecryptedPayload,
isEncryptedTransferPayload,
ItemContent,
MutationType,
PayloadEmitSource,
SmartView,
SNComponent,
SNNote,
SNTag,
TransactionalMutation,
} from '@standardnotes/models'
export class MutatorService extends AbstractService implements MutatorClientInterface {
@@ -54,106 +71,101 @@ export class MutatorService extends AbstractService implements MutatorClientInte
;(this.historyService as unknown) = undefined
}
public async insertItem(item: Models.DecryptedItemInterface): Promise<Models.DecryptedItemInterface> {
const mutator = Models.CreateDecryptedMutatorForItem(item, Models.MutationType.UpdateUserTimestamps)
public async insertItem(item: DecryptedItemInterface): Promise<DecryptedItemInterface> {
const mutator = CreateDecryptedMutatorForItem(item, MutationType.UpdateUserTimestamps)
const dirtiedPayload = mutator.getResult()
const insertedItem = await this.itemManager.emitItemFromPayload(
dirtiedPayload,
Models.PayloadEmitSource.LocalInserted,
)
const insertedItem = await this.itemManager.emitItemFromPayload(dirtiedPayload, PayloadEmitSource.LocalInserted)
return insertedItem
}
public async changeAndSaveItem<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
itemToLookupUuidFor: Models.DecryptedItemInterface,
public async changeAndSaveItem<M extends DecryptedItemMutator = DecryptedItemMutator>(
itemToLookupUuidFor: DecryptedItemInterface,
mutate: (mutator: M) => void,
updateTimestamps = true,
emitSource?: Models.PayloadEmitSource,
emitSource?: PayloadEmitSource,
syncOptions?: SyncOptions,
): Promise<Models.DecryptedItemInterface | undefined> {
): Promise<DecryptedItemInterface | undefined> {
await this.itemManager.changeItems(
[itemToLookupUuidFor],
mutate,
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
emitSource,
)
await this.syncService.sync(syncOptions)
return this.itemManager.findItem(itemToLookupUuidFor.uuid)
}
public async changeAndSaveItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
public async changeAndSaveItems<M extends DecryptedItemMutator = DecryptedItemMutator>(
itemsToLookupUuidsFor: DecryptedItemInterface[],
mutate: (mutator: M) => void,
updateTimestamps = true,
emitSource?: Models.PayloadEmitSource,
emitSource?: PayloadEmitSource,
syncOptions?: SyncOptions,
): Promise<void> {
await this.itemManager.changeItems(
itemsToLookupUuidsFor,
mutate,
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
emitSource,
)
await this.syncService.sync(syncOptions)
}
public async changeItem<M extends Models.DecryptedItemMutator>(
itemToLookupUuidFor: Models.DecryptedItemInterface,
public async changeItem<M extends DecryptedItemMutator>(
itemToLookupUuidFor: DecryptedItemInterface,
mutate: (mutator: M) => void,
updateTimestamps = true,
): Promise<Models.DecryptedItemInterface | undefined> {
): Promise<DecryptedItemInterface | undefined> {
await this.itemManager.changeItems(
[itemToLookupUuidFor],
mutate,
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
)
return this.itemManager.findItem(itemToLookupUuidFor.uuid)
}
public async changeItems<M extends Models.DecryptedItemMutator = Models.DecryptedItemMutator>(
itemsToLookupUuidsFor: Models.DecryptedItemInterface[],
public async changeItems<M extends DecryptedItemMutator = DecryptedItemMutator>(
itemsToLookupUuidsFor: DecryptedItemInterface[],
mutate: (mutator: M) => void,
updateTimestamps = true,
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
): Promise<(DecryptedItemInterface | undefined)[]> {
return this.itemManager.changeItems(
itemsToLookupUuidsFor,
mutate,
updateTimestamps ? Models.MutationType.UpdateUserTimestamps : Models.MutationType.NoUpdateUserTimestamps,
updateTimestamps ? MutationType.UpdateUserTimestamps : MutationType.NoUpdateUserTimestamps,
)
}
public async runTransactionalMutations(
transactions: TransactionalMutation[],
emitSource = Models.PayloadEmitSource.LocalChanged,
emitSource = PayloadEmitSource.LocalChanged,
payloadSourceKey?: string,
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
): Promise<(DecryptedItemInterface | undefined)[]> {
return this.itemManager.runTransactionalMutations(transactions, emitSource, payloadSourceKey)
}
public async runTransactionalMutation(
transaction: TransactionalMutation,
emitSource = Models.PayloadEmitSource.LocalChanged,
emitSource = PayloadEmitSource.LocalChanged,
payloadSourceKey?: string,
): Promise<Models.DecryptedItemInterface | undefined> {
): Promise<DecryptedItemInterface | undefined> {
return this.itemManager.runTransactionalMutation(transaction, emitSource, payloadSourceKey)
}
async protectItems<M extends Models.DecryptedItemMutator, I extends Models.DecryptedItemInterface>(
items: I[],
): Promise<I[]> {
async protectItems<M extends DecryptedItemMutator, I extends DecryptedItemInterface>(items: I[]): Promise<I[]> {
const protectedItems = await this.itemManager.changeItems<M, I>(
items,
(mutator) => {
mutator.protected = true
},
Models.MutationType.NoUpdateUserTimestamps,
MutationType.NoUpdateUserTimestamps,
)
void this.syncService.sync()
return protectedItems
}
async unprotectItems<M extends Models.DecryptedItemMutator, I extends Models.DecryptedItemInterface>(
async unprotectItems<M extends DecryptedItemMutator, I extends DecryptedItemInterface>(
items: I[],
reason: ChallengeReason,
): Promise<I[] | undefined> {
@@ -166,74 +178,69 @@ export class MutatorService extends AbstractService implements MutatorClientInte
(mutator) => {
mutator.protected = false
},
Models.MutationType.NoUpdateUserTimestamps,
MutationType.NoUpdateUserTimestamps,
)
void this.syncService.sync()
return unprotectedItems
}
public async protectNote(note: Models.SNNote): Promise<Models.SNNote> {
public async protectNote(note: SNNote): Promise<SNNote> {
const result = await this.protectItems([note])
return result[0]
}
public async unprotectNote(note: Models.SNNote): Promise<Models.SNNote | undefined> {
public async unprotectNote(note: SNNote): Promise<SNNote | undefined> {
const result = await this.unprotectItems([note], ChallengeReason.UnprotectNote)
return result ? result[0] : undefined
}
public async protectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]> {
public async protectNotes(notes: SNNote[]): Promise<SNNote[]> {
return this.protectItems(notes)
}
public async unprotectNotes(notes: Models.SNNote[]): Promise<Models.SNNote[]> {
public async unprotectNotes(notes: SNNote[]): Promise<SNNote[]> {
const results = await this.unprotectItems(notes, ChallengeReason.UnprotectNote)
return results || []
}
async protectFile(file: Models.FileItem): Promise<Models.FileItem> {
async protectFile(file: FileItem): Promise<FileItem> {
const result = await this.protectItems([file])
return result[0]
}
async unprotectFile(file: Models.FileItem): Promise<Models.FileItem | undefined> {
async unprotectFile(file: FileItem): Promise<FileItem | undefined> {
const result = await this.unprotectItems([file], ChallengeReason.UnprotectFile)
return result ? result[0] : undefined
}
public async mergeItem(
item: Models.DecryptedItemInterface,
source: Models.PayloadEmitSource,
): Promise<Models.DecryptedItemInterface> {
public async mergeItem(item: DecryptedItemInterface, source: PayloadEmitSource): Promise<DecryptedItemInterface> {
return this.itemManager.emitItemFromPayload(item.payloadRepresentation(), source)
}
public createTemplateItem<
C extends Models.ItemContent = Models.ItemContent,
I extends Models.DecryptedItemInterface<C> = Models.DecryptedItemInterface<C>,
C extends ItemContent = ItemContent,
I extends DecryptedItemInterface<C> = DecryptedItemInterface<C>,
>(contentType: ContentType, content?: C): I {
return this.itemManager.createTemplateItem(contentType, content)
}
public async setItemNeedsSync(
item: Models.DecryptedItemInterface,
item: DecryptedItemInterface,
updateTimestamps = false,
): Promise<Models.DecryptedItemInterface | undefined> {
): Promise<DecryptedItemInterface | undefined> {
return this.itemManager.setItemDirty(item, updateTimestamps)
}
public async setItemsNeedsSync(
items: Models.DecryptedItemInterface[],
): Promise<(Models.DecryptedItemInterface | undefined)[]> {
public async setItemsNeedsSync(items: DecryptedItemInterface[]): Promise<(DecryptedItemInterface | undefined)[]> {
return this.itemManager.setItemsDirty(items)
}
public async deleteItem(item: Models.DecryptedItemInterface | Models.EncryptedItemInterface): Promise<void> {
public async deleteItem(item: DecryptedItemInterface | EncryptedItemInterface): Promise<void> {
return this.deleteItems([item])
}
public async deleteItems(items: (Models.DecryptedItemInterface | Models.EncryptedItemInterface)[]): Promise<void> {
public async deleteItems(items: (DecryptedItemInterface | EncryptedItemInterface)[]): Promise<void> {
await this.itemManager.setItemsToBeDeleted(items)
await this.syncService.sync()
}
@@ -243,7 +250,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
await this.syncService.sync()
}
public duplicateItem<T extends Models.DecryptedItemInterface>(
public duplicateItem<T extends DecryptedItemInterface>(
item: T,
additionalContent?: Partial<T['content']>,
): Promise<T> {
@@ -257,29 +264,29 @@ export class MutatorService extends AbstractService implements MutatorClientInte
return this.syncService.sync()
}
public async setTagParent(parentTag: Models.SNTag, childTag: Models.SNTag): Promise<void> {
public async setTagParent(parentTag: SNTag, childTag: SNTag): Promise<void> {
await this.itemManager.setTagParent(parentTag, childTag)
}
public async unsetTagParent(childTag: Models.SNTag): Promise<void> {
public async unsetTagParent(childTag: SNTag): Promise<void> {
await this.itemManager.unsetTagParent(childTag)
}
public async findOrCreateTag(title: string): Promise<Models.SNTag> {
public async findOrCreateTag(title: string): Promise<SNTag> {
return this.itemManager.findOrCreateTagByTitle(title)
}
/** Creates and returns the tag but does not run sync. Callers must perform sync. */
public async createTagOrSmartView(title: string): Promise<Models.SNTag | Models.SmartView> {
public async createTagOrSmartView(title: string): Promise<SNTag | SmartView> {
return this.itemManager.createTagOrSmartView(title)
}
public async toggleComponent(component: Models.SNComponent): Promise<void> {
public async toggleComponent(component: SNComponent): Promise<void> {
await this.componentManager.toggleComponent(component.uuid)
await this.syncService.sync()
}
public async toggleTheme(theme: Models.SNComponent): Promise<void> {
public async toggleTheme(theme: SNComponent): Promise<void> {
await this.componentManager.toggleTheme(theme.uuid)
await this.syncService.sync()
}
@@ -289,7 +296,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
awaitSync = false,
): Promise<
| {
affectedItems: Models.DecryptedItemInterface[]
affectedItems: DecryptedItemInterface[]
errorCount: number
}
| {
@@ -342,7 +349,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
if (isEncryptedTransferPayload(item)) {
return CreateEncryptedBackupFileContextPayload(item)
} else {
return CreateDecryptedBackupFileContextPayload(item as Models.BackupFileDecryptedContextualPayload)
return CreateDecryptedBackupFileContextPayload(item as BackupFileDecryptedContextualPayload)
}
})
@@ -355,9 +362,9 @@ export class MutatorService extends AbstractService implements MutatorClientInte
const validPayloads = decryptedPayloadsOrError.filter(isDecryptedPayload).map((payload) => {
/* Don't want to activate any components during import process in
* case of exceptions breaking up the import proccess */
if (payload.content_type === ContentType.Component && (payload.content as Models.ComponentContent).active) {
const typedContent = payload as Models.DecryptedPayloadInterface<Models.ComponentContent>
return Models.CopyPayloadWithContentOverride(typedContent, {
if (payload.content_type === ContentType.Component && (payload.content as ComponentContent).active) {
const typedContent = payload as DecryptedPayloadInterface<ComponentContent>
return CopyPayloadWithContentOverride(typedContent, {
active: false,
})
} else {
@@ -376,7 +383,7 @@ export class MutatorService extends AbstractService implements MutatorClientInte
await promise
}
const affectedItems = this.itemManager.findItems(affectedUuids) as Models.DecryptedItemInterface[]
const affectedItems = this.itemManager.findItems(affectedUuids) as DecryptedItemInterface[]
return {
affectedItems: affectedItems,