diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 035e48f2b8..d1b1d0db86 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -122,7 +122,7 @@ "regenerator-runtime": "^0.13.5", "rison": "^0.1.1", "shortid": "^2.2.6", - "urijs": "^1.19.4", + "urijs": "^1.19.6", "use-immer": "^0.4.2", "use-query-params": "^1.1.9" }, @@ -54461,9 +54461,9 @@ } }, "node_modules/urijs": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.4.tgz", - "integrity": "sha512-2YF/wdFu02Gsly/wyx+S/f5w/oCF0ihVSgK/Sn8fcY/ZYMYtqxgi03Vi3V7HqyQP8mj8xHMuNFTBIPufmPRdoA==" + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.6.tgz", + "integrity": "sha512-eSXsXZ2jLvGWeLYlQA3Gh36BcjF+0amo92+wHPyN1mdR8Nxf75fuEuYTd9c0a+m/vhCjRK0ESlE9YNLW+E1VEw==" }, "node_modules/urix": { "version": "0.1.0", @@ -78681,6 +78681,12 @@ "requires": { "glob": "^7.1.3" } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true } } }, @@ -78844,7 +78850,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -82030,7 +82036,7 @@ "dependencies": { "domelementtype": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", + "resolved": "http://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" } } @@ -92097,7 +92103,7 @@ }, "json5": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" }, "jsonfile": { @@ -94586,7 +94592,7 @@ }, "pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, @@ -100253,7 +100259,7 @@ }, "regexpu-core": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", + "resolved": "http://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", "dev": true, "requires": { @@ -100264,13 +100270,13 @@ }, "regjsgen": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "resolved": "http://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", "dev": true }, "regjsparser": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "resolved": "http://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", "dev": true, "requires": { @@ -106039,6 +106045,12 @@ "strip-ansi": "^5.0.0" } }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, "yargs": { "version": "13.2.4", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", @@ -107142,9 +107154,9 @@ "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yallist": { diff --git a/superset-frontend/src/dashboard/actions/hydrate.js b/superset-frontend/src/dashboard/actions/hydrate.js index 8065bf625f..7b87d5c510 100644 --- a/superset-frontend/src/dashboard/actions/hydrate.js +++ b/superset-frontend/src/dashboard/actions/hydrate.js @@ -28,7 +28,7 @@ import { getInitialState as getInitialNativeFilterState } from 'src/dashboard/re import { getParam } from 'src/modules/utils'; import { applyDefaultFormData } from 'src/explore/store'; import { buildActiveFilters } from 'src/dashboard/util/activeDashboardFilters'; -import getPermissions from 'src/dashboard/util/getPermissions'; +import findPermission from 'src/dashboard/util/findPermission'; import { DASHBOARD_FILTER_SCOPE_GLOBAL, dashboardFilter, @@ -311,21 +311,21 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => ( dashboardInfo: { ...dashboardData, userId: String(user.userId), // legacy, please use state.user instead - dash_edit_perm: getPermissions('can_write', 'Dashboard', roles), - dash_save_perm: getPermissions('can_save_dash', 'Superset', roles), - dash_share_perm: getPermissions( + dash_edit_perm: findPermission('can_write', 'Dashboard', roles), + dash_save_perm: findPermission('can_save_dash', 'Superset', roles), + dash_share_perm: findPermission( 'can_share_dashboard', 'Superset', roles, ), - superset_can_explore: getPermissions('can_explore', 'Superset', roles), - superset_can_share: getPermissions( + superset_can_explore: findPermission('can_explore', 'Superset', roles), + superset_can_share: findPermission( 'can_share_chart', 'Superset', roles, ), - superset_can_csv: getPermissions('can_csv', 'Superset', roles), - slice_can_edit: getPermissions('can_slice', 'Superset', roles), + superset_can_csv: findPermission('can_csv', 'Superset', roles), + slice_can_edit: findPermission('can_slice', 'Superset', roles), common: { // legacy, please use state.common instead flash_messages: common.flash_messages, @@ -347,7 +347,7 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => ( css: dashboardData.css || '', colorNamespace: metadata?.color_namespace || null, colorScheme: metadata?.color_scheme || null, - editMode: getPermissions('can_write', 'Dashboard', roles) && editMode, + editMode: findPermission('can_write', 'Dashboard', roles) && editMode, isPublished: dashboardData.published, hasUnsavedChanges: false, maxUndoHistoryExceeded: false, diff --git a/superset-frontend/src/dashboard/util/findPermission.test.ts b/superset-frontend/src/dashboard/util/findPermission.test.ts new file mode 100644 index 0000000000..0dda552c2a --- /dev/null +++ b/superset-frontend/src/dashboard/util/findPermission.test.ts @@ -0,0 +1,59 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +import findPermission from './findPermission'; + +test('findPermission for single role', () => { + expect(findPermission('abc', 'def', { role: [['abc', 'def']] })).toEqual( + true, + ); + + expect(findPermission('abc', 'def', { role: [['abc', 'de']] })).toEqual( + false, + ); + + expect(findPermission('abc', 'def', { role: [] })).toEqual(false); +}); + +test('findPermission for multiple roles', () => { + expect( + findPermission('abc', 'def', { + role1: [ + ['ccc', 'aaa'], + ['abc', 'def'], + ], + role2: [['abc', 'def']], + }), + ).toEqual(true); + + expect( + findPermission('abc', 'def', { + role1: [['abc', 'def']], + role2: [['abc', 'dd']], + }), + ).toEqual(true); + + expect( + findPermission('abc', 'def', { + role1: [['ccc', 'aaa']], + role2: [['aaa', 'ddd']], + }), + ).toEqual(false); + + expect(findPermission('abc', 'def', { role1: [], role2: [] })).toEqual(false); +}); diff --git a/superset-frontend/src/dashboard/util/getPermissions.ts b/superset-frontend/src/dashboard/util/findPermission.ts similarity index 63% rename from superset-frontend/src/dashboard/util/getPermissions.ts rename to superset-frontend/src/dashboard/util/findPermission.ts index 0208fd68fd..613d1899f3 100644 --- a/superset-frontend/src/dashboard/util/getPermissions.ts +++ b/superset-frontend/src/dashboard/util/findPermission.ts @@ -18,22 +18,13 @@ */ import memoizeOne from 'memoize-one'; -const findPermissions = (perm: string, view: string, roles: object) => { - const roleList = Object.entries(roles); - if (roleList.length === 0) return false; - let bool; +type UserRoles = Record; - roleList.forEach(([role, permissions]) => { - bool = Boolean( - permissions.find( - (permission: Array) => - permission[0] === perm && permission[1] === view, - ), - ); - }); - return bool; -}; +const findPermission = memoizeOne( + (perm: string, view: string, roles: UserRoles) => + Object.values(roles).some(permissions => + permissions.some(([perm_, view_]) => perm_ === perm && view_ === view), + ), +); -const getPermissions = memoizeOne(findPermissions); - -export default getPermissions; +export default findPermission;