WIP
This commit is contained in:
@@ -7,10 +7,12 @@ class ActionsMenuCtrl extends PureCtrl {
|
|||||||
$scope,
|
$scope,
|
||||||
$timeout,
|
$timeout,
|
||||||
actionsManager,
|
actionsManager,
|
||||||
|
godService
|
||||||
) {
|
) {
|
||||||
super($timeout);
|
super($timeout);
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.actionsManager = actionsManager;
|
this.actionsManager = actionsManager;
|
||||||
|
this.godService = godService;
|
||||||
}
|
}
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
@@ -64,7 +66,7 @@ class ActionsMenuCtrl extends PureCtrl {
|
|||||||
switch (action.verb) {
|
switch (action.verb) {
|
||||||
case 'render': {
|
case 'render': {
|
||||||
const item = result.item;
|
const item = result.item;
|
||||||
this.actionsManager.presentRevisionPreviewModal(
|
this.godService.presentRevisionPreviewModal(
|
||||||
item.uuid,
|
item.uuid,
|
||||||
item.content
|
item.content
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
import { protocolManager, SNComponent, SFItem, SFModelManager } from 'snjs';
|
import {
|
||||||
|
PAYLOAD_SOURCE_REMOTE_ACTION_RETRIEVED,
|
||||||
|
CONTENT_TYPE_NOTE,
|
||||||
|
CONTENT_TYPE_COMPONENT
|
||||||
|
} from 'snjs';
|
||||||
import template from '%/directives/revision-preview-modal.pug';
|
import template from '%/directives/revision-preview-modal.pug';
|
||||||
|
|
||||||
class RevisionPreviewModalCtrl {
|
class RevisionPreviewModalCtrl {
|
||||||
@@ -6,44 +10,40 @@ class RevisionPreviewModalCtrl {
|
|||||||
constructor(
|
constructor(
|
||||||
$element,
|
$element,
|
||||||
$scope,
|
$scope,
|
||||||
$timeout,
|
$timeout
|
||||||
syncManager,
|
|
||||||
) {
|
) {
|
||||||
this.$element = $element;
|
this.$element = $element;
|
||||||
this.$scope = $scope;
|
this.$scope = $scope;
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.syncManager = syncManager;
|
this.configure();
|
||||||
this.createNote();
|
|
||||||
this.configureEditor();
|
|
||||||
$scope.$on('$destroy', () => {
|
$scope.$on('$destroy', () => {
|
||||||
if (this.identifier) {
|
if (this.identifier) {
|
||||||
this.application.componentManager.deregisterHandler(this.identifier);
|
this.application.componentManager.deregisterHandler(this.identifier);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createNote() {
|
async configure() {
|
||||||
this.note = new SFItem({
|
this.note = await this.application.createItem({
|
||||||
content: this.content,
|
contentType: CONTENT_TYPE_NOTE,
|
||||||
content_type: "Note"
|
content: this.content
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
configureEditor() {
|
|
||||||
/**
|
/**
|
||||||
* Set UUID so editoForNote can find proper editor, but then generate new uuid
|
* Set UUID so editoForNote can find proper editor, but then generate new uuid
|
||||||
* for note as not to save changes to original, if editor makes changes.
|
* for note as not to save changes to original, if editor makes changes.
|
||||||
*/
|
*/
|
||||||
this.note.uuid = this.uuid;
|
this.note.uuid = this.uuid;
|
||||||
const editorForNote = this.application.componentManager.editorForNote(this.note);
|
const editorForNote = this.application.componentManager.editorForNote(this.note);
|
||||||
this.note.uuid = protocolManager.crypto.generateUUIDSync();
|
this.note.uuid = await this.application.generateUuid();
|
||||||
if (editorForNote) {
|
if (editorForNote) {
|
||||||
/**
|
/**
|
||||||
* Create temporary copy, as a lot of componentManager is uuid based, so might
|
* Create temporary copy, as a lot of componentManager is uuid based, so might
|
||||||
* interfere with active editor. Be sure to copy only the content, as the top level
|
* interfere with active editor. Be sure to copy only the content, as the top level
|
||||||
* editor object has non-copyable properties like .window, which cannot be transfered
|
* editor object has non-copyable properties like .window, which cannot be transfered
|
||||||
*/
|
*/
|
||||||
const editorCopy = new SNComponent({
|
const editorCopy = await this.application.createItem({
|
||||||
|
contentType: CONTENT_TYPE_COMPONENT,
|
||||||
content: editorForNote.content
|
content: editorForNote.content
|
||||||
});
|
});
|
||||||
editorCopy.readonly = true;
|
editorCopy.readonly = true;
|
||||||
@@ -85,13 +85,12 @@ class RevisionPreviewModalCtrl {
|
|||||||
const uuid = this.uuid;
|
const uuid = this.uuid;
|
||||||
item = this.application.findItem({uuid: uuid});
|
item = this.application.findItem({uuid: uuid});
|
||||||
item.content = Object.assign({}, this.content);
|
item.content = Object.assign({}, this.content);
|
||||||
this.modelManager.mapResponseItemsToLocalModels(
|
await this.application.mergeItem({
|
||||||
[item],
|
item: item,
|
||||||
SFModelManager.MappingSourceRemoteActionRetrieved
|
source: PAYLOAD_SOURCE_REMOTE_ACTION_RETRIEVED
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
this.modelManager.setItemDirty(item);
|
this.application.saveItem({item});
|
||||||
this.syncManager.sync();
|
|
||||||
this.dismiss();
|
this.dismiss();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,14 @@ class SessionHistoryMenuCtrl {
|
|||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor(
|
||||||
$timeout,
|
$timeout,
|
||||||
actionsManager,
|
godService,
|
||||||
alertManager,
|
application,
|
||||||
sessionHistory,
|
|
||||||
) {
|
) {
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.alertManager = alertManager;
|
this.godService = godService;
|
||||||
this.actionsManager = actionsManager;
|
this.application = application;
|
||||||
this.sessionHistory = sessionHistory;
|
this.diskEnabled = this.application.historyManager.isDiskEnabled();
|
||||||
this.diskEnabled = this.sessionHistory.diskEnabled;
|
this.autoOptimize = this.application.historyManager.isAutoOptimizeEnabled();
|
||||||
this.autoOptimize = this.sessionHistory.autoOptimize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
@@ -21,7 +19,7 @@ class SessionHistoryMenuCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reloadHistory() {
|
reloadHistory() {
|
||||||
const history = this.sessionHistory.historyForItem(this.item);
|
const history = this.application.historyManager.historyForItem(this.item);
|
||||||
this.entries = history.entries.slice(0).sort((a, b) => {
|
this.entries = history.entries.slice(0).sort((a, b) => {
|
||||||
return a.item.updated_at < b.item.updated_at ? 1 : -1;
|
return a.item.updated_at < b.item.updated_at ? 1 : -1;
|
||||||
});
|
});
|
||||||
@@ -29,7 +27,7 @@ class SessionHistoryMenuCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openRevision(revision) {
|
openRevision(revision) {
|
||||||
this.actionsManager.presentRevisionPreviewModal(
|
this.godService.presentRevisionPreviewModal(
|
||||||
revision.item.uuid,
|
revision.item.uuid,
|
||||||
revision.item.content
|
revision.item.content
|
||||||
);
|
);
|
||||||
@@ -47,11 +45,11 @@ class SessionHistoryMenuCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearItemHistory() {
|
clearItemHistory() {
|
||||||
this.alertManager.confirm({
|
this.application.alertManager.confirm({
|
||||||
text: "Are you sure you want to delete the local session history for this note?",
|
text: "Are you sure you want to delete the local session history for this note?",
|
||||||
destructive: true,
|
destructive: true,
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
this.sessionHistory.clearHistoryForItem(this.item).then(() => {
|
this.application.historyManager.clearHistoryForItem(this.item).then(() => {
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.reloadHistory();
|
this.reloadHistory();
|
||||||
});
|
});
|
||||||
@@ -61,11 +59,11 @@ class SessionHistoryMenuCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearAllHistory() {
|
clearAllHistory() {
|
||||||
this.alertManager.confirm({
|
this.application.alertManager.confirm({
|
||||||
text: "Are you sure you want to delete the local session history for all notes?",
|
text: "Are you sure you want to delete the local session history for all notes?",
|
||||||
destructive: true,
|
destructive: true,
|
||||||
onConfirm: () => {
|
onConfirm: () => {
|
||||||
this.sessionHistory.clearAllHistory().then(() => {
|
this.application.historyManager.clearAllHistory().then(() => {
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.reloadHistory();
|
this.reloadHistory();
|
||||||
});
|
});
|
||||||
@@ -76,14 +74,14 @@ class SessionHistoryMenuCtrl {
|
|||||||
|
|
||||||
toggleDiskSaving() {
|
toggleDiskSaving() {
|
||||||
const run = () => {
|
const run = () => {
|
||||||
this.sessionHistory.toggleDiskSaving().then(() => {
|
this.application.historyManager.toggleDiskSaving().then(() => {
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.diskEnabled = this.sessionHistory.diskEnabled;
|
this.diskEnabled = this.application.historyManager.diskEnabled;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
if (!this.sessionHistory.diskEnabled) {
|
if (!this.application.historyManager.diskEnabled) {
|
||||||
this.alertManager.confirm({
|
this.application.alertManager.confirm({
|
||||||
text: `Are you sure you want to save history to disk? This will decrease general
|
text: `Are you sure you want to save history to disk? This will decrease general
|
||||||
performance, especially as you type. You are advised to disable this feature
|
performance, especially as you type. You are advised to disable this feature
|
||||||
if you experience any lagging.`,
|
if you experience any lagging.`,
|
||||||
@@ -96,9 +94,9 @@ class SessionHistoryMenuCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
toggleAutoOptimize() {
|
toggleAutoOptimize() {
|
||||||
this.sessionHistory.toggleAutoOptimize().then(() => {
|
this.application.historyManager.toggleAutoOptimize().then(() => {
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.autoOptimize = this.sessionHistory.autoOptimize;
|
this.autoOptimize = this.application.historyManager.autoOptimize;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ class SyncResolutionMenuCtrl {
|
|||||||
constructor(
|
constructor(
|
||||||
$timeout,
|
$timeout,
|
||||||
archiveManager,
|
archiveManager,
|
||||||
syncManager,
|
application
|
||||||
) {
|
) {
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.archiveManager = archiveManager;
|
this.archiveManager = archiveManager;
|
||||||
this.syncManager = syncManager;
|
this.application = application;
|
||||||
this.status = {};
|
this.status = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,11 +24,11 @@ class SyncResolutionMenuCtrl {
|
|||||||
|
|
||||||
async performSyncResolution() {
|
async performSyncResolution() {
|
||||||
this.status.resolving = true;
|
this.status.resolving = true;
|
||||||
await this.syncManager.resolveOutOfSync();
|
await this.application.resolveOutOfSync();
|
||||||
this.$timeout(() => {
|
this.$timeout(() => {
|
||||||
this.status.resolving = false;
|
this.status.resolving = false;
|
||||||
this.status.attemptedResolution = true;
|
this.status.attemptedResolution = true;
|
||||||
if (this.syncManager.isOutOfSync()) {
|
if (this.application.getSyncStatus().isOutOfSync()) {
|
||||||
this.status.fail = true;
|
this.status.fail = true;
|
||||||
} else {
|
} else {
|
||||||
this.status.success = true;
|
this.status.success = true;
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { SFItemHistoryEntry } from 'snjs';
|
|
||||||
|
|
||||||
export class NoteHistoryEntry extends SFItemHistoryEntry {
|
|
||||||
|
|
||||||
previewTitle() {
|
|
||||||
return this.item.updated_at.toLocaleString();
|
|
||||||
}
|
|
||||||
|
|
||||||
previewSubTitle() {
|
|
||||||
if(!this.hasPreviousEntry) {
|
|
||||||
return `${this.textCharDiffLength} characters loaded`;
|
|
||||||
} else if(this.textCharDiffLength < 0) {
|
|
||||||
return `${this.textCharDiffLength * -1} characters removed`;
|
|
||||||
} else if(this.textCharDiffLength > 0) {
|
|
||||||
return `${this.textCharDiffLength} characters added`;
|
|
||||||
} else {
|
|
||||||
return "Title or metadata changed";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import angular from 'angular';
|
|
||||||
import { Action, SFModelManager, SFItemParams, protocolManager } from 'snjs';
|
|
||||||
|
|
||||||
export class ActionsManager {
|
|
||||||
|
|
||||||
/* @ngInject */
|
|
||||||
constructor(
|
|
||||||
$compile,
|
|
||||||
$rootScope,
|
|
||||||
$timeout,
|
|
||||||
alertManager,
|
|
||||||
authManager,
|
|
||||||
httpManager,
|
|
||||||
modelManager,
|
|
||||||
syncManager,
|
|
||||||
) {
|
|
||||||
this.$compile = $compile;
|
|
||||||
this.$rootScope = $rootScope;
|
|
||||||
this.$timeout = $timeout;
|
|
||||||
this.alertManager = alertManager;
|
|
||||||
this.authManager = authManager;
|
|
||||||
this.httpManager = httpManager;
|
|
||||||
this.modelManager = modelManager;
|
|
||||||
this.syncManager = syncManager;
|
|
||||||
/* Used when decrypting old items with new keys. This array is only kept in memory. */
|
|
||||||
this.previousPasswords = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
get extensions() {
|
|
||||||
return this.modelManager.validItemsForContentType('Extension');
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionsInContextOfItem(item) {
|
|
||||||
return this.extensions.filter((ext) => {
|
|
||||||
return _.includes(ext.supported_types, item.content_type) ||
|
|
||||||
ext.actionsWithContextForItem(item).length > 0;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads an extension in the context of a certain item.
|
|
||||||
* The server then has the chance to respond with actions that are
|
|
||||||
* relevant just to this item. The response extension is not saved,
|
|
||||||
* just displayed as a one-time thing.
|
|
||||||
*/
|
|
||||||
async loadExtensionInContextOfItem(extension, item) {
|
|
||||||
const params = {
|
|
||||||
content_type: item.content_type,
|
|
||||||
item_uuid: item.uuid
|
|
||||||
};
|
|
||||||
const emptyFunc = () => { };
|
|
||||||
return this.httpManager.getAbsolute(
|
|
||||||
extension.url,
|
|
||||||
params,
|
|
||||||
emptyFunc,
|
|
||||||
emptyFunc
|
|
||||||
).then((response) => {
|
|
||||||
this.updateExtensionFromRemoteResponse(extension, response);
|
|
||||||
return extension;
|
|
||||||
}).catch((response) => {
|
|
||||||
console.error("Error loading extension", response);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
updateExtensionFromRemoteResponse(extension, response) {
|
|
||||||
if (response.description) {
|
|
||||||
extension.description = response.description;
|
|
||||||
}
|
|
||||||
if (response.supported_types) {
|
|
||||||
extension.supported_types = response.supported_types;
|
|
||||||
}
|
|
||||||
if (response.actions) {
|
|
||||||
extension.actions = response.actions.map((action) => {
|
|
||||||
return new Action(action);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
extension.actions = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async executeAction(action, extension, item) {
|
|
||||||
action.running = true;
|
|
||||||
let result;
|
|
||||||
switch (action.verb) {
|
|
||||||
case 'get':
|
|
||||||
result = await this.handleGetAction(action);
|
|
||||||
break;
|
|
||||||
case 'render':
|
|
||||||
result = await this.handleRenderAction(action);
|
|
||||||
break;
|
|
||||||
case 'show':
|
|
||||||
result = await this.handleShowAction(action);
|
|
||||||
break;
|
|
||||||
case 'post':
|
|
||||||
result = await this.handlePostAction(action, item, extension);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
action.lastExecuted = new Date();
|
|
||||||
action.running = false;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async decryptResponse(response, keys) {
|
|
||||||
const responseItem = response.item;
|
|
||||||
await protocolManager.decryptItem(responseItem, keys);
|
|
||||||
if (!responseItem.errorDecrypting) {
|
|
||||||
return {
|
|
||||||
response: response,
|
|
||||||
item: responseItem
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.auth_params) {
|
|
||||||
/**
|
|
||||||
* In some cases revisions were missing auth params.
|
|
||||||
* Instruct the user to email us to get this remedied.
|
|
||||||
*/
|
|
||||||
this.alertManager.alert({
|
|
||||||
text: `We were unable to decrypt this revision using your current keys,
|
|
||||||
and this revision is missing metadata that would allow us to try different
|
|
||||||
keys to decrypt it. This can likely be fixed with some manual intervention.
|
|
||||||
Please email hello@standardnotes.org for assistance.`
|
|
||||||
});
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try previous passwords */
|
|
||||||
const triedPasswords = [];
|
|
||||||
for (const passwordCandidate of this.previousPasswords) {
|
|
||||||
if (triedPasswords.includes(passwordCandidate)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
triedPasswords.push(passwordCandidate);
|
|
||||||
const keyResults = await protocolManager.computeEncryptionKeysForUser(
|
|
||||||
passwordCandidate,
|
|
||||||
response.auth_params
|
|
||||||
);
|
|
||||||
if (!keyResults) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const nestedResponse = await this.decryptResponse(
|
|
||||||
response,
|
|
||||||
keyResults
|
|
||||||
);
|
|
||||||
if (nestedResponse.item) {
|
|
||||||
return nestedResponse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.presentPasswordModal((password) => {
|
|
||||||
this.previousPasswords.push(password);
|
|
||||||
const result = this.decryptResponse(response, keys);
|
|
||||||
resolve(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async handlePostAction(action, item, extension) {
|
|
||||||
const decrypted = action.access_type === 'decrypted';
|
|
||||||
const itemParams = await this.outgoingParamsForItem(item, extension, decrypted);
|
|
||||||
const params = {
|
|
||||||
items: [itemParams]
|
|
||||||
};
|
|
||||||
/* Needed until SNJS detects null function */
|
|
||||||
const emptyFunc = () => { };
|
|
||||||
return this.httpManager.postAbsolute(
|
|
||||||
action.url,
|
|
||||||
params,
|
|
||||||
emptyFunc,
|
|
||||||
emptyFunc
|
|
||||||
).then((response) => {
|
|
||||||
action.error = false;
|
|
||||||
return {response: response};
|
|
||||||
}).catch((response) => {
|
|
||||||
action.error = true;
|
|
||||||
console.error("Action error response:", response);
|
|
||||||
this.alertManager.alert({
|
|
||||||
text: "An issue occurred while processing this action. Please try again."
|
|
||||||
});
|
|
||||||
return { response: response };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleShowAction(action) {
|
|
||||||
const win = window.open(action.url, '_blank');
|
|
||||||
if (win) {
|
|
||||||
win.focus();
|
|
||||||
}
|
|
||||||
return { response: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleGetAction(action) {
|
|
||||||
/* Needed until SNJS detects null function */
|
|
||||||
const emptyFunc = () => {};
|
|
||||||
const onConfirm = async () => {
|
|
||||||
return this.httpManager.getAbsolute(action.url, {}, emptyFunc, emptyFunc)
|
|
||||||
.then(async (response) => {
|
|
||||||
action.error = false;
|
|
||||||
await this.decryptResponse(response, await this.authManager.keys());
|
|
||||||
const items = await this.modelManager.mapResponseItemsToLocalModels(
|
|
||||||
[response.item],
|
|
||||||
SFModelManager.MappingSourceRemoteActionRetrieved
|
|
||||||
);
|
|
||||||
for (const mappedItem of items) {
|
|
||||||
this.modelManager.setItemDirty(mappedItem, true);
|
|
||||||
}
|
|
||||||
this.syncManager.sync();
|
|
||||||
return {
|
|
||||||
response: response,
|
|
||||||
item: response.item
|
|
||||||
};
|
|
||||||
}).catch((response) => {
|
|
||||||
const error = (response && response.error)
|
|
||||||
|| { message: "An issue occurred while processing this action. Please try again." };
|
|
||||||
this.alertManager.alert({ text: error.message });
|
|
||||||
action.error = true;
|
|
||||||
return { error: error };
|
|
||||||
});
|
|
||||||
};
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.alertManager.confirm({
|
|
||||||
text: "Are you sure you want to replace the current note contents with this action's results?",
|
|
||||||
onConfirm: () => {
|
|
||||||
onConfirm().then(resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleRenderAction(action) {
|
|
||||||
/* Needed until SNJS detects null function */
|
|
||||||
const emptyFunc = () => {};
|
|
||||||
return this.httpManager.getAbsolute(
|
|
||||||
action.url,
|
|
||||||
{},
|
|
||||||
emptyFunc,
|
|
||||||
emptyFunc
|
|
||||||
).then(async (response) => {
|
|
||||||
action.error = false;
|
|
||||||
const result = await this.decryptResponse(response, await this.authManager.keys());
|
|
||||||
const item = this.modelManager.createItem(result.item);
|
|
||||||
return {
|
|
||||||
response: result.response,
|
|
||||||
item: item
|
|
||||||
};
|
|
||||||
}).catch((response) => {
|
|
||||||
const error = (response && response.error)
|
|
||||||
|| { message: "An issue occurred while processing this action. Please try again." };
|
|
||||||
this.alertManager.alert({ text: error.message });
|
|
||||||
action.error = true;
|
|
||||||
return { error: error };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async outgoingParamsForItem(item, extension, decrypted = false) {
|
|
||||||
let keys = await this.authManager.keys();
|
|
||||||
if (decrypted) {
|
|
||||||
keys = null;
|
|
||||||
}
|
|
||||||
const itemParams = new SFItemParams(
|
|
||||||
item,
|
|
||||||
keys,
|
|
||||||
await this.authManager.getAuthParams()
|
|
||||||
);
|
|
||||||
return itemParams.paramsForExtension();
|
|
||||||
}
|
|
||||||
|
|
||||||
presentRevisionPreviewModal(uuid, content) {
|
|
||||||
const scope = this.$rootScope.$new(true);
|
|
||||||
scope.uuid = uuid;
|
|
||||||
scope.content = content;
|
|
||||||
const el = this.$compile(
|
|
||||||
`<revision-preview-modal uuid='uuid' content='content'
|
|
||||||
class='sk-modal'></revision-preview-modal>`
|
|
||||||
)(scope);
|
|
||||||
angular.element(document.body).append(el);
|
|
||||||
}
|
|
||||||
|
|
||||||
presentPasswordModal(callback) {
|
|
||||||
const scope = this.$rootScope.$new(true);
|
|
||||||
scope.type = "password";
|
|
||||||
scope.title = "Decryption Assistance";
|
|
||||||
scope.message = `Unable to decrypt this item with your current keys.
|
|
||||||
Please enter your account password at the time of this revision.`;
|
|
||||||
scope.callback = callback;
|
|
||||||
const el = this.$compile(
|
|
||||||
`<input-modal type='type' message='message'
|
|
||||||
title='title' callback='callback'></input-modal>`
|
|
||||||
)(scope);
|
|
||||||
angular.element(document.body).append(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,10 +5,12 @@ export class GodService {
|
|||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor(
|
constructor(
|
||||||
$rootScope,
|
$rootScope,
|
||||||
$compile
|
$compile,
|
||||||
|
application
|
||||||
) {
|
) {
|
||||||
this.$rootScope = $rootScope;
|
this.$rootScope = $rootScope;
|
||||||
this.$compile = $compile;
|
this.$compile = $compile;
|
||||||
|
this.application = application;
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkForSecurityUpdate() {
|
async checkForSecurityUpdate() {
|
||||||
@@ -16,7 +18,7 @@ export class GodService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const latest = protocolManager.version();
|
const latest = await this.application.getUserVersion();
|
||||||
const updateAvailable = await this.protocolVersion() !== latest;
|
const updateAvailable = await this.protocolVersion() !== latest;
|
||||||
if (updateAvailable !== this.securityUpdateAvailable) {
|
if (updateAvailable !== this.securityUpdateAvailable) {
|
||||||
this.securityUpdateAvailable = updateAvailable;
|
this.securityUpdateAvailable = updateAvailable;
|
||||||
@@ -70,4 +72,29 @@ export class GodService {
|
|||||||
authenticationInProgress() {
|
authenticationInProgress() {
|
||||||
return this.currentAuthenticationElement != null;
|
return this.currentAuthenticationElement != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
presentPasswordModal(callback) {
|
||||||
|
const scope = this.$rootScope.$new(true);
|
||||||
|
scope.type = "password";
|
||||||
|
scope.title = "Decryption Assistance";
|
||||||
|
scope.message = `Unable to decrypt this item with your current keys.
|
||||||
|
Please enter your account password at the time of this revision.`;
|
||||||
|
scope.callback = callback;
|
||||||
|
const el = this.$compile(
|
||||||
|
`<input-modal type='type' message='message'
|
||||||
|
title='title' callback='callback'></input-modal>`
|
||||||
|
)(scope);
|
||||||
|
angular.element(document.body).append(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
presentRevisionPreviewModal(uuid, content) {
|
||||||
|
const scope = this.$rootScope.$new(true);
|
||||||
|
scope.uuid = uuid;
|
||||||
|
scope.content = content;
|
||||||
|
const el = this.$compile(
|
||||||
|
`<revision-preview-modal uuid='uuid' content='content'
|
||||||
|
class='sk-modal'></revision-preview-modal>`
|
||||||
|
)(scope);
|
||||||
|
angular.element(document.body).append(el);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ export class WebDeviceInterface extends DeviceInterface {
|
|||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openUrl(url) {
|
||||||
|
const win = window.open(url, '_blank');
|
||||||
|
if (win) {
|
||||||
|
win.focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** @database */
|
/** @database */
|
||||||
|
|
||||||
|
|||||||
4995
dist/javascripts/app.js
vendored
4995
dist/javascripts/app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/javascripts/app.js.map
vendored
2
dist/javascripts/app.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user