From a9cfbc53e09364857be1675e66890109ecd5e3ef Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Mon, 29 Apr 2019 18:48:52 -0500 Subject: [PATCH] ComponentManager permissions logic, Batch Manager content type expansion, Stylekit 2.0.14, SFJS 0.3.58 --- .../app/services/componentManager.js | 115 +++++++++++------- .../app/services/nativeExtManager.js | 7 +- app/assets/stylesheets/app/_notes.scss | 2 +- package-lock.json | 12 +- package.json | 4 +- public/extensions/batch-manager | 2 +- 6 files changed, 85 insertions(+), 57 deletions(-) diff --git a/app/assets/javascripts/app/services/componentManager.js b/app/assets/javascripts/app/services/componentManager.js index d4761bb6c..f2d753b46 100644 --- a/app/assets/javascripts/app/services/componentManager.js +++ b/app/assets/javascripts/app/services/componentManager.js @@ -505,16 +505,24 @@ class ComponentManager { }.bind(this)) } - isItemWithinComponentContextJurisdiction(item, component) { + isItemIdWithinComponentContextJurisdiction(uuid, component) { + let itemIdsInJurisdiction = this.itemIdsInContextJurisdictionForComponent(component); + return itemIdsInJurisdiction.includes(uuid); + } + + /* Returns items that given component has context permissions for */ + itemIdsInContextJurisdictionForComponent(component) { + let itemIds = []; for(let handler of this.handlersForArea(component.area)) { if(handler.contextRequestHandler) { var itemInContext = handler.contextRequestHandler(component); - if(itemInContext && itemInContext.uuid == item.uuid) { - return true; + if(itemInContext) { + itemIds.push(itemInContext.uuid); } } } - return false; + + return itemIds; } handlersForArea(area) { @@ -522,24 +530,32 @@ class ComponentManager { } handleSaveItemsMessage(component, message) { - var responseItems = message.data.items; - var requiredPermissions; + let responseItems = message.data.items; + let requiredPermissions = []; - // Check if you're just trying to save the context item, which requires only stream-context-item permissions - if(responseItems.length == 1 && this.isItemWithinComponentContextJurisdiction(responseItems[0], component)) { - requiredPermissions = [ - { + let itemIdsInContextJurisdiction = this.itemIdsInContextJurisdictionForComponent(component); + + // Pending as in needed to be accounted for in permissions. + let pendingResponseItems = responseItems.slice(); + + for(let responseItem of responseItems.slice()) { + if(itemIdsInContextJurisdiction.includes(responseItem.uuid)) { + requiredPermissions.push({ name: "stream-context-item" - } - ]; - } else { - var requiredContentTypes = _.uniq(responseItems.map((i) => {return i.content_type})).sort(); - requiredPermissions = [ - { - name: "stream-items", - content_types: requiredContentTypes - } - ]; + }); + _.pull(pendingResponseItems, responseItem); + // We break because there can only be one context item + break; + } + } + + // Check to see if additional privileges are required + if(pendingResponseItems.length > 0) { + var requiredContentTypes = _.uniq(pendingResponseItems.map((i) => {return i.content_type})).sort(); + requiredPermissions.push({ + name: "stream-items", + content_types: requiredContentTypes + }); } this.runWithPermissions(component, requiredPermissions, () => { @@ -751,41 +767,44 @@ class ComponentManager { } runWithPermissions(component, requiredPermissions, runFunction) { - if(!component.permissions) { component.permissions = []; } + // Make copy as not to mutate input values + requiredPermissions = JSON.parse(JSON.stringify(requiredPermissions)); + var acquiredPermissions = component.permissions; - var acquiredMatchesRequired = true; - for(var required of requiredPermissions) { - var matching = acquiredPermissions.find((candidate) => { - var matchesContentTypes = true; - if(candidate.content_types && required.content_types) { - matchesContentTypes = JSON.stringify(candidate.content_types.sort()) == JSON.stringify(required.content_types.sort()); - } - return candidate.name == required.name && matchesContentTypes; - }); + for(let required of requiredPermissions.slice()) { + // Remove anything we already have + let respectiveAcquired = acquiredPermissions.find((candidate) => candidate.name == required.name); + if(!respectiveAcquired) { + continue; + } - if(!matching) { - /* Required permissions can be 1 content type, and requestedPermisisons may send an array of content types. - In the case of an array, we can just check to make sure that requiredPermissions content type is found in the array - */ - matching = acquiredPermissions.find((candidate) => { - return Array.isArray(candidate.content_types) - && Array.isArray(required.content_types) - && candidate.content_types.containsPrimitiveSubset(required.content_types); - }); + // We now match on name, lets substract from required.content_types anything we have in acquired. + let requiredContentTypes = required.content_types; - if(!matching) { - acquiredMatchesRequired = false; - break; - } + if(!requiredContentTypes) { + // If this permission does not require any content types (i.e stream-context-item) + // then we can remove this from required since we match by name (respectiveAcquired.name == required.name) + _.pull(requiredPermissions, required); + continue; + } + + for(let acquiredContentType of respectiveAcquired.content_types) { + // console.log("Removing content_type", acquiredContentType, "from", requiredContentTypes); + _.pull(requiredContentTypes, acquiredContentType); + } + + if(requiredContentTypes.length == 0) { + // We've removed all acquired and end up with zero, means we already have all these permissions + _.pull(requiredPermissions, required); } } - if(!acquiredMatchesRequired) { + if(requiredPermissions.length > 0) { this.promptForPermissions(component, requiredPermissions, function(approved){ if(approved) { runFunction(); @@ -804,9 +823,13 @@ class ComponentManager { scope.callback = function(approved) { if(approved) { - for(var permission of permissions) { - if(!component.permissions.includes(permission)) { + for(let permission of permissions) { + let matchingPermission = component.permissions.find((candidate) => candidate.name == permission.name); + if(!matchingPermission) { component.permissions.push(permission); + } else { + // Permission already exists, but content_types may have been expanded + matchingPermission.content_types = _.uniq(matchingPermission.content_types.concat(permission.content_types)); } } component.setDirty(true); diff --git a/app/assets/javascripts/app/services/nativeExtManager.js b/app/assets/javascripts/app/services/nativeExtManager.js index c44561488..105c3a588 100644 --- a/app/assets/javascripts/app/services/nativeExtManager.js +++ b/app/assets/javascripts/app/services/nativeExtManager.js @@ -141,7 +141,12 @@ class NativeExtManager { permissions: [ { name: "stream-items", - content_types: ["Note", "Tag", "SN|Component", "SN|Theme", "SF|Extension", "Extension", "SF|MFA", "SN|Editor", "SN|UserPreferences"] + content_types: [ + "Note", "Tag", "SN|SmartTag", + "SN|Component", "SN|Theme", "SN|UserPreferences", + "SF|Extension", "Extension", "SF|MFA", "SN|Editor", + "SN|FileSafe|Credentials", "SN|FileSafe|FileMetadata", "SN|FileSafe|Integration" + ] } ] } diff --git a/app/assets/stylesheets/app/_notes.scss b/app/assets/stylesheets/app/_notes.scss index fc0ab7779..d0b7975ee 100644 --- a/app/assets/stylesheets/app/_notes.scss +++ b/app/assets/stylesheets/app/_notes.scss @@ -20,7 +20,7 @@ #notes-title-bar { padding-top: 16px; font-weight: normal; - font-size: 18px; + font-size: var(--sn-stylekit-font-size-h1); .section-title-bar-header .title { color: var(--sn-stylekit-neutral-color); diff --git a/package-lock.json b/package-lock.json index 829236fcf..77e22eab8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4756,9 +4756,9 @@ "dev": true }, "sn-stylekit": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/sn-stylekit/-/sn-stylekit-2.0.13.tgz", - "integrity": "sha512-rGDc2cc0/r84lQn/HJOw6GvJz5VonSK2UVdLTS9TFo+wwbAtRnww8aj7VILgNneUAnqwdCKdY5O/Fk3rN0Hw7g==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/sn-stylekit/-/sn-stylekit-2.0.14.tgz", + "integrity": "sha512-48RqEhxLbvDrEmY+SgiQg8IbeAlf0bjtHk/RAhMNwGc9ZrUgBoxMyxJJgUZeKiyx+dm8POfaxpsgzHBG9Qix+A==", "dev": true }, "snake-case": { @@ -4830,9 +4830,9 @@ "dev": true }, "standard-file-js": { - "version": "0.3.57", - "resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.57.tgz", - "integrity": "sha512-DJA3KKHTTKXnMzl7xer0mu5aPhAv/XUftIJokq+G/BNx1EHG30mwC3YTDJhAOjfSDXR+M4geB0A7gj80LA1Veg==", + "version": "0.3.58", + "resolved": "https://registry.npmjs.org/standard-file-js/-/standard-file-js-0.3.58.tgz", + "integrity": "sha512-xkoC+lDK12WPL2+ckD2Ki8WfTsy8TphvwqLS9OASuY06MHdVh9qGGooYvewjXSQkSQTBDrs7f+0mzEX0Rn2AZw==", "dev": true }, "statuses": { diff --git a/package.json b/package.json index a8181a478..a20b139b3 100644 --- a/package.json +++ b/package.json @@ -37,8 +37,8 @@ "mocha": "^5.2.0", "serve-static": "^1.13.2", "sn-models": "0.1.14", - "sn-stylekit": "2.0.13", - "standard-file-js": "0.3.57", + "sn-stylekit": "2.0.14", + "standard-file-js": "0.3.58", "grunt-shell": "^2.1.0" } } diff --git a/public/extensions/batch-manager b/public/extensions/batch-manager index db7b790e3..3897593b9 160000 --- a/public/extensions/batch-manager +++ b/public/extensions/batch-manager @@ -1 +1 @@ -Subproject commit db7b790e3302f4c3ca37cd9502d842e4ae936500 +Subproject commit 3897593b98fe46505a8bf8a8e22fd64319dc5900