This is an automated email from the ASF dual-hosted git repository.

amitmiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/master by this push:
     new 9c5264a  feat(can_share): can share chart and dashboard (#14076)
9c5264a is described below

commit 9c5264af0d4040cfcfb13c7e668e3ad9c242dcf8
Author: Amit Miran <[email protected]>
AuthorDate: Tue Apr 13 13:54:14 2021 +0300

    feat(can_share): can share chart and dashboard (#14076)
    
    
    * feat: share chart  - can_share_chart
    share dashboard can_share_dashboard
    
    * fix: pre-commit
    
    * fix: userCanShare tests
    
    * fix: after hugh CR
    
    * fix: adjust after spa refactor
---
 .../components/HeaderActionsDropdown_spec.jsx      | 14 ++++++----
 superset-frontend/src/dashboard/actions/hydrate.js | 10 ++++++++
 .../src/dashboard/components/Header.jsx            |  2 ++
 .../dashboard/components/HeaderActionsDropdown.jsx | 22 +++++++++-------
 .../src/dashboard/components/SliceHeader/index.tsx |  3 +++
 .../components/SliceHeaderControls/index.jsx       | 30 ++++++++++++----------
 .../dashboard/components/gridComponents/Chart.jsx  |  3 +++
 .../src/dashboard/containers/Chart.jsx             |  1 +
 superset/security/manager.py                       |  2 ++
 tests/security_tests.py                            |  5 +++-
 10 files changed, 64 insertions(+), 28 deletions(-)

diff --git 
a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
 
b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
index ea3b65c..fa60986 100644
--- 
a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
@@ -67,7 +67,7 @@ describe('HeaderActionsDropdown', () => {
   }
 
   describe('readonly-user', () => {
-    const overrideProps = { userCanSave: false };
+    const overrideProps = { userCanSave: false, userCanShare: false };
 
     it('should render the DropdownButton', () => {
       const { wrapper } = setup(overrideProps);
@@ -89,9 +89,9 @@ describe('HeaderActionsDropdown', () => {
       expect(menu.find(RefreshIntervalModal)).toExist();
     });
 
-    it('should render the ShareMenuItems', () => {
+    it('should not render the ShareMenuItems', () => {
       const { menu } = setup(overrideProps);
-      expect(menu.find(ShareMenuItems)).toExist();
+      expect(menu.find(ShareMenuItems)).not.toExist();
     });
 
     it('should not render the CssEditor', () => {
@@ -101,7 +101,7 @@ describe('HeaderActionsDropdown', () => {
   });
 
   describe('write-user', () => {
-    const overrideProps = { userCanSave: true };
+    const overrideProps = { userCanSave: true, userCanShare: true };
 
     it('should render the DropdownButton', () => {
       const { wrapper } = setup(overrideProps);
@@ -135,7 +135,11 @@ describe('HeaderActionsDropdown', () => {
   });
 
   describe('write-user-with-edit-mode', () => {
-    const overrideProps = { userCanSave: true, editMode: true };
+    const overrideProps = {
+      userCanSave: true,
+      editMode: true,
+      userCanShare: true,
+    };
 
     it('should render the DropdownButton', () => {
       const { wrapper } = setup(overrideProps);
diff --git a/superset-frontend/src/dashboard/actions/hydrate.js 
b/superset-frontend/src/dashboard/actions/hydrate.js
index 7cdaa23..8065bf6 100644
--- a/superset-frontend/src/dashboard/actions/hydrate.js
+++ b/superset-frontend/src/dashboard/actions/hydrate.js
@@ -313,7 +313,17 @@ export const hydrateDashboard = (dashboardData, chartData, 
datasourcesData) => (
         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(
+          'can_share_dashboard',
+          'Superset',
+          roles,
+        ),
         superset_can_explore: getPermissions('can_explore', 'Superset', roles),
+        superset_can_share: getPermissions(
+          'can_share_chart',
+          'Superset',
+          roles,
+        ),
         superset_can_csv: getPermissions('can_csv', 'Superset', roles),
         slice_can_edit: getPermissions('can_slice', 'Superset', roles),
         common: {
diff --git a/superset-frontend/src/dashboard/components/Header.jsx 
b/superset-frontend/src/dashboard/components/Header.jsx
index 6a89e94..1e5d186 100644
--- a/superset-frontend/src/dashboard/components/Header.jsx
+++ b/superset-frontend/src/dashboard/components/Header.jsx
@@ -375,6 +375,7 @@ class Header extends React.PureComponent {
     } = this.props;
 
     const userCanEdit = dashboardInfo.dash_edit_perm;
+    const userCanShare = dashboardInfo.dash_share_perm;
     const userCanSaveAs = dashboardInfo.dash_save_perm;
     const refreshLimit =
       dashboardInfo.common.conf.SUPERSET_DASHBOARD_PERIODICAL_REFRESH_LIMIT;
@@ -542,6 +543,7 @@ class Header extends React.PureComponent {
             editMode={editMode}
             hasUnsavedChanges={hasUnsavedChanges}
             userCanEdit={userCanEdit}
+            userCanShare={userCanShare}
             userCanSave={userCanSaveAs}
             isLoading={isLoading}
             showPropertiesModal={this.showPropertiesModal}
diff --git 
a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx 
b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
index 5d27f1f..ba255fb 100644
--- a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
@@ -54,6 +54,7 @@ const propTypes = {
   startPeriodicRender: PropTypes.func.isRequired,
   editMode: PropTypes.bool.isRequired,
   userCanEdit: PropTypes.bool.isRequired,
+  userCanShare: PropTypes.bool.isRequired,
   userCanSave: PropTypes.bool.isRequired,
   isLoading: PropTypes.bool.isRequired,
   layout: PropTypes.object.isRequired,
@@ -192,6 +193,7 @@ class HeaderActionsDropdown extends React.PureComponent {
       expandedSlices,
       onSave,
       userCanEdit,
+      userCanShare,
       userCanSave,
       isLoading,
       refreshLimit,
@@ -241,15 +243,17 @@ class HeaderActionsDropdown extends React.PureComponent {
             />
           </Menu.Item>
         )}
-        <ShareMenuItems
-          url={url}
-          copyMenuItemTitle={t('Copy dashboard URL')}
-          emailMenuItemTitle={t('Share dashboard by email')}
-          emailSubject={emailSubject}
-          emailBody={emailBody}
-          addSuccessToast={addSuccessToast}
-          addDangerToast={addDangerToast}
-        />
+        {userCanShare && (
+          <ShareMenuItems
+            url={url}
+            copyMenuItemTitle={t('Copy dashboard URL')}
+            emailMenuItemTitle={t('Share dashboard by email')}
+            emailSubject={emailSubject}
+            emailBody={emailBody}
+            addSuccessToast={addSuccessToast}
+            addDangerToast={addDangerToast}
+          />
+        )}
         <Menu.Item
           key={MENU_KEYS.REFRESH_DASHBOARD}
           data-test="refresh-dashboard-menu-item"
diff --git a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx 
b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
index 875852c..72bd089 100644
--- a/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
+++ b/superset-frontend/src/dashboard/components/SliceHeader/index.tsx
@@ -46,6 +46,7 @@ type SliceHeaderProps = {
   annotationError?: object;
   sliceName?: string;
   supersetCanExplore?: boolean;
+  supersetCanShare?: boolean;
   supersetCanCSV?: boolean;
   sliceCanEdit?: boolean;
   componentId: string;
@@ -83,6 +84,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
   isExpanded = [],
   sliceName = '',
   supersetCanExplore = false,
+  supersetCanShare = false,
   supersetCanCSV = false,
   sliceCanEdit = false,
   slice,
@@ -172,6 +174,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
               exploreChart={exploreChart}
               exportCSV={exportCSV}
               supersetCanExplore={supersetCanExplore}
+              supersetCanShare={supersetCanShare}
               supersetCanCSV={supersetCanCSV}
               sliceCanEdit={sliceCanEdit}
               componentId={componentId}
diff --git 
a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx 
b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
index edef021..650a590 100644
--- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
+++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
@@ -43,6 +43,7 @@ const propTypes = {
   isExpanded: PropTypes.bool,
   updatedDttm: PropTypes.number,
   supersetCanExplore: PropTypes.bool,
+  supersetCanShare: PropTypes.bool,
   supersetCanCSV: PropTypes.bool,
   sliceCanEdit: PropTypes.bool,
   toggleExpandSlice: PropTypes.func,
@@ -61,6 +62,7 @@ const defaultProps = {
   isCached: [],
   isExpanded: false,
   supersetCanExplore: false,
+  supersetCanShare: false,
   supersetCanCSV: false,
   sliceCanEdit: false,
 };
@@ -72,7 +74,6 @@ const MENU_KEYS = {
   EXPLORE_CHART: 'explore_chart',
   EXPORT_CSV: 'export_csv',
   RESIZE_LABEL: 'resize_label',
-  SHARE_CHART: 'share_chart',
   DOWNLOAD_AS_IMAGE: 'download_as_image',
 };
 
@@ -188,6 +189,7 @@ class SliceHeaderControls extends React.PureComponent {
       addSuccessToast,
       addDangerToast,
       isFullSize,
+      supersetCanShare,
     } = this.props;
     const crossFilterItems = getChartMetadataRegistry().items;
     const isCrossFilter = Object.entries(crossFilterItems)
@@ -253,18 +255,20 @@ class SliceHeaderControls extends React.PureComponent {
           </Menu.Item>
         )}
 
-        <ShareMenuItems
-          url={getDashboardUrl(
-            window.location.pathname,
-            getActiveFilters(),
-            componentId,
-          )}
-          copyMenuItemTitle={t('Copy chart URL')}
-          emailMenuItemTitle={t('Share chart by email')}
-          emailSubject={t('Superset chart')}
-          addSuccessToast={addSuccessToast}
-          addDangerToast={addDangerToast}
-        />
+        {supersetCanShare && (
+          <ShareMenuItems
+            url={getDashboardUrl(
+              window.location.pathname,
+              getActiveFilters(),
+              componentId,
+            )}
+            copyMenuItemTitle={t('Copy chart URL')}
+            emailMenuItemTitle={t('Share chart by email')}
+            emailSubject={t('Superset chart')}
+            addSuccessToast={addSuccessToast}
+            addDangerToast={addDangerToast}
+          />
+        )}
 
         <Menu.Item key={MENU_KEYS.RESIZE_LABEL}>{resizeLabel}</Menu.Item>
 
diff --git 
a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx 
b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
index 18cec53..bfe775e 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
@@ -65,6 +65,7 @@ const propTypes = {
   isExpanded: PropTypes.bool.isRequired,
   isCached: PropTypes.bool,
   supersetCanExplore: PropTypes.bool.isRequired,
+  supersetCanShare: PropTypes.bool.isRequired,
   supersetCanCSV: PropTypes.bool.isRequired,
   sliceCanEdit: PropTypes.bool.isRequired,
   addSuccessToast: PropTypes.func.isRequired,
@@ -256,6 +257,7 @@ export default class Chart extends React.Component {
       toggleExpandSlice,
       timeout,
       supersetCanExplore,
+      supersetCanShare,
       supersetCanCSV,
       sliceCanEdit,
       addSuccessToast,
@@ -311,6 +313,7 @@ export default class Chart extends React.Component {
           updateSliceName={updateSliceName}
           sliceName={sliceName}
           supersetCanExplore={supersetCanExplore}
+          supersetCanShare={supersetCanShare}
           supersetCanCSV={supersetCanCSV}
           sliceCanEdit={sliceCanEdit}
           componentId={componentId}
diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx 
b/superset-frontend/src/dashboard/containers/Chart.jsx
index 94f88d3..31c0e32 100644
--- a/superset-frontend/src/dashboard/containers/Chart.jsx
+++ b/superset-frontend/src/dashboard/containers/Chart.jsx
@@ -84,6 +84,7 @@ function mapStateToProps(
     editMode: dashboardState.editMode,
     isExpanded: !!dashboardState.expandedSlices[id],
     supersetCanExplore: !!dashboardInfo.superset_can_explore,
+    supersetCanShare: !!dashboardInfo.superset_can_share,
     supersetCanCSV: !!dashboardInfo.superset_can_csv,
     sliceCanEdit: !!dashboardInfo.slice_can_edit,
     ownCurrentState: dataMask.ownFilters?.[id]?.currentState,
diff --git a/superset/security/manager.py b/superset/security/manager.py
index 1c4419c..6472af6 100644
--- a/superset/security/manager.py
+++ b/superset/security/manager.py
@@ -556,6 +556,8 @@ class SupersetSecurityManager(  # pylint: 
disable=too-many-public-methods
         self.add_permission_view_menu("all_datasource_access", 
"all_datasource_access")
         self.add_permission_view_menu("all_database_access", 
"all_database_access")
         self.add_permission_view_menu("all_query_access", "all_query_access")
+        self.add_permission_view_menu("can_share_dashboard", "Superset")
+        self.add_permission_view_menu("can_share_chart", "Superset")
 
     def create_missing_perms(self) -> None:
         """
diff --git a/tests/security_tests.py b/tests/security_tests.py
index 0648104..f7e5517 100644
--- a/tests/security_tests.py
+++ b/tests/security_tests.py
@@ -670,12 +670,13 @@ class TestRolePermission(SupersetTestCase):
         self.assertIn(("can_csv", "Superset"), perm_set)
         self.assertIn(("can_dashboard", "Superset"), perm_set)
         self.assertIn(("can_explore", "Superset"), perm_set)
+        self.assertIn(("can_share_chart", "Superset"), perm_set)
+        self.assertIn(("can_share_dashboard", "Superset"), perm_set)
         self.assertIn(("can_explore_json", "Superset"), perm_set)
         self.assertIn(("can_fave_dashboards", "Superset"), perm_set)
         self.assertIn(("can_fave_slices", "Superset"), perm_set)
         self.assertIn(("can_save_dash", "Superset"), perm_set)
         self.assertIn(("can_slice", "Superset"), perm_set)
-        self.assertIn(("can_explore", "Superset"), perm_set)
         self.assertIn(("can_explore_json", "Superset"), perm_set)
         self.assertIn(("can_userinfo", "UserDBModelView"), perm_set)
         self.assert_can_menu("Databases", perm_set)
@@ -868,6 +869,8 @@ class TestRolePermission(SupersetTestCase):
         self.assertIn(("can_csv", "Superset"), gamma_perm_set)
         self.assertIn(("can_dashboard", "Superset"), gamma_perm_set)
         self.assertIn(("can_explore", "Superset"), gamma_perm_set)
+        self.assertIn(("can_share_chart", "Superset"), gamma_perm_set)
+        self.assertIn(("can_share_dashboard", "Superset"), gamma_perm_set)
         self.assertIn(("can_explore_json", "Superset"), gamma_perm_set)
         self.assertIn(("can_fave_dashboards", "Superset"), gamma_perm_set)
         self.assertIn(("can_fave_slices", "Superset"), gamma_perm_set)

Reply via email to