Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(can_share): can share chart and dashboard #14076

Merged
merged 7 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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', () => {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions superset-frontend/src/dashboard/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,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;
Expand Down Expand Up @@ -543,6 +544,7 @@ class Header extends React.PureComponent {
editMode={editMode}
hasUnsavedChanges={hasUnsavedChanges}
userCanEdit={userCanEdit}
userCanShare={userCanShare}
userCanSave={userCanSaveAs}
isLoading={isLoading}
showPropertiesModal={this.showPropertiesModal}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -192,6 +193,7 @@ class HeaderActionsDropdown extends React.PureComponent {
expandedSlices,
onSave,
userCanEdit,
userCanShare,
userCanSave,
isLoading,
refreshLimit,
Expand Down Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type SliceHeaderProps = {
annotationError?: object;
sliceName?: string;
supersetCanExplore?: boolean;
supersetCanShare?: boolean;
supersetCanCSV?: boolean;
sliceCanEdit?: boolean;
componentId: string;
Expand Down Expand Up @@ -83,6 +84,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
isExpanded = [],
sliceName = '',
supersetCanExplore = false,
supersetCanShare = false,
supersetCanCSV = false,
sliceCanEdit = false,
slice,
Expand Down Expand Up @@ -172,6 +174,7 @@ const SliceHeader: FC<SliceHeaderProps> = ({
exploreChart={exploreChart}
exportCSV={exportCSV}
supersetCanExplore={supersetCanExplore}
supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}
sliceCanEdit={sliceCanEdit}
componentId={componentId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -61,6 +62,7 @@ const defaultProps = {
isCached: [],
isExpanded: false,
supersetCanExplore: false,
supersetCanShare: false,
supersetCanCSV: false,
sliceCanEdit: false,
};
Expand All @@ -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',
};

Expand Down Expand Up @@ -253,18 +254,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}
/>
{this.props.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>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -256,6 +257,7 @@ export default class Chart extends React.Component {
toggleExpandSlice,
timeout,
supersetCanExplore,
supersetCanShare,
supersetCanCSV,
sliceCanEdit,
addSuccessToast,
Expand Down Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions superset-frontend/src/dashboard/containers/Chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions superset-frontend/src/dashboard/reducers/getInitialState.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,10 @@ export default function getInitialState(bootstrapData) {
metadata: dashboard.metadata,
userId: user_id,
dash_edit_perm: dashboard.dash_edit_perm,
dash_share_perm: dashboard.dash_share_perm,
dash_save_perm: dashboard.dash_save_perm,
superset_can_explore: dashboard.superset_can_explore,
superset_can_share: dashboard.superset_can_share,
superset_can_csv: dashboard.superset_can_csv,
slice_can_edit: dashboard.slice_can_edit,
common: {
Expand Down
2 changes: 2 additions & 0 deletions superset/security/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,8 @@ def create_custom_permissions(self) -> None:
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:
"""
Expand Down
8 changes: 8 additions & 0 deletions superset/views/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,12 @@ def dashboard( # pylint: disable=too-many-locals
) and security_manager.can_access("can_save_dash", "Superset")
dash_save_perm = security_manager.can_access("can_save_dash", "Superset")
superset_can_explore = security_manager.can_access("can_explore", "Superset")
superset_can_share_chart = security_manager.can_access(
"can_share_chart", "Superset"
)
superset_can_share_dashboard = security_manager.can_access(
"can_share_dashboard", "Superset"
)
superset_can_csv = security_manager.can_access("can_csv", "Superset")
slice_can_edit = security_manager.can_access("can_edit", "SliceModelView")
standalone_mode = ReservedUrlParameters.is_standalone_mode()
Expand Down Expand Up @@ -1874,8 +1880,10 @@ def dashboard( # pylint: disable=too-many-locals
**data["dashboard"],
"standalone_mode": standalone_mode,
"dash_save_perm": dash_save_perm,
"dash_share_perm": superset_can_share_dashboard,
"dash_edit_perm": dash_edit_perm,
"superset_can_explore": superset_can_explore,
"superset_can_share": superset_can_share_chart,
"superset_can_csv": superset_can_csv,
"slice_can_edit": slice_can_edit,
},
Expand Down
5 changes: 4 additions & 1 deletion tests/security_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,12 +670,13 @@ def assert_can_gamma(self, perm_set):
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)
Expand Down Expand Up @@ -868,6 +869,8 @@ def test_gamma_permissions(self):
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)
Expand Down