Skip to content

Commit

Permalink
feat: adds can_tag_object permission to Taxonomy List response
Browse files Browse the repository at this point in the history
This permission is needed by the Content Tag Drawer, which fetches the
list of taxonomies available for tagging a given content item, and shows
an "Add tags" button for the ones the user may add Object Tags for.
  • Loading branch information
pomegranited committed Jan 11, 2024
1 parent 7470904 commit 1e2d9b0
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 1 deletion.
20 changes: 20 additions & 0 deletions openedx_tagging/core/tagging/rest_api/v1/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from openedx_tagging.core.tagging.data import TagData
from openedx_tagging.core.tagging.import_export.parsers import ParserFormat
from openedx_tagging.core.tagging.models import ObjectTag, Tag, TagImportTask, Taxonomy
from openedx_tagging.core.tagging.rules import ObjectTagPermissionItem

from ..utils import UserPermissionsHelper

Expand Down Expand Up @@ -72,6 +73,7 @@ class TaxonomySerializer(UserPermissionsSerializerMixin, serializers.ModelSerial
tags_count = serializers.SerializerMethodField()
can_change = serializers.SerializerMethodField()
can_delete = serializers.SerializerMethodField()
can_tag_object = serializers.SerializerMethodField()

class Meta:
model = Taxonomy
Expand All @@ -87,6 +89,7 @@ class Meta:
"tags_count",
"can_change",
"can_delete",
"can_tag_object",
]

def to_representation(self, instance):
Expand All @@ -99,6 +102,23 @@ def to_representation(self, instance):
def get_tags_count(self, instance):
return instance.tag_set.count()

def get_can_tag_object(self, instance) -> Optional[bool]:
"""
Returns True if the current request user may create object tags on this taxonomy.
(The object_id test is necessarily skipped because we don't have an object_id to check.)
"""
request = self._request
assert request and request.user
if not self._include_perms:
return None

model = self._model
app_label = model._meta.app_label
perm_name = f'{app_label}.add_objecttag'
perm_object = ObjectTagPermissionItem(taxonomy=instance, object_id=None)
return request.user.has_perm(perm_name, perm_object)


class ObjectTagListQueryParamsSerializer(serializers.Serializer): # pylint: disable=abstract-method
"""
Expand Down
12 changes: 11 additions & 1 deletion tests/openedx_tagging/core/tagging/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def check_taxonomy(
visible_to_authors=True,
can_change=None,
can_delete=None,
can_tag_object=None,
):
"""
Check taxonomy data
Expand All @@ -69,6 +70,7 @@ def check_taxonomy(
assert data["visible_to_authors"] == visible_to_authors
assert data["can_change"] == can_change
assert data["can_delete"] == can_delete
assert data["can_tag_object"] == can_tag_object


class TestTaxonomyViewMixin(APITestCase):
Expand Down Expand Up @@ -170,6 +172,7 @@ def test_list_taxonomy(self, user_attr: str | None, expected_status: int, tags_c
# System taxonomy cannot be modified
"can_change": False,
"can_delete": False,
"can_tag_object": False,
},
{
"id": taxonomy.id,
Expand All @@ -184,6 +187,7 @@ def test_list_taxonomy(self, user_attr: str | None, expected_status: int, tags_c
# Enabled taxonomy can be modified by staff
"can_change": is_admin,
"can_delete": is_admin,
"can_tag_object": False,
},
]
assert response.data.get("can_add") == is_admin
Expand Down Expand Up @@ -263,6 +267,7 @@ def test_list_taxonomy_query_count(self, include_perms):
for taxonomy in response.data["results"]:
assert taxonomy["can_change"] == expected_perm
assert taxonomy["can_delete"] == expected_perm
assert taxonomy["can_tag_object"] == expected_perm

def test_list_invalid_page(self) -> None:
url = TAXONOMY_LIST_URL
Expand Down Expand Up @@ -320,6 +325,7 @@ def test_detail_taxonomy(
expected_data = create_data
expected_data["can_change"] = is_admin
expected_data["can_delete"] = is_admin
expected_data["can_tag_object"] = False
check_taxonomy(response.data, taxonomy.pk, **expected_data)

def test_detail_system_taxonomy(self):
Expand Down Expand Up @@ -431,6 +437,7 @@ def test_update_taxonomy(self, user_attr, expected_status):
"enabled": True,
"can_change": True,
"can_delete": True,
"can_tag_object": False,
},
)

Expand Down Expand Up @@ -489,6 +496,7 @@ def test_patch_taxonomy(self, user_attr, expected_status):
"enabled": True,
"can_change": True,
"can_delete": True,
"can_tag_object": False,
},
)

Expand Down Expand Up @@ -1430,7 +1438,7 @@ def test_small_query_count(self, include_perms):
expected_perm = None
url = f"{self.small_taxonomy_url}?search_term=eU"
if include_perms:
url += '?include_perms'
url += '&include_perms'
expected_perm = True

self.client.force_authenticate(user=self.staff)
Expand All @@ -1443,6 +1451,7 @@ def test_small_query_count(self, include_perms):
for taxonomy in response.data["results"]:
assert taxonomy["can_change"] == expected_perm
assert taxonomy["can_delete"] == expected_perm
assert not taxonomy["can_tag_object"]

def test_empty_results(self):
"""
Expand Down Expand Up @@ -1517,6 +1526,7 @@ def test_large_taxonomy(self, include_perms):
)
assert results[0].get("can_change") == expected_perm
assert results[0].get("can_delete") == expected_perm
assert not results[0].get("can_tag_object")

# Checking pagination values
assert data.get("next") == (
Expand Down

0 comments on commit 1e2d9b0

Please sign in to comment.