Files
standardnotes-app-web/app/assets/javascripts/services/migrationManager.js
2020-02-04 14:22:02 +01:00

173 lines
5.6 KiB
JavaScript

import { isDesktopApplication } from '@/utils';
import { SFMigrationManager } from 'snjs';
import { ComponentManager } from '@/services/componentManager';
export class MigrationManager extends SFMigrationManager {
/* @ngInject */
constructor(
modelManager,
syncManager,
componentManager,
storageManager,
statusManager,
authManager,
desktopManager
) {
super(modelManager, syncManager, storageManager, authManager);
this.componentManager = componentManager;
this.statusManager = statusManager;
this.desktopManager = desktopManager;
}
registeredMigrations() {
return [
this.editorToComponentMigration(),
this.componentUrlToHostedUrl(),
this.removeTagReferencesFromNotes()
];
}
/*
Migrate SN|Editor to SN|Component. Editors are deprecated as of November 2017. Editors using old APIs must
convert to using the new component API.
*/
editorToComponentMigration() {
return {
name: "editor-to-component",
content_type: "SN|Editor",
handler: async (editors) => {
// Convert editors to components
for(var editor of editors) {
// If there's already a component for this url, then skip this editor
if(editor.url && !this.componentManager.componentForUrl(editor.url)) {
var component = this.modelManager.createItem({
content_type: "SN|Component",
content: {
url: editor.url,
name: editor.name,
area: "editor-editor"
}
});
component.setAppDataItem("data", editor.data);
this.modelManager.addItem(component);
this.modelManager.setItemDirty(component, true);
}
}
for(const editor of editors) {
this.modelManager.setItemToBeDeleted(editor);
}
this.syncManager.sync();
}
};
}
/*
Migrate component.url fields to component.hosted_url. This involves rewriting any note data that relied on the
component.url value to store clientData, such as the CodeEditor, which stores the programming language for the note
in the note's clientData[component.url]. We want to rewrite any matching items to transfer that clientData into
clientData[component.uuid].
April 3, 2019 note: it seems this migration is mis-named. The first part of the description doesn't match what the code is actually doing.
It has nothing to do with url/hosted_url relationship and more to do with just mapping client data from the note's hosted_url to its uuid
Created: July 6, 2018
*/
componentUrlToHostedUrl() {
return {
name: "component-url-to-hosted-url",
content_type: "SN|Component",
handler: async (components) => {
let hasChanges = false;
const notes = this.modelManager.validItemsForContentType("Note");
for(const note of notes) {
for(const component of components) {
const clientData = note.getDomainDataItem(component.hosted_url, ComponentManager.ClientDataDomain);
if(clientData) {
note.setDomainDataItem(component.uuid, clientData, ComponentManager.ClientDataDomain);
note.setDomainDataItem(component.hosted_url, null, ComponentManager.ClientDataDomain);
this.modelManager.setItemDirty(note, true);
hasChanges = true;
}
}
}
if(hasChanges) {
this.syncManager.sync();
}
}
};
}
/*
Migrate notes which have relationships on tags to migrate those relationships to the tags themselves.
That is, notes.content.references should not include any mention of tags.
This will apply to notes created before the schema change. Now, only tags reference notes.
Created: April 3, 2019
*/
removeTagReferencesFromNotes() {
return {
name: "remove-tag-references-from-notes",
content_type: "Note",
handler: async (notes) => {
const needsSync = false;
let status = this.statusManager.addStatusFromString("Optimizing data...");
let dirtyCount = 0;
for(const note of notes) {
if(!note.content) {
continue;
}
const references = note.content.references;
// Remove any tag references, and transfer them to the tag if neccessary.
const newReferences = [];
for(const reference of references) {
if(reference.content_type != "Tag") {
newReferences.push(reference);
continue;
}
// is Tag content_type, we will not be adding this to newReferences
const tag = this.modelManager.findItem(reference.uuid);
if(tag && !tag.hasRelationshipWithItem(note)) {
tag.addItemAsRelationship(note);
this.modelManager.setItemDirty(tag, true);
dirtyCount++;
}
}
if(newReferences.length != references.length) {
note.content.references = newReferences;
this.modelManager.setItemDirty(note, true);
dirtyCount++;
}
}
if(dirtyCount > 0) {
if(isDesktopApplication()) {
this.desktopManager.saveBackup();
}
status = this.statusManager.replaceStatusWithString(status, `${dirtyCount} items optimized.`);
await this.syncManager.sync();
status = this.statusManager.replaceStatusWithString(status, `Optimization complete.`);
setTimeout(() => {
this.statusManager.removeStatus(status);
}, 2000);
} else {
this.statusManager.removeStatus(status);
}
}
};
}
}