diff --git a/superset-frontend/src/features/tags/BulkTagModal.tsx b/superset-frontend/src/features/tags/BulkTagModal.tsx index 32ccd4b0dde69..320c6d296a6d5 100644 --- a/superset-frontend/src/features/tags/BulkTagModal.tsx +++ b/superset-frontend/src/features/tags/BulkTagModal.tsx @@ -59,7 +59,7 @@ const BulkTagModal: FC = ({ endpoint: `/api/v1/tag/bulk_create`, jsonPayload: { tags: tags.map(tag => ({ - name: tag.value, + name: tag.value.toString(), objects_to_tag: selected.map(item => [ resourceName, +item.original.id, @@ -68,10 +68,13 @@ const BulkTagModal: FC = ({ }, }) .then(({ json = {} }) => { - const skipped = json.result.objects_skipped; - const tagged = json.result.objects_tagged; - if (skipped.length > 0) { - addSuccessToast( + const skipped = json.result.objects_skipped || []; + const tagged = json.result.objects_tagged || []; + if (tagged.length > 0) { + addSuccessToast(t('Tagged %s %ss', tagged.length, resourceName)); + } + if (skipped.length > 0 && tagged.length === 0) { + addDangerToast( t( '%s items could not be tagged because you don’t have edit permissions to all selected objects.', skipped.length, @@ -79,12 +82,10 @@ const BulkTagModal: FC = ({ ), ); } - addSuccessToast(t('Tagged %s %ss', tagged.length, resourceName)); }) .catch(err => { addDangerToast(t('Failed to tag items')); }); - refreshData(); onHide(); setTags([]); diff --git a/superset/commands/tag/create.py b/superset/commands/tag/create.py index 775250dc8172d..f53b1be6546aa 100644 --- a/superset/commands/tag/create.py +++ b/superset/commands/tag/create.py @@ -91,20 +91,15 @@ def validate(self) -> None: for obj_type, obj_id in objects_to_tag: object_type = to_object_type(obj_type) - # Validate object type - for obj_type, obj_id in objects_to_tag: - object_type = to_object_type(obj_type) - - if not object_type: - exceptions.append( - TagInvalidError(f"invalid object type {object_type}") - ) - try: - if model := to_object_model(object_type, obj_id): # type: ignore - security_manager.raise_for_ownership(model) - except SupersetSecurityException: - # skip the object if the user doesn't have access - self._skipped_tagged_objects.add((obj_type, obj_id)) + if not object_type: + exceptions.append(TagInvalidError(f"invalid object type {object_type}")) + continue + + try: + if model := to_object_model(object_type, obj_id): + security_manager.raise_for_ownership(model) + except SupersetSecurityException: + self._skipped_tagged_objects.add((obj_type, obj_id)) self._properties["objects_to_tag"] = ( set(objects_to_tag) - self._skipped_tagged_objects diff --git a/superset/queries/saved_queries/filters.py b/superset/queries/saved_queries/filters.py index caf0603d01be7..821f42d6f1120 100644 --- a/superset/queries/saved_queries/filters.py +++ b/superset/queries/saved_queries/filters.py @@ -16,15 +16,14 @@ # under the License. from typing import Any +from flask import g from flask_babel import lazy_gettext as _ from flask_sqlalchemy import BaseQuery from sqlalchemy import or_ from sqlalchemy.orm.query import Query -from superset import security_manager from superset.models.sql_lab import SavedQuery from superset.tags.filters import BaseTagIdFilter, BaseTagNameFilter -from superset.utils.core import get_user_id from superset.views.base import BaseFilter from superset.views.base_api import BaseFavoriteFilter @@ -83,13 +82,10 @@ class SavedQueryTagIdFilter(BaseTagIdFilter): # pylint: disable=too-few-public- class SavedQueryFilter(BaseFilter): # pylint: disable=too-few-public-methods def apply(self, query: BaseQuery, value: Any) -> BaseQuery: """ - Filters saved queries to include: - - Queries owned by the current user - - Queries accessible by users with 'can read' permission on SavedQuery - """ - user_id = get_user_id() - - if security_manager.can_access("can_read", "SavedQuery"): - return query + Filter saved queries to only those created by current user. - return query.filter(SavedQuery.user_id == user_id) + :returns: flask-sqlalchemy query + """ + return query.filter( + SavedQuery.created_by == g.user # pylint: disable=comparison-with-callable + )