diff --git a/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py b/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py index 8cb4b94fd227..7caccf7e81cc 100644 --- a/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py +++ b/openedx/core/djangoapps/content_tagging/rest_api/v1/tests/test_views.py @@ -270,18 +270,18 @@ def test_list_invalid_page(self): assert response.status_code == status.HTTP_404_NOT_FOUND @ddt.data( - (None, "ot1", status.HTTP_403_FORBIDDEN), - (None, "ot2", status.HTTP_403_FORBIDDEN), - (None, "st1", status.HTTP_403_FORBIDDEN), - (None, "st2", status.HTTP_403_FORBIDDEN), - (None, "t1", status.HTTP_403_FORBIDDEN), - (None, "t2", status.HTTP_403_FORBIDDEN), - (None, "tA1", status.HTTP_403_FORBIDDEN), - (None, "tA2", status.HTTP_403_FORBIDDEN), - (None, "tB1", status.HTTP_403_FORBIDDEN), - (None, "tB2", status.HTTP_403_FORBIDDEN), - (None, "tC1", status.HTTP_403_FORBIDDEN), - (None, "tC2", status.HTTP_403_FORBIDDEN), + (None, "ot1", status.HTTP_401_UNAUTHORIZED), + (None, "ot2", status.HTTP_401_UNAUTHORIZED), + (None, "st1", status.HTTP_401_UNAUTHORIZED), + (None, "st2", status.HTTP_401_UNAUTHORIZED), + (None, "t1", status.HTTP_401_UNAUTHORIZED), + (None, "t2", status.HTTP_401_UNAUTHORIZED), + (None, "tA1", status.HTTP_401_UNAUTHORIZED), + (None, "tA2", status.HTTP_401_UNAUTHORIZED), + (None, "tB1", status.HTTP_401_UNAUTHORIZED), + (None, "tB2", status.HTTP_401_UNAUTHORIZED), + (None, "tC1", status.HTTP_401_UNAUTHORIZED), + (None, "tC2", status.HTTP_401_UNAUTHORIZED), ("user", "ot1", status.HTTP_200_OK), ("user", "ot2", status.HTTP_404_NOT_FOUND), ("user", "st1", status.HTTP_200_OK), @@ -336,7 +336,7 @@ def test_detail_taxonomy(self, user_attr, taxonomy_attr, expected_status): check_taxonomy(response.data, taxonomy.pk, **(TaxonomySerializer(taxonomy.cast()).data)) @ddt.data( - (None, status.HTTP_403_FORBIDDEN), + (None, status.HTTP_401_UNAUTHORIZED), ("user", status.HTTP_403_FORBIDDEN), ("userA", status.HTTP_403_FORBIDDEN), ("userS", status.HTTP_201_CREATED), @@ -368,18 +368,18 @@ def test_create_taxonomy(self, user_attr, expected_status): check_taxonomy(response.data, response.data["id"], **create_data) @ddt.data( - (None, "ot1", status.HTTP_403_FORBIDDEN), - (None, "ot2", status.HTTP_403_FORBIDDEN), - (None, "st1", status.HTTP_403_FORBIDDEN), - (None, "st2", status.HTTP_403_FORBIDDEN), - (None, "t1", status.HTTP_403_FORBIDDEN), - (None, "t2", status.HTTP_403_FORBIDDEN), - (None, "tA1", status.HTTP_403_FORBIDDEN), - (None, "tA2", status.HTTP_403_FORBIDDEN), - (None, "tB1", status.HTTP_403_FORBIDDEN), - (None, "tB2", status.HTTP_403_FORBIDDEN), - (None, "tC1", status.HTTP_403_FORBIDDEN), - (None, "tC2", status.HTTP_403_FORBIDDEN), + (None, "ot1", status.HTTP_401_UNAUTHORIZED), + (None, "ot2", status.HTTP_401_UNAUTHORIZED), + (None, "st1", status.HTTP_401_UNAUTHORIZED), + (None, "st2", status.HTTP_401_UNAUTHORIZED), + (None, "t1", status.HTTP_401_UNAUTHORIZED), + (None, "t2", status.HTTP_401_UNAUTHORIZED), + (None, "tA1", status.HTTP_401_UNAUTHORIZED), + (None, "tA2", status.HTTP_401_UNAUTHORIZED), + (None, "tB1", status.HTTP_401_UNAUTHORIZED), + (None, "tB2", status.HTTP_401_UNAUTHORIZED), + (None, "tC1", status.HTTP_401_UNAUTHORIZED), + (None, "tC2", status.HTTP_401_UNAUTHORIZED), ("user", "ot1", status.HTTP_403_FORBIDDEN), ("user", "ot2", status.HTTP_403_FORBIDDEN), ("user", "st1", status.HTTP_403_FORBIDDEN), @@ -465,18 +465,18 @@ def test_update_taxonomy_system_defined(self, update_value, expected_status): assert response.data["system_defined"] is True @ddt.data( - (None, "ot1", status.HTTP_403_FORBIDDEN), - (None, "ot2", status.HTTP_403_FORBIDDEN), - (None, "st1", status.HTTP_403_FORBIDDEN), - (None, "st2", status.HTTP_403_FORBIDDEN), - (None, "t1", status.HTTP_403_FORBIDDEN), - (None, "t2", status.HTTP_403_FORBIDDEN), - (None, "tA1", status.HTTP_403_FORBIDDEN), - (None, "tA2", status.HTTP_403_FORBIDDEN), - (None, "tB1", status.HTTP_403_FORBIDDEN), - (None, "tB2", status.HTTP_403_FORBIDDEN), - (None, "tC1", status.HTTP_403_FORBIDDEN), - (None, "tC2", status.HTTP_403_FORBIDDEN), + (None, "ot1", status.HTTP_401_UNAUTHORIZED), + (None, "ot2", status.HTTP_401_UNAUTHORIZED), + (None, "st1", status.HTTP_401_UNAUTHORIZED), + (None, "st2", status.HTTP_401_UNAUTHORIZED), + (None, "t1", status.HTTP_401_UNAUTHORIZED), + (None, "t2", status.HTTP_401_UNAUTHORIZED), + (None, "tA1", status.HTTP_401_UNAUTHORIZED), + (None, "tA2", status.HTTP_401_UNAUTHORIZED), + (None, "tB1", status.HTTP_401_UNAUTHORIZED), + (None, "tB2", status.HTTP_401_UNAUTHORIZED), + (None, "tC1", status.HTTP_401_UNAUTHORIZED), + (None, "tC2", status.HTTP_401_UNAUTHORIZED), ("user", "ot1", status.HTTP_403_FORBIDDEN), ("user", "ot2", status.HTTP_403_FORBIDDEN), ("user", "st1", status.HTTP_403_FORBIDDEN), @@ -560,18 +560,18 @@ def test_patch_taxonomy_system_defined(self, update_value, expected_status): assert response.data["system_defined"] is True @ddt.data( - (None, "ot1", status.HTTP_403_FORBIDDEN), - (None, "ot2", status.HTTP_403_FORBIDDEN), - (None, "st1", status.HTTP_403_FORBIDDEN), - (None, "st2", status.HTTP_403_FORBIDDEN), - (None, "t1", status.HTTP_403_FORBIDDEN), - (None, "t2", status.HTTP_403_FORBIDDEN), - (None, "tA1", status.HTTP_403_FORBIDDEN), - (None, "tA2", status.HTTP_403_FORBIDDEN), - (None, "tB1", status.HTTP_403_FORBIDDEN), - (None, "tB2", status.HTTP_403_FORBIDDEN), - (None, "tC1", status.HTTP_403_FORBIDDEN), - (None, "tC2", status.HTTP_403_FORBIDDEN), + (None, "ot1", status.HTTP_401_UNAUTHORIZED), + (None, "ot2", status.HTTP_401_UNAUTHORIZED), + (None, "st1", status.HTTP_401_UNAUTHORIZED), + (None, "st2", status.HTTP_401_UNAUTHORIZED), + (None, "t1", status.HTTP_401_UNAUTHORIZED), + (None, "t2", status.HTTP_401_UNAUTHORIZED), + (None, "tA1", status.HTTP_401_UNAUTHORIZED), + (None, "tA2", status.HTTP_401_UNAUTHORIZED), + (None, "tB1", status.HTTP_401_UNAUTHORIZED), + (None, "tB2", status.HTTP_401_UNAUTHORIZED), + (None, "tC1", status.HTTP_401_UNAUTHORIZED), + (None, "tC2", status.HTTP_401_UNAUTHORIZED), ("user", "ot1", status.HTTP_403_FORBIDDEN), ("user", "ot2", status.HTTP_403_FORBIDDEN), ("user", "st1", status.HTTP_403_FORBIDDEN), @@ -695,24 +695,24 @@ def setUp(self): @ddt.data( # userA and userS are staff in courseA and can tag using enabled taxonomies - (None, "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN), + (None, "tA1", ["Tag 1"], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userA", "tA1", ["Tag 1"], status.HTTP_200_OK), ("userS", "tA1", ["Tag 1"], status.HTTP_200_OK), - (None, "tA1", [], status.HTTP_403_FORBIDDEN), + (None, "tA1", [], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", [], status.HTTP_403_FORBIDDEN), ("userA", "tA1", [], status.HTTP_200_OK), ("userS", "tA1", [], status.HTTP_200_OK), - (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN), + (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_401_UNAUTHORIZED), ("user", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN), ("userA", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK), ("userS", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK), - (None, "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN), + (None, "open_taxonomy", ["tag1"], status.HTTP_401_UNAUTHORIZED), ("user", "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN), ("userA", "open_taxonomy", ["tag1"], status.HTTP_200_OK), ("userS", "open_taxonomy", ["tag1"], status.HTTP_200_OK), # Only userS is Tagging Admin and can tag objects using disabled taxonomies - (None, "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), + (None, "tA2", ["Tag 1"], status.HTTP_401_UNAUTHORIZED), ("user", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userA", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userS", "tA2", ["Tag 1"], status.HTTP_200_OK), @@ -736,11 +736,11 @@ def test_tag_course(self, user_attr, taxonomy_attr, tag_values, expected_status) @ddt.data( # Can't add invalid tags to a object using a closed taxonomy - (None, "tA1", ["invalid"], status.HTTP_403_FORBIDDEN), + (None, "tA1", ["invalid"], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", ["invalid"], status.HTTP_403_FORBIDDEN), ("userA", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST), ("userS", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST), - (None, "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN), + (None, "multiple_taxonomy", ["invalid"], status.HTTP_401_UNAUTHORIZED), ("user", "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN), ("userA", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST), ("userS", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST), @@ -763,24 +763,24 @@ def test_tag_course_invalid(self, user_attr, taxonomy_attr, tag_values, expected @ddt.data( # userA and userS are staff in courseA (owner of xblockA) and can tag using enabled taxonomies - (None, "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN), + (None, "tA1", ["Tag 1"], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userA", "tA1", ["Tag 1"], status.HTTP_200_OK), ("userS", "tA1", ["Tag 1"], status.HTTP_200_OK), - (None, "tA1", [], status.HTTP_403_FORBIDDEN), + (None, "tA1", [], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", [], status.HTTP_403_FORBIDDEN), ("userA", "tA1", [], status.HTTP_200_OK), ("userS", "tA1", [], status.HTTP_200_OK), - (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN), + (None, "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_401_UNAUTHORIZED), ("user", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_403_FORBIDDEN), ("userA", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK), ("userS", "multiple_taxonomy", ["Tag 1", "Tag 2"], status.HTTP_200_OK), - (None, "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN), + (None, "open_taxonomy", ["tag1"], status.HTTP_401_UNAUTHORIZED), ("user", "open_taxonomy", ["tag1"], status.HTTP_403_FORBIDDEN), ("userA", "open_taxonomy", ["tag1"], status.HTTP_200_OK), ("userS", "open_taxonomy", ["tag1"], status.HTTP_200_OK), # Only userS is Tagging Admin and can tag objects using disabled taxonomies - (None, "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), + (None, "tA2", ["Tag 1"], status.HTTP_401_UNAUTHORIZED), ("user", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userA", "tA2", ["Tag 1"], status.HTTP_403_FORBIDDEN), ("userS", "tA2", ["Tag 1"], status.HTTP_200_OK), @@ -804,11 +804,11 @@ def test_tag_xblock(self, user_attr, taxonomy_attr, tag_values, expected_status) @ddt.data( # Can't add invalid tags to a object using a closed taxonomy - (None, "tA1", ["invalid"], status.HTTP_403_FORBIDDEN), + (None, "tA1", ["invalid"], status.HTTP_401_UNAUTHORIZED), ("user", "tA1", ["invalid"], status.HTTP_403_FORBIDDEN), ("userA", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST), ("userS", "tA1", ["invalid"], status.HTTP_400_BAD_REQUEST), - (None, "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN), + (None, "multiple_taxonomy", ["invalid"], status.HTTP_401_UNAUTHORIZED), ("user", "multiple_taxonomy", ["invalid"], status.HTTP_403_FORBIDDEN), ("userA", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST), ("userS", "multiple_taxonomy", ["invalid"], status.HTTP_400_BAD_REQUEST), diff --git a/openedx/core/djangoapps/content_tagging/rules.py b/openedx/core/djangoapps/content_tagging/rules.py index bad38019ce51..b046fe51732a 100644 --- a/openedx/core/djangoapps/content_tagging/rules.py +++ b/openedx/core/djangoapps/content_tagging/rules.py @@ -86,6 +86,7 @@ def can_change_taxonomy_tag(user: UserType, tag: oel_tagging.Tag | None = None) rules.set_perm("oel_tagging.change_taxonomy", oel_tagging.can_change_taxonomy) rules.set_perm("oel_tagging.delete_taxonomy", oel_tagging.can_change_taxonomy) rules.set_perm("oel_tagging.view_taxonomy", oel_tagging.can_view_taxonomy) +rules.set_perm("oel_tagging.export_taxonomy", oel_tagging.can_view_taxonomy) # Tag rules.set_perm("oel_tagging.add_tag", can_change_taxonomy_tag) diff --git a/requirements/constraints.txt b/requirements/constraints.txt index f39da29f11c5..6b68db0e11bf 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -121,7 +121,7 @@ libsass==0.10.0 click==8.1.6 # pinning this version to avoid updates while the library is being developed -openedx-learning==0.2.3 +openedx-learning==0.2.4 # lti-consumer-xblock 9.6.2 contains a breaking change that makes # existing custom parameter configurations unusable. diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index c5ed717a7720..119461936aa8 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -785,7 +785,7 @@ openedx-filters==1.6.0 # via # -r requirements/edx/kernel.in # lti-consumer-xblock -openedx-learning==0.2.3 +openedx-learning==0.2.4 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/kernel.in diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 86cb1ccb51d4..29b9567f14a4 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -1318,7 +1318,7 @@ openedx-filters==1.6.0 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # lti-consumer-xblock -openedx-learning==0.2.3 +openedx-learning==0.2.4 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/doc.txt diff --git a/requirements/edx/doc.txt b/requirements/edx/doc.txt index 4f6abf333fda..c5b3e10f6d6e 100644 --- a/requirements/edx/doc.txt +++ b/requirements/edx/doc.txt @@ -925,7 +925,7 @@ openedx-filters==1.6.0 # via # -r requirements/edx/base.txt # lti-consumer-xblock -openedx-learning==0.2.3 +openedx-learning==0.2.4 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 2aabad42efe6..831ee3136d6f 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -992,7 +992,7 @@ openedx-filters==1.6.0 # via # -r requirements/edx/base.txt # lti-consumer-xblock -openedx-learning==0.2.3 +openedx-learning==0.2.4 # via # -c requirements/edx/../constraints.txt # -r requirements/edx/base.txt