Merge pull request #285 from standardnotes/3.0.8

3.0.8
This commit is contained in:
Mo Bitar
2019-04-16 13:33:45 -05:00
committed by GitHub
42 changed files with 1487 additions and 1163 deletions

View File

@@ -122,18 +122,22 @@ class ActionsManager {
switch (action.verb) {
case "get": {
this.httpManager.getAbsolute(action.url, {}, async (response) => {
action.error = false;
handleResponseDecryption(response, await this.authManager.keys(), true);
}, (response) => {
action.error = true;
customCallback(null);
})
if(confirm("Are you sure you want to replace the current note contents with this action's results?")) {
this.httpManager.getAbsolute(action.url, {}, async (response) => {
action.error = false;
handleResponseDecryption(response, await this.authManager.keys(), true);
}, (response) => {
if(response && response.error) {
alert("An issue occurred while processing this action. Please try again.");
}
action.error = true;
customCallback(null);
})
}
break;
}
case "render": {
this.httpManager.getAbsolute(action.url, {}, async (response) => {
action.error = false;
handleResponseDecryption(response, await this.authManager.keys(), false);
@@ -158,7 +162,10 @@ class ActionsManager {
items: [itemParams] // Wrap it in an array
}
this.performPost(action, extension, params, function(response){
this.performPost(action, extension, params, (response) => {
if(response && response.error) {
alert("An issue occurred while processing this action. Please try again.");
}
customCallback(response);
});
})

View File

@@ -24,6 +24,11 @@ class AuthManager extends SFAuthManager {
this.configureUserPrefs();
this.checkForSecurityUpdate();
this.modelManager.addItemSyncObserver("user-prefs", "SN|UserPreferences", (allItems, validItems, deletedItems, source, sourceKey) => {
this.userPreferencesDidChange();
});
}
offline() {
@@ -136,7 +141,6 @@ class AuthManager extends SFAuthManager {
let contentTypePredicate = new SFPredicate("content_type", "=", prefsContentType);
this.singletonManager.registerSingleton([contentTypePredicate], (resolvedSingleton) => {
this.userPreferences = resolvedSingleton;
this.userPreferencesDidChange();
}, (valueCallback) => {
// Safe to create. Create and return object.
var prefs = new SFItem({content_type: prefsContentType});

View File

@@ -28,6 +28,10 @@ class DesktopManager {
})
}
saveBackup() {
this.majorDataChangeHandler && this.majorDataChangeHandler();
}
getApplicationDataPath() {
console.assert(this.applicationDataPath, "applicationDataPath is null");
return this.applicationDataPath;

View File

@@ -1,14 +1,17 @@
class MigrationManager extends SFMigrationManager {
constructor($rootScope, modelManager, syncManager, componentManager, storageManager) {
super(modelManager, syncManager, storageManager);
constructor($rootScope, 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.componentUrlToHostedUrl(),
this.removeTagReferencesFromNotes()
];
}
@@ -54,6 +57,10 @@ class MigrationManager extends SFMigrationManager {
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() {
@@ -62,10 +69,10 @@ class MigrationManager extends SFMigrationManager {
content_type: "SN|Component",
handler: async (components) => {
let hasChanges = false;
var notes = this.modelManager.validItemsForContentType("Note");
for(var note of notes) {
for(var component of components) {
var clientData = note.getDomainDataItem(component.hosted_url, ComponentManager.ClientDataDomain);
let notes = this.modelManager.validItemsForContentType("Note");
for(let note of notes) {
for(let component of components) {
let 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);
@@ -81,6 +88,74 @@ class MigrationManager extends SFMigrationManager {
}
}
}
/*
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) => {
let needsSync = false;
let status = this.statusManager.addStatusFromString("Optimizing data...");
let dirtyCount = 0;
for(let note of notes) {
if(!note.content) {
continue;
}
let references = note.content.references;
// Remove any tag references, and transfer them to the tag if neccessary.
let newReferences = [];
for(let reference of references) {
if(reference.content_type != "Tag") {
newReferences.push(reference);
continue;
}
// is Tag content_type, we will not be adding this to newReferences
let tag = this.modelManager.findItem(reference.uuid);
if(tag && !tag.hasRelationshipWithItem(note)) {
tag.addItemAsRelationship(note);
tag.setDirty(true, true);
dirtyCount++;
}
}
if(newReferences.length != references.length) {
note.content.references = newReferences;
note.setDirty(true, 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);
}
}
}
}
}
angular.module('app').service('migrationManager', MigrationManager);

View File

@@ -11,6 +11,7 @@ class PasscodeManager {
this._hasPasscode = this.storageManager.getItemSync("offlineParams", StorageManager.Fixed) != null;
this._locked = this._hasPasscode;
this.visibilityObservers = [];
this.passcodeChangeObservers = [];
this.configureAutoLock();
@@ -37,6 +38,21 @@ class PasscodeManager {
return this._keys;
}
addVisibilityObserver(callback) {
this.visibilityObservers.push(callback);
return callback;
}
removeVisibilityObserver(callback) {
_.pull(this.visibilityObservers, callback);
}
notifiyVisibilityObservers(visible) {
for(let callback of this.visibilityObservers) {
callback(visible);
}
}
async setAutoLockInterval(interval) {
return this.storageManager.setItem(PasscodeManager.AutoLockIntervalKey, JSON.stringify(interval), StorageManager.FixedEncrypted);
}
@@ -213,6 +229,8 @@ class PasscodeManager {
} else {
this.beginAutoLockTimer();
}
this.notifiyVisibilityObservers(visible);
}
async beginAutoLockTimer() {

View File

@@ -0,0 +1,67 @@
class StatusManager {
constructor() {
this.statuses = [];
this.observers = [];
}
statusFromString(string) {
return {string: string};
}
replaceStatusWithString(status, string) {
this.removeStatus(status);
return this.addStatusFromString(string);
}
addStatusFromString(string) {
return this.addStatus(this.statusFromString(string));
}
addStatus(status) {
if(typeof status !== "object") {
console.error("Attempting to set non-object status", status);
return;
}
this.statuses.push(status);
this.notifyObservers();
return status;
}
removeStatus(status) {
_.pull(this.statuses, status);
this.notifyObservers();
return null;
}
getStatusString() {
let result = "";
this.statuses.forEach((status, index) => {
if(index > 0) {
result += " ";
}
result += status.string;
})
return result;
}
notifyObservers() {
for(let observer of this.observers) {
observer(this.getStatusString());
}
}
addStatusObserver(callback) {
this.observers.push(callback);
}
removeStatusObserver(callback) {
_.pull(this.statuses, callback);
}
}
angular.module('app').service('statusManager', StatusManager);

View File

@@ -107,7 +107,12 @@ class StorageManager extends SFStorageManager {
async setItem(key, value, vaultKey) {
var storage = this.getVault(vaultKey);
storage.setItem(key, value);
try {
storage.setItem(key, value);
} catch (e) {
console.error("Exception while trying to setItem in StorageManager:", e);
alert("The application's local storage is out of space. If you have Session History save-to-disk enabled, please disable it, and try again.");
}
if(vaultKey === StorageManager.FixedEncrypted || (!vaultKey && this.itemsStorageMode === StorageManager.FixedEncrypted)) {
this.writeEncryptedStorageToDisk();