extension sync

This commit is contained in:
Mo Bitar
2017-01-05 15:42:35 -06:00
parent 117d6fca4e
commit 54ac4ffd15
10 changed files with 542 additions and 174 deletions

View File

@@ -53,6 +53,12 @@ angular.module('app.frontend')
})
}
this.reloadExtensionsPressed = function() {
if(confirm("For your security, reloading extensions will disable any currently enabled repeat actions.")) {
extensionManager.refreshExtensionsFromServer();
}
}
this.changeServer = function() {
apiController.setServer(this.serverData.url, true);
}

View File

@@ -1,14 +1,3 @@
class Extension extends Item {
constructor(json) {
super(json);
_.merge(this, json);
this.actions = this.actions.map(function(action){
return new Action(action);
})
}
}
class Action {
constructor(json) {
_.merge(this, json);
@@ -22,3 +11,44 @@ class Action {
}
}
}
class Extension extends Item {
constructor(json) {
super(json);
_.merge(this, json);
this.content_type = "Extension";
}
mapContentToLocalProperties(contentObject) {
super.mapContentToLocalProperties(contentObject)
this.name = contentObject.name;
this.url = contentObject.url;
this.actions = contentObject.actions.map(function(action){
return new Action(action);
})
}
updateFromExternalResponseItem(externalResponseItem) {
_.merge(this, externalResponseItem);
this.actions = externalResponseItem.actions.map(function(action){
return new Action(action);
})
}
referenceParams() {
return null;
}
structureParams() {
var params = {
name: this.name,
url: this.url,
actions: this.actions
};
_.merge(params, super.structureParams());
return params;
}
}

View File

@@ -234,7 +234,7 @@ angular.module('app.frontend')
return this.createRequestParamsForItem(item, options.additionalFields);
}.bind(this));
console.log("syncing items", request.items);
// console.log("syncing items", request.items);
if(this.syncToken) {
request.sync_token = this.syncToken;

View File

@@ -1,28 +1,78 @@
class ExtensionManager {
constructor(Restangular, modelManager) {
constructor(Restangular, modelManager, apiController) {
this.Restangular = Restangular;
this.modelManager = modelManager;
this.extensions = [];
this.enabledRepeatActions = [];
this.enabledRepeatActionUrls = localStorage.getItem("enabled_ext_urls") || [];
this.apiController = apiController;
this.enabledRepeatActionUrls = JSON.parse(localStorage.getItem("enabledRepeatActionUrls")) || [];
modelManager.addItemSyncObserver("extensionManager", "Extension", function(items){
for (var ext of items) {
for (var action of ext.actions) {
if(this.enabledRepeatActionUrls.includes(action.url)) {
this.enableRepeatAction(action, ext);
}
}
}
}.bind(this))
}
get extensions() {
return this.modelManager.extensions;
}
actionWithURL(url) {
for (var extension of this.extensions) {
return _.find(extension.actions, {url: url})
}
}
addExtension(url) {
this.retrieveExtensionFromServer(url, null);
}
retrieveExtensionFromServer(url, callback) {
console.log("Registering URL", url);
this.Restangular.oneUrl(url, url).get().then(function(response){
console.log("get response", response.plain());
var extension = new Extension(response.plain());
this.registerExtension(extension);
var ext = this.handleExtensionLoadExternalResponseItem(url, response.plain());
if(callback) {
callback(ext);
}
}.bind(this))
.catch(function(response){
console.log("Error registering extension", response);
})
}
registerExtension(extension) {
this.extensions.push(extension);
console.log("registered extensions", this.extensions);
handleExtensionLoadExternalResponseItem(url, externalResponseItem) {
var extension = _.find(this.extensions, {url: url});
if(extension) {
extension.updateFromExternalResponseItem(externalResponseItem);
console.log("updated existing ext", extension);
} else {
console.log("creating new ext", externalResponseItem);
extension = new Extension(externalResponseItem);
extension.url = url;
extension.dirty = true;
this.modelManager.addItem(extension);
this.apiController.sync(null);
}
return extension;
}
refreshExtensionsFromServer() {
for (var url of this.enabledRepeatActionUrls) {
var action = this.actionWithURL(url);
this.disableRepeatAction(action);
}
for(var ext of this.extensions) {
this.retrieveExtensionFromServer(ext.url, function(extension){
extension.dirty = true;
});
}
}
executeAction(action, extension, callback) {
@@ -43,46 +93,71 @@ class ExtensionManager {
disableRepeatAction(action, extension) {
console.log("Disabling action", action);
_.pull(this.enabledRepeatActionUrls, action.url);
_.pull(this.enabledRepeatActions, action);
this.modelManager.removeItemObserver(action.url);
this.modelManager.removeItemSyncObserver(action.url);
console.assert(this.isRepeatActionEnabled(action) == false);
}
enableRepeatAction(action, extension) {
console.log("Enabling repeat action", action);
this.enabledRepeatActionUrls.push(action.url);
this.enabledRepeatActions.push(action);
if(!_.find(this.enabledRepeatActionUrls, action.url)) {
this.enabledRepeatActionUrls.push(action.url);
localStorage.setItem("enabledRepeatActionUrls", JSON.stringify(this.enabledRepeatActionUrls));
}
if(action.repeatType == "watch") {
for(var structure of action.structures) {
this.modelManager.addItemObserver(action.url, structure.type, function(changedItems){
this.modelManager.addItemSyncObserver(action.url, structure.type, function(changedItems){
this.triggerWatchAction(action, changedItems);
}.bind(this))
}
}
}
queueAction(action, delay, changedItems) {
this.actionQueue = this.actionQueue || [];
if(_.find(this.actionQueue, action)) {
// console.log("Action already queued, skipping.")
return;
}
// console.log("Adding action to queue", action);
this.actionQueue.push(action);
setTimeout(function () {
console.log("Performing queued action", action);
this.triggerWatchAction(action, changedItems);
_.pull(this.actionQueue, action);
}.bind(this), delay * 1000);
}
triggerWatchAction(action, changedItems) {
console.log("Watch action triggered", action, changedItems);
// console.log("Watch action triggered", action, changedItems);
if(action.repeatFrequency > 0) {
var lastExecuted = action.lastExecuted;
var diffInSeconds = (new Date() - lastExecuted)/1000;
console.log("last executed", action.lastExecuted, "diff", diffInSeconds, "repeatFreq", action.repeatFrequency);
if(diffInSeconds < action.repeatFrequency) {
console.log("too frequent, returning");
var delay = action.repeatFrequency - diffInSeconds;
console.log("delaying action by", delay);
this.queueAction(action, delay, changedItems);
return;
}
}
console.log("Performing action immediately", action);
action.lastExecuted = new Date();
// console.log("setting last exectured", action.lastExecuted)
if(action.repeatVerb == "post") {
var request = this.Restangular.oneUrl(action.url, action.url);
request.items = changedItems.map(function(item){
var params = {uuid: item.uuid, content_type: item.content_type, content: item.content};
var params = {uuid: item.uuid, content_type: item.content_type, content: item.createContentJSONFromProperties()};
return params;
})
request.post().then(function(response){
console.log("watch action response", response);
action.lastExecuted = new Date();
// console.log("watch action response", response);
})
}
}

View File

@@ -3,8 +3,9 @@ class ModelManager {
constructor() {
this.notes = [];
this.tags = [];
this.changeObservers = [];
this.itemSyncObservers = [];
this.items = [];
this.extensions = [];
}
findItem(itemId) {
@@ -44,6 +45,13 @@ class ModelManager {
models.push(item)
}
for(var observer of this.itemSyncObservers) {
var relevantItems = models.filter(function(item){return item.content_type == observer.type});
if(relevantItems.length > 0) {
observer.callback(relevantItems);
}
}
this.sortItems();
return models;
}
@@ -53,6 +61,8 @@ class ModelManager {
return new Note(json_obj);
} else if(json_obj.content_type == "Tag") {
return new Tag(json_obj);
} else if(json_obj.content_type == "Extension") {
return new Extension(json_obj);
} else {
return new Item(json_obj);
}
@@ -70,6 +80,10 @@ class ModelManager {
if(!_.find(this.notes, {uuid: item.uuid})) {
this.notes.unshift(item);
}
} else if(item.content_type == "Extension") {
if(!_.find(this.extensions, {uuid: item.uuid})) {
this.extensions.unshift(item);
}
}
}.bind(this))
}
@@ -85,7 +99,6 @@ class ModelManager {
}
resolveReferencesForItem(item) {
var contentObject = item.contentObject;
if(!contentObject.references) {
return;
@@ -100,7 +113,6 @@ class ModelManager {
console.log("Unable to find item:", reference.uuid);
}
}
}
sortItems() {
@@ -111,33 +123,23 @@ class ModelManager {
})
}
addItemObserver(id, type, callback) {
this.changeObservers.push({id: id, type: type, callback: callback});
addItemSyncObserver(id, type, callback) {
this.itemSyncObservers.push({id: id, type: type, callback: callback});
}
removeItemObserver(id) {
_.remove(this.changeObservers, _.find(this.changeObservers, {id: id}));
removeItemSyncObserver(id) {
_.remove(this.itemSyncObservers, _.find(this.itemSyncObservers, {id: id}));
}
get filteredNotes() {
return Note.filterDummyNotes(this.notes);
}
notifyObserversOfSyncCompletion() {
for(var observer of this.changeObservers) {
var changedItems = this.dirtyItems.filter(function(item){return item.content_type == observer.type});
console.log("observer:", observer, "items", changedItems);
observer.callback(changedItems);
}
}
getDirtyItems() {
return this.items.filter(function(item){return item.dirty == true && !item.dummy})
}
clearDirtyItems() {
this.notifyObserversOfSyncCompletion();
this.getDirtyItems().forEach(function(item){
item.dirty = false;
})
@@ -156,6 +158,8 @@ class ModelManager {
_.pull(this.tags, item);
} else if(item.content_type == "Note") {
_.pull(this.notes, item);
} else if(item.content_type == "Extension") {
_.pull(this.extensions, item);
}
}