@@ -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);
|
||||
});
|
||||
})
|
||||
|
||||
@@ -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});
|
||||
|
||||
@@ -28,6 +28,10 @@ class DesktopManager {
|
||||
})
|
||||
}
|
||||
|
||||
saveBackup() {
|
||||
this.majorDataChangeHandler && this.majorDataChangeHandler();
|
||||
}
|
||||
|
||||
getApplicationDataPath() {
|
||||
console.assert(this.applicationDataPath, "applicationDataPath is null");
|
||||
return this.applicationDataPath;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
|
||||
67
app/assets/javascripts/app/services/statusManager.js
Normal file
67
app/assets/javascripts/app/services/statusManager.js
Normal 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);
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user