diff --git a/platform/entanglement/bundle.json b/platform/entanglement/bundle.json index 714d9f7f79..fc17ef9ef2 100644 --- a/platform/entanglement/bundle.json +++ b/platform/entanglement/bundle.json @@ -11,7 +11,7 @@ "glyph": "f", "category": "contextual", "implementation": "actions/MoveAction.js", - "depends": ["locationService", "moveService"] + "depends": ["policyService", "locationService", "moveService"] }, { "key": "copy", @@ -20,7 +20,7 @@ "glyph": "+", "category": "contextual", "implementation": "actions/CopyAction.js", - "depends": ["$log", "locationService", "copyService", + "depends": ["$log", "policyService", "locationService", "copyService", "dialogService", "notificationService"] }, { @@ -30,7 +30,7 @@ "glyph": "\u00E8", "category": "contextual", "implementation": "actions/LinkAction.js", - "depends": ["locationService", "linkService"] + "depends": ["policyService", "locationService", "linkService"] }, { "key": "follow", @@ -54,7 +54,11 @@ "depends": ["contextualize", "$q", "$log"] } ], - "controllers": [ + "policies": [ + { + "category": "action", + "implementation": "policies/CrossSpacePolicy.js" + } ], "capabilities": [ { diff --git a/platform/entanglement/src/actions/AbstractComposeAction.js b/platform/entanglement/src/actions/AbstractComposeAction.js index f68391adc9..a9fbbf282c 100644 --- a/platform/entanglement/src/actions/AbstractComposeAction.js +++ b/platform/entanglement/src/actions/AbstractComposeAction.js @@ -71,7 +71,14 @@ define( * @param {string} [suffix] a string to display in the dialog title; * default is "to a new location" */ - function AbstractComposeAction(locationService, composeService, context, verb, suffix) { + function AbstractComposeAction( + policyService, + locationService, + composeService, + context, + verb, + suffix + ) { if (context.selectedObject) { this.newParent = context.domainObject; this.object = context.selectedObject; @@ -83,16 +90,27 @@ define( .getCapability('context') .getParent(); + this.context = context; + this.policyService = policyService; this.locationService = locationService; this.composeService = composeService; this.verb = verb || "Compose"; this.suffix = suffix || "to a new location"; } + AbstractComposeAction.prototype.cloneContext = function () { + var clone = {}, original = this.context; + Object.keys(original).forEach(function (k) { + clone[k] = original[k]; + }); + return clone; + }; + AbstractComposeAction.prototype.perform = function () { var dialogTitle, label, validateLocation, + self = this, locationService = this.locationService, composeService = this.composeService, currentParent = this.currentParent, @@ -109,7 +127,11 @@ define( label = this.verb + " To"; validateLocation = function (newParent) { - return composeService.validate(object, newParent); + var newContext = self.cloneContext(); + newContext.selectedObject = object; + newContext.domainObject = newParent; + return composeService.validate(object, newParent) && + self.policyService.allow("action", self, newContext); }; return locationService.getLocationFromUser( diff --git a/platform/entanglement/src/actions/CopyAction.js b/platform/entanglement/src/actions/CopyAction.js index cdcefeb935..876d46d5a8 100644 --- a/platform/entanglement/src/actions/CopyAction.js +++ b/platform/entanglement/src/actions/CopyAction.js @@ -34,16 +34,30 @@ define( * @constructor * @memberof platform/entanglement */ - function CopyAction($log, locationService, copyService, dialogService, - notificationService, context) { + function CopyAction( + $log, + policyService, + locationService, + copyService, + dialogService, + notificationService, + context + ) { this.dialog = undefined; this.notification = undefined; this.dialogService = dialogService; this.notificationService = notificationService; this.$log = $log; //Extend the behaviour of the Abstract Compose Action - AbstractComposeAction.call(this, locationService, copyService, - context, "Duplicate", "to a location"); + AbstractComposeAction.call( + this, + policyService, + locationService, + copyService, + context, + "Duplicate", + "to a location" + ); } /** @@ -87,8 +101,8 @@ define( }; /** - * Executes the CopyAction. The CopyAction uses the default behaviour of - * the AbstractComposeAction, but extends it to support notification + * Executes the CopyAction. The CopyAction uses the default behaviour of + * the AbstractComposeAction, but extends it to support notification * updates of progress on copy. */ CopyAction.prototype.perform = function() { diff --git a/platform/entanglement/src/actions/LinkAction.js b/platform/entanglement/src/actions/LinkAction.js index c791310886..2edc8fd9ef 100644 --- a/platform/entanglement/src/actions/LinkAction.js +++ b/platform/entanglement/src/actions/LinkAction.js @@ -34,8 +34,9 @@ define( * @constructor * @memberof platform/entanglement */ - function LinkAction(locationService, linkService, context) { + function LinkAction(policyService, locationService, linkService, context) { return new AbstractComposeAction( + policyService, locationService, linkService, context, diff --git a/platform/entanglement/src/actions/MoveAction.js b/platform/entanglement/src/actions/MoveAction.js index 4fdd4b59df..e377ac8081 100644 --- a/platform/entanglement/src/actions/MoveAction.js +++ b/platform/entanglement/src/actions/MoveAction.js @@ -34,8 +34,9 @@ define( * @constructor * @memberof platform/entanglement */ - function MoveAction(locationService, moveService, context) { + function MoveAction(policyService, locationService, moveService, context) { return new AbstractComposeAction( + policyService, locationService, moveService, context, diff --git a/platform/entanglement/src/policies/CrossSpacePolicy.js b/platform/entanglement/src/policies/CrossSpacePolicy.js new file mode 100644 index 0000000000..ad18f36840 --- /dev/null +++ b/platform/entanglement/src/policies/CrossSpacePolicy.js @@ -0,0 +1,65 @@ +/***************************************************************************** + * Open MCT Web, Copyright (c) 2014-2015, United States Government + * as represented by the Administrator of the National Aeronautics and Space + * Administration. All rights reserved. + * + * Open MCT Web is licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * Open MCT Web includes source code licensed under additional open source + * licenses. See the Open Source Licenses file (LICENSES.md) included with + * this source code distribution or the Licensing information page available + * at runtime from the About dialog for additional information. + *****************************************************************************/ + +/*global define */ +define( + [], + function () { + 'use strict'; + + var DISALLOWED_ACTIONS = [ + "move", + "copy", + "link", + "compose" + ]; + + function CrossSpacePolicy() { + } + + function lookupSpace(domainObject) { + var persistence = domainObject && + domainObject.getCapability("persistence"); + return persistence && persistence.getSpace(); + } + + function isCrossSpace(context) { + var domainObject = context.domainObject, + selectedObject = context.selectedObject, + spaces = [ domainObject, selectedObject ].map(lookupSpace); + return spaces[0] === spaces[1]; + } + + CrossSpacePolicy.prototype.allow = function (action, context) { + var key = action.getMetadata().key; + + if (DISALLOWED_ACTIONS.indexOf(key) !== -1) { + return !isCrossSpace(context); + } + + return true; + }; + + return CrossSpacePolicy; + + } +);