diff --git a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/api.py b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/api.py index 6f54142053..a7cc3730cc 100644 --- a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/api.py +++ b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/api.py @@ -27,7 +27,7 @@ class {{cookiecutter.model}}ViewSet( queryset = {{cookiecutter.model}}.objects.all() serializer_class = serializers.{{cookiecutter.model}}Serializer permission_classes = [ - core_permissions.IsTokenResourceRouteObject + core_permissions.IsTokenPlaylistRouteObject & (core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin) ] @@ -44,7 +44,7 @@ def get_permissions(self): & (core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin) ] elif self.action in ["retrieve"]: - permission_classes = [core_permissions.IsTokenResourceRouteObject] + permission_classes = [core_permissions.IsTokenPlaylistRouteObject] else: permission_classes = self.permission_classes return [permission() for permission in permission_classes] diff --git a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_api.py b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_api.py index 00e2b964c1..75cae2e9a5 100644 --- a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_api.py +++ b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_api.py @@ -42,7 +42,7 @@ def test_api_{{cookiecutter.model_lower}}_fetch_list_student(self): {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() jwt_token = StudentLtiTokenFactory( - resource={{cookiecutter.model_lower}}, + playlist={{cookiecutter.model_lower}}.playlist, permissions__can_update=True, ) @@ -55,7 +55,7 @@ def test_api_{{cookiecutter.model_lower}}_fetch_list_instructor(self): """An instructor should not be able to fetch a {{cookiecutter.model_lower}} list.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) response = self.client.get( "/api/{{cookiecutter.model_url_part}}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -66,7 +66,7 @@ def test_api_{{cookiecutter.model_lower}}_fetch_student(self): """A student should be allowed to fetch a {{cookiecutter.model_lower}}.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = StudentLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = StudentLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) response = self.client.get( f"/api/{{cookiecutter.model_url_part}}/{ {{cookiecutter.model_lower}}.id!s}/", @@ -95,7 +95,7 @@ def test_api_{{cookiecutter.model_lower}}_fetch_from_other_{{cookiecutter.model_ other_{{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = StudentLtiTokenFactory(resource=other_{{cookiecutter.model_lower}}) + jwt_token = StudentLtiTokenFactory(playlist=other_{{cookiecutter.model_lower}}.playlist) response = self.client.get( f"/api/{{cookiecutter.model_url_part}}/{ {{cookiecutter.model_lower}}.id!s}/", @@ -107,7 +107,7 @@ def test_api_{{cookiecutter.model_lower}}_fetch_instructor(self): """An instructor should be able to fetch a {{cookiecutter.model_lower}}.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) response = self.client.get( f"/api/{{cookiecutter.model_url_part}}/{ {{cookiecutter.model_lower}}.id!s}/", @@ -140,7 +140,7 @@ def test_api_{{cookiecutter.model_lower}}_create_student(self): {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() jwt_token = StudentLtiTokenFactory( - resource={{cookiecutter.model_lower}}, + playlist={{cookiecutter.model_lower}}.playlist, permissions__can_update=True, ) @@ -163,7 +163,7 @@ def test_api_{{cookiecutter.model_lower}}_create_instructor(self): """An instructor without playlist token should not be able to create a {{cookiecutter.model_lower}}.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) response = self.client.post( "/api/{{cookiecutter.model_url_part}}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -230,7 +230,7 @@ def test_api_{{cookiecutter.model_lower}}_update_student(self): """A student user should not be able to update a {{cookiecutter.model_lower}}.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = StudentLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = StudentLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) data = {"title": "new title"} response = self.client.patch( @@ -246,7 +246,7 @@ def test_api_{{cookiecutter.model_lower}}_update_instructor_read_only(self): {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource={{cookiecutter.model_lower}}, + playlist={{cookiecutter.model_lower}}.playlist, permissions__can_update=False, ) data = {"title": "new title"} @@ -263,7 +263,7 @@ def test_api_{{cookiecutter.model_lower}}_update_instructor(self): """An instructor should be able to update a {{cookiecutter.model_lower}}.""" {{cookiecutter.model_lower}} = {{cookiecutter.model}}Factory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource={{cookiecutter.model_lower}}) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist={{cookiecutter.model_lower}}.playlist) data = {"title": "new title", "description": "Hello"} response = self.client.patch( diff --git a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_views_lti.py b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_views_lti.py index 3be3330fc0..a442359d2c 100644 --- a/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_views_lti.py +++ b/src/backend/marsha/.cookiecutter/{{cookiecutter.app_name}}/tests/test_views_lti.py @@ -18,7 +18,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.test_views_lti_base import BaseLTIViewForPortabilityTestCase from ..factories import {{cookiecutter.model}}Factory @@ -65,7 +65,7 @@ def test_views_lti_{{cookiecutter.model_lower}}_student(self, mock_get_consumer_ ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "{{cookiecutter.model_plural_lower}}") @@ -153,7 +153,7 @@ def test_views_lti_{{cookiecutter.model_lower}}_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(jwt_token.payload["resource_id"], str({{cookiecutter.model_lower}}.id)) self.assertEqual( jwt_token.payload["user"], diff --git a/src/backend/marsha/account/serializers.py b/src/backend/marsha/account/serializers.py index bd7d46cd1c..d1f16787fe 100644 --- a/src/backend/marsha/account/serializers.py +++ b/src/backend/marsha/account/serializers.py @@ -18,7 +18,7 @@ TokenRefreshSerializer as BaseTokenRefreshSerializer, ) -from marsha.core.simple_jwt.authentication import TokenResource +from marsha.core.simple_jwt.authentication import TokenPlaylist from marsha.core.simple_jwt.tokens import MarshaRefreshToken, UserRefreshToken @@ -79,7 +79,7 @@ def __init__(self, *args, **kwargs): """Instantiate the serializer and make the `TokenUser` to `User` conversion.""" super().__init__(*args, **kwargs) if isinstance(self.user, TokenUser) and not isinstance( - self.user, TokenResource + self.user, TokenPlaylist ): # May raise 500 here but this is not expected so let it raise self.user = get_user_model().objects.get(pk=self.user.pk) diff --git a/src/backend/marsha/account/tests/api/test_password_change.py b/src/backend/marsha/account/tests/api/test_password_change.py index 1a193ed129..80217fbcaa 100644 --- a/src/backend/marsha/account/tests/api/test_password_change.py +++ b/src/backend/marsha/account/tests/api/test_password_change.py @@ -4,7 +4,7 @@ from django.test import TestCase from marsha.core.factories import UserFactory -from marsha.core.simple_jwt.factories import LTIResourceAccessTokenFactory +from marsha.core.simple_jwt.factories import LTIPlaylistAccessTokenFactory from marsha.core.simple_jwt.tokens import UserAccessToken @@ -54,7 +54,7 @@ def test_password_change_wrong_authentication(self): "new_password2": "new_password", } ), - HTTP_AUTHORIZATION=f"Bearer {str(LTIResourceAccessTokenFactory())}", + HTTP_AUTHORIZATION=f"Bearer {str(LTIPlaylistAccessTokenFactory())}", ) self.assertEqual(response.status_code, 401) # Unauthorized diff --git a/src/backend/marsha/account/tests/api/test_token_refresh.py b/src/backend/marsha/account/tests/api/test_token_refresh.py index e0d761d58e..fdddac3835 100644 --- a/src/backend/marsha/account/tests/api/test_token_refresh.py +++ b/src/backend/marsha/account/tests/api/test_token_refresh.py @@ -8,8 +8,8 @@ from marsha.core.factories import UserFactory from marsha.core.simple_jwt.tokens import ( - ResourceAccessToken, - ResourceRefreshToken, + PlaylistAccessToken, + PlaylistRefreshToken, UserAccessToken, UserRefreshToken, ) @@ -86,13 +86,13 @@ def test_success_user_access(self): # ... and new refresh token is not new_refresh_token.verify() - def test_success_resource_access(self): + def test_success_playlist_access(self): """ - A request with a correct resource refresh token should return a 200 with a new token pair. + A request with a correct playlist refresh token should return a 200 with a new token pair. """ session_id = str(uuid.uuid4()) - resource_id = str(uuid.uuid4()) - refresh_token = ResourceRefreshToken.for_resource_id(resource_id, session_id) + playlist_id = str(uuid.uuid4()) + refresh_token = PlaylistRefreshToken.for_playlist_id(playlist_id, session_id) response = self.client.post( "/account/api/token/refresh/", @@ -110,12 +110,12 @@ def test_success_resource_access(self): self.assertIn("refresh", response_data) # Verify tokens - new_token = ResourceAccessToken(response_data["access"]) - new_refresh_token = ResourceRefreshToken(response_data["refresh"]) + new_token = PlaylistAccessToken(response_data["access"]) + new_refresh_token = PlaylistRefreshToken(response_data["refresh"]) - self.assertEqual(new_token.payload["token_type"], "resource_access") + self.assertEqual(new_token.payload["token_type"], "playlist_access") self.assertEqual( - new_refresh_token.payload["access_token_type"], "resource_access" + new_refresh_token.payload["access_token_type"], "playlist_access" ) # Assert old refresh token is blacklisted ... diff --git a/src/backend/marsha/bbb/api.py b/src/backend/marsha/bbb/api.py index 2638cfc3cb..aa9f9a7c80 100644 --- a/src/backend/marsha/bbb/api.py +++ b/src/backend/marsha/bbb/api.py @@ -94,7 +94,7 @@ class ClassroomViewSet( permission_classes = [ ( - core_permissions.IsPlaylistToken + core_permissions.IsPlaylistTokenMatchingRouteObject & (core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin) ) | ( @@ -116,7 +116,7 @@ def get_permissions(self): if self.action in ["create"]: permission_classes = [ ( - core_permissions.HasPlaylistToken + core_permissions.IsPlaylistToken & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -142,8 +142,8 @@ def get_permissions(self): ] elif self.action in ["retrieve", "service_join"]: permission_classes = [ - core_permissions.IsPlaylistToken - | core_permissions.IsTokenResourceRouteObject # needed for invite links + core_permissions.IsPlaylistTokenMatchingRouteObject + | core_permissions.IsTokenPlaylistRouteObject # needed for invite links | ( core_permissions.UserIsAuthenticated # asserts request.resource is None & ( @@ -188,8 +188,8 @@ def get_serializer_context(self): ) # For LTI | ( - core_permissions.ResourceIsAuthenticated - & core_permissions.IsPlaylistToken + core_permissions.PlaylistIsAuthenticated + & core_permissions.IsPlaylistTokenMatchingRouteObject & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -241,7 +241,7 @@ def create(self, request, *args, **kwargs): methods=["get"], detail=False, url_path="lti-select", - permission_classes=[core_permissions.HasPlaylistToken], + permission_classes=[core_permissions.IsPlaylistToken], ) def lti_select(self, request): """Get selectable content for LTI. @@ -263,7 +263,7 @@ def lti_select(self, request): new_url = self.request.build_absolute_uri(LTI_ROUTE) classrooms = serializers.ClassroomSelectLTISerializer( - Classroom.objects.filter(playlist__id=request.resource.playlist_id), + Classroom.objects.filter(playlist__id=request.resource.id), many=True, context={"request": self.request}, ).data @@ -539,7 +539,7 @@ def get_permissions(self): ) ] elif self.action in ["metadata"]: - permission_classes = [core_permissions.UserOrResourceIsAuthenticated] + permission_classes = [core_permissions.UserOrPlaylistIsAuthenticated] else: permission_classes = self.permission_classes return [permission() for permission in permission_classes] diff --git a/src/backend/marsha/bbb/tests/api/classroom/recordings/test_create_vod.py b/src/backend/marsha/bbb/tests/api/classroom/recordings/test_create_vod.py index b0f47ab6f4..fec8fa255a 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/recordings/test_create_vod.py +++ b/src/backend/marsha/bbb/tests/api/classroom/recordings/test_create_vod.py @@ -78,7 +78,7 @@ def test_api_classroom_recording_create_anonymous_unknown_recording(self): def test_api_classroom_recording_create_vod_student(self): """Students should not be able to convert a recording to a VOD.""" recording = ClassroomRecordingFactory() - jwt_token = StudentLtiTokenFactory(resource=recording.classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=recording.classroom.playlist) with mock.patch("marsha.bbb.api.invoke_lambda_convert"): response = self.client.post( @@ -100,7 +100,7 @@ def test_api_classroom_recording_create_vod_instructor_or_admin(self): started_at="2019-08-21T15:00:02Z", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=recording.classroom.playlist + playlist=recording.classroom.playlist ) self.assertEqual(Video.objects.count(), 0) @@ -155,7 +155,7 @@ def test_api_classroom_recording_create_vod_instructor_or_admin_unknown_recordin started_at="2019-08-21T15:00:02Z", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=recording.classroom.playlist + playlist=recording.classroom.playlist ) self.assertEqual(Video.objects.count(), 0) @@ -372,7 +372,7 @@ def test_api_classroom_recording_create_vod_instructor_or_admin_inactive_convers classroom__playlist__consumer_site__inactive_features=["vod_convert"], ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=recording.classroom.playlist + playlist=recording.classroom.playlist ) self.assertEqual(Video.objects.count(), 0) diff --git a/src/backend/marsha/bbb/tests/api/classroom/recordings/test_delete.py b/src/backend/marsha/bbb/tests/api/classroom/recordings/test_delete.py index 9cb5f2e775..f2d25bc10a 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/recordings/test_delete.py +++ b/src/backend/marsha/bbb/tests/api/classroom/recordings/test_delete.py @@ -68,7 +68,7 @@ def test_api_delete_classroom_recording_anonymous(self, delete_recording_mock): def test_api_delete_classroom_recording_student(self, delete_recording_mock): """Students should not be able to delete a recording.""" recording = ClassroomRecordingFactory() - jwt_token = StudentLtiTokenFactory(resource=recording.classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=recording.classroom.playlist) self.assertEqual(ClassroomRecording.objects.count(), 1) response = self.client.delete( @@ -94,7 +94,7 @@ def test_api_delete_classroom_recording_instructor_or_admin( started_at="2019-08-21T15:00:02Z", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=recording.classroom.playlist + playlist=recording.classroom.playlist ) self.assertEqual(ClassroomRecording.objects.count(), 1) diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_bulk_destroy.py b/src/backend/marsha/bbb/tests/api/classroom/test_bulk_destroy.py index aaab0d437e..046663f892 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_bulk_destroy.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_bulk_destroy.py @@ -13,7 +13,6 @@ from marsha.core.models import ADMINISTRATOR, INSTRUCTOR, STUDENT from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -52,28 +51,7 @@ def test_api_classroom_bulk_delete_student(self): classroom2 = ClassroomFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom1.playlist, - permissions__can_update=True, - ) - - response = self.client.delete( - self._api_url(), - {"ids": [str(classroom1.pk), str(classroom2.pk)]}, - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - content_type="application/json", - ) - self.assertEqual(response.status_code, 403) - content = json.loads(response.content) - self.assertEqual( - content, {"detail": "You do not have permission to perform this action."} - ) - - def test_api_classroom_bulk_delete_student_with_playlist_token(self): - """LTI Token can't delete a list of classroom.""" - classroom1 = ClassroomFactory() - classroom2 = ClassroomFactory() - jwt_token = PlaylistLtiTokenFactory( - roles=["student"], + playlist=classroom1.playlist, permissions__can_update=True, ) @@ -93,7 +71,7 @@ def test_api_classroom_bulk_delete_instructor(self): """LTI Token can't delete a list of classroom.""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.delete( self._api_url(), @@ -107,30 +85,6 @@ def test_api_classroom_bulk_delete_instructor(self): content, {"detail": "You do not have permission to perform this action."} ) - def test_api_classroom_bulk_delete_instructor_with_playlist_token(self): - """LTI Token can't delete a list of classroom.""" - - playlist = PlaylistFactory() - classroom = ClassroomFactory(playlist=playlist) - - jwt_token = PlaylistLtiTokenFactory(resource=classroom.playlist) - - self.assertEqual(Classroom.objects.count(), 1) - - response = self.client.delete( - self._api_url(), - {"ids": [str(classroom.pk)]}, - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - content_type="application/json", - ) - - self.assertEqual(response.status_code, 403) - self.assertEqual(Classroom.objects.count(), 1) - content = json.loads(response.content) - self.assertEqual( - content, {"detail": "You do not have permission to perform this action."} - ) - def test_api_classroom_bulk_delete_user_access_token(self): """LTI Token can't delete a list of classroom.""" organization_access = OrganizationAccessFactory() diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_classroomdocuments.py b/src/backend/marsha/bbb/tests/api/classroom/test_classroomdocuments.py index e2f9686321..8f9af309e9 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_classroomdocuments.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_classroomdocuments.py @@ -49,7 +49,7 @@ def test_api_list_classroom_documents_student(self): """A student should not be able to fetch a list of classroom documents.""" classroom = ClassroomFactory() ClassroomDocumentFactory.create_batch(3, classroom=classroom) - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id}/classroomdocuments/", @@ -63,7 +63,7 @@ def test_api_list_classroom_documents_instructor(self): classroom_documents = ClassroomDocumentFactory.create_batch( 3, classroom=classroom ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id}/classroomdocuments/?limit=2", @@ -118,7 +118,7 @@ def test_api_list_classroom_documents_instructor_urls(self): uploaded_on=now, ) ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id}/classroomdocuments/", diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_create.py b/src/backend/marsha/bbb/tests/api/classroom/test_create.py index 998333d922..f461a2fe31 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_create.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_create.py @@ -15,7 +15,6 @@ from marsha.core.models import ADMINISTRATOR, INSTRUCTOR from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -51,7 +50,7 @@ def test_api_classroom_create_student(self): classroom = ClassroomFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom.playlist, + playlist=classroom.playlist, permissions__can_update=True, ) @@ -60,39 +59,9 @@ def test_api_classroom_create_student(self): ) self.assertEqual(response.status_code, 403) - def test_api_classroom_create_student_with_playlist_token(self): - """A student with a playlist token should not be able to create a classroom.""" - jwt_token = PlaylistLtiTokenFactory( - roles=["student"], - permissions__can_update=True, - ) - - response = self.client.post( - "/api/classrooms/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - self.assertEqual(Classroom.objects.count(), 0) - - def test_api_classroom_create_instructor(self): - """An instructor without playlist token should not be able to create a classroom.""" - classroom = ClassroomFactory() - - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) - - response = self.client.post( - "/api/classrooms/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - @mock.patch.object(serializers, "get_meeting_infos") - def test_api_classroom_create_instructor_with_playlist_token( - self, mock_get_meeting_infos - ): - """ - Create classroom with playlist token. - - Used in the context of a lti select request (deep linking). - """ + def test_api_classroom_create_instructor(self, mock_get_meeting_infos): + """An instructor should be able to create a classroom.""" playlist = core_factories.PlaylistFactory() mock_get_meeting_infos.return_value = { @@ -100,7 +69,7 @@ def test_api_classroom_create_instructor_with_playlist_token( "running": "true", } - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(Classroom.objects.count(), 0) diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_delete.py b/src/backend/marsha/bbb/tests/api/classroom/test_delete.py index fb9e39e247..ef3e8144df 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_delete.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_delete.py @@ -17,7 +17,6 @@ from marsha.core.models import ADMINISTRATOR from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -46,20 +45,7 @@ def test_api_classroom_delete_student(self): classroom = ClassroomFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom.playlist, - permissions__can_update=True, - ) - - response = self.client.delete( - f"/api/classrooms/{classroom.id}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - - def test_api_classroom_delete_student_with_playlist_token(self): - """A student with a playlist token should not be able to delete a classroom.""" - classroom = ClassroomFactory() - jwt_token = PlaylistLtiTokenFactory( - roles=["student"], + playlist=classroom.playlist, permissions__can_update=True, ) @@ -72,31 +58,13 @@ def test_api_classroom_delete_instructor(self): """An instructor without playlist token should not be able to delete a classroom.""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.delete( f"/api/classrooms/{classroom.id}/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" ) self.assertEqual(response.status_code, 403) - def test_api_classroom_delete_instructor_with_playlist_token(self): - """ - Delete classroom with playlist token should not be permitted in LTI. - """ - playlist = PlaylistFactory() - classroom = ClassroomFactory(playlist=playlist) - - jwt_token = PlaylistLtiTokenFactory(resource=classroom.playlist) - - self.assertEqual(Classroom.objects.count(), 1) - - response = self.client.delete( - f"/api/classrooms/{classroom.id}/", - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - ) - - self.assertEqual(response.status_code, 403) - def test_api_classroom_delete_user_access_token(self): """A user with UserAccessToken should not be able to delete a classroom.""" organization_access = OrganizationAccessFactory() diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_invite_token.py b/src/backend/marsha/bbb/tests/api/classroom/test_invite_token.py index afd87db018..a10cdeb42f 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_invite_token.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_invite_token.py @@ -5,7 +5,7 @@ from marsha.bbb.factories import ClassroomFactory from marsha.core.models import INSTRUCTOR, NONE -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.testing_utils import reload_urlconf @@ -52,8 +52,10 @@ def test_invite_public_token(self): self.assertEqual(response.status_code, 200) public_token = response.json().get("access_token") - decoded_public_token = ResourceAccessToken(public_token) - self.assertEqual(decoded_public_token.payload["resource_id"], str(classroom.id)) + decoded_public_token = PlaylistAccessToken(public_token) + self.assertEqual( + decoded_public_token.payload["playlist_id"], str(classroom.playlist_id) + ) self.assertEqual(decoded_public_token.payload["roles"], [NONE]) self.assertEqual( decoded_public_token.payload["permissions"], @@ -71,9 +73,9 @@ def test_invite_instructor_token(self): self.assertEqual(response.status_code, 200) instructor_token = response.json().get("access_token") - decoded_instructor_token = ResourceAccessToken(instructor_token) + decoded_instructor_token = PlaylistAccessToken(instructor_token) self.assertEqual( - decoded_instructor_token.payload["resource_id"], str(classroom.id) + decoded_instructor_token.payload["playlist_id"], str(classroom.playlist_id) ) self.assertEqual(decoded_instructor_token.payload["roles"], [INSTRUCTOR]) self.assertEqual( diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_list.py b/src/backend/marsha/bbb/tests/api/classroom/test_list.py index bcd9916259..f1a9d3b777 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_list.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_list.py @@ -46,7 +46,7 @@ def test_api_classroom_fetch_list_student(self): classroom = ClassroomFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom.playlist, + playlist=classroom.playlist, permissions__can_update=True, ) @@ -59,7 +59,7 @@ def test_api_fetch_list_instructor(self): """An instructor should not be able to fetch a classroom list.""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( "/api/classrooms/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_lti_select.py b/src/backend/marsha/bbb/tests/api/classroom/test_lti_select.py index 9ff62aa89b..cc01a08f97 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_lti_select.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_lti_select.py @@ -4,7 +4,7 @@ from marsha.bbb.factories import ClassroomFactory from marsha.core import factories as core_factories -from marsha.core.simple_jwt.factories import PlaylistLtiTokenFactory +from marsha.core.simple_jwt.factories import InstructorOrAdminLtiTokenFactory from marsha.core.tests.testing_utils import reload_urlconf @@ -31,7 +31,7 @@ def test_api_select_instructor_no_bbb_server(self): """An instructor should be able to fetch a classroom lti select.""" playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) response = self.client.get( "/api/classrooms/lti-select/", @@ -50,7 +50,7 @@ def test_api_select_instructor_no_classrooms(self): """An instructor should be able to fetch a classroom lti select.""" playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) response = self.client.get( "/api/classrooms/lti-select/", @@ -69,7 +69,7 @@ def test_api_select_instructor(self): """An instructor should be able to fetch a classroom lti select.""" classroom = ClassroomFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( "/api/classrooms/lti-select/", diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_retrieve.py b/src/backend/marsha/bbb/tests/api/classroom/test_retrieve.py index bef73f488f..41d0b6b1b5 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_retrieve.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_retrieve.py @@ -51,7 +51,7 @@ def test_api_classroom_fetch_student(self, mock_get_meeting_infos): "running": "true", } - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -109,7 +109,7 @@ def test_api_classroom_fetch_student_with_recordings(self, mock_get_meeting_info "running": "true", } - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -158,7 +158,7 @@ def test_api_classroom_fetch_from_other_classroom(self): classroom = ClassroomFactory() other_classroom = ClassroomFactory() - jwt_token = StudentLtiTokenFactory(resource=other_classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=other_classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -183,7 +183,7 @@ def test_api_classroom_fetch_student_scheduled(self, mock_get_meeting_infos): "running": "true", } - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -233,7 +233,7 @@ def test_api_classroom_fetch_instructor(self, mock_get_meeting_infos): "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -474,7 +474,7 @@ def test_api_classroom_fetch_with_recordings(self, mock_get_meeting_infos): "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -546,7 +546,7 @@ def test_api_classroom_fetch_from_LTI_inactive_conversion( "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.get( f"/api/classrooms/{classroom.id!s}/", @@ -678,8 +678,8 @@ def test_api_classroom_fetch_moderator_invite(self, mock_get_meeting_infos): }, "starting_at": None, "estimated_duration": None, - "public_token": None, - "instructor_token": None, + "public_token": classroom.public_token, + "instructor_token": classroom.instructor_token, "recordings": [], "retention_date": None, "enable_waiting_room": False, diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_service_create.py b/src/backend/marsha/bbb/tests/api/classroom/test_service_create.py index 463f0143f5..ac7a084957 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_service_create.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_service_create.py @@ -67,7 +67,7 @@ def test_api_bbb_create_student(self, mock_create_request): """A student should not be able to create a classroom.""" classroom = ClassroomFactory() - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.patch( f"/api/classrooms/{classroom.id}/create/", @@ -86,7 +86,7 @@ def test_api_bbb_create_new_classroom( mock_get_meeting_infos.return_value = {"returncode": "SUCCESS"} mock_create_request.return_value = {"returncode": "SUCCESS"} - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) data = {"title": "new title", "welcome_text": "Hello"} response = self.client.patch( @@ -126,7 +126,7 @@ def test_api_bbb_create_existing_classroom( {"message": "A classroom already exists with that classroom ID."} ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) data = {"title": classroom.title, "welcome_text": classroom.welcome_text} response = self.client.patch( diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_service_end.py b/src/backend/marsha/bbb/tests/api/classroom/test_service_end.py index db175688e0..6e7ef21d2d 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_service_end.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_service_end.py @@ -70,7 +70,7 @@ def test_api_bbb_end_classroom_student(self, mock_end_request): """A student should not be able to end a classroom.""" classroom = ClassroomFactory() - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.patch( f"/api/classrooms/{classroom.id}/end/", @@ -92,7 +92,7 @@ def test_api_bbb_end_classroom_instructor(self, mock_end_request): "returncode": "SUCCESS", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.patch( f"/api/classrooms/{classroom.id}/end/", diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_service_join.py b/src/backend/marsha/bbb/tests/api/classroom/test_service_join.py index 1fd3bfd79d..c38eb9c1df 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_service_join.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_service_join.py @@ -76,7 +76,7 @@ def test_api_bbb_join_student(self): ) jwt_token = StudentLtiTokenFactory( - resource=classroom.playlist, + playlist=classroom.playlist, consumer_site="consumer_site", user__id="user_id", ) @@ -106,7 +106,7 @@ def test_api_bbb_join_from_other_classroom(self): other_classroom = ClassroomFactory() jwt_token = StudentLtiTokenFactory( - resource=other_classroom.playlist, + playlist=other_classroom.playlist, consumer_site="consumer_site", user__id="user_id", ) @@ -127,7 +127,7 @@ def test_api_bbb_join_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom.playlist, + playlist=classroom.playlist, consumer_site="consumer_site", user__id="user_id", ) @@ -153,7 +153,7 @@ def test_api_bbb_join_instructor_no_fullname(self): title="Classroom 1", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.patch( f"/api/classrooms/{classroom.id}/join/", diff --git a/src/backend/marsha/bbb/tests/api/classroom/test_update.py b/src/backend/marsha/bbb/tests/api/classroom/test_update.py index 4318f14420..9e379f7625 100644 --- a/src/backend/marsha/bbb/tests/api/classroom/test_update.py +++ b/src/backend/marsha/bbb/tests/api/classroom/test_update.py @@ -64,7 +64,7 @@ def test_api_classroom_update_student(self): """A student user should not be able to update a classroom.""" classroom = ClassroomFactory() - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) data = {"title": "new title"} @@ -81,7 +81,7 @@ def test_api_classroom_update_instructor_read_only(self): classroom = ClassroomFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom.playlist, + playlist=classroom.playlist, permissions__can_update=False, ) data = {"title": "new title"} @@ -104,7 +104,7 @@ def test_api_classroom_update_instructor(self, mock_get_meeting_infos): "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) data = {"title": "new title", "welcome_text": "Hello"} response = self.client.patch( @@ -129,7 +129,7 @@ def test_api_classroom_update_instructor_scheduling(self, mock_get_meeting_infos "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) now = datetime(2018, 8, 8, tzinfo=zoneinfo.ZoneInfo("Europe/Paris")) # set microseconds to 0 to compare date surely as serializer truncate them @@ -203,7 +203,7 @@ def test_api_classroom_update_instructor_scheduling_past_date( "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) now = datetime(2018, 8, 8, tzinfo=zoneinfo.ZoneInfo("Europe/Paris")) # set microseconds to 0 to compare date surely as serializer truncate them @@ -250,7 +250,7 @@ def test_api_classroom_update_put_instructor_scheduling( "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) # set microseconds to 0 to compare date surely as serializer truncate them starting_at = (now + timedelta(hours=1)).replace(microsecond=0) @@ -321,7 +321,7 @@ def test_api_classroom_update_starting_at_ended(self, mock_get_meeting_infos): "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) # set microseconds to 0 to compare date surely as serializer truncate them starting_at = (now + timedelta(hours=1)).replace(microsecond=0) @@ -350,7 +350,7 @@ def test_api_classroom_update_estimated_duration_ended( "running": "true", } - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) estimated_duration = timedelta(seconds=60) data = {"estimated_duration": estimated_duration} diff --git a/src/backend/marsha/bbb/tests/api/classroomdocument/test_create.py b/src/backend/marsha/bbb/tests/api/classroomdocument/test_create.py index ac9cc952b9..f8f744f203 100644 --- a/src/backend/marsha/bbb/tests/api/classroomdocument/test_create.py +++ b/src/backend/marsha/bbb/tests/api/classroomdocument/test_create.py @@ -43,7 +43,7 @@ def test_api_classroom_document_create_student(self): """ classroom = ClassroomFactory() - jwt_token = StudentLtiTokenFactory(resource=classroom.playlist) + jwt_token = StudentLtiTokenFactory(playlist=classroom.playlist) response = self.client.post( f"/api/classrooms/{classroom.id}/classroomdocuments/", @@ -69,7 +69,7 @@ def test_api_classroom_document_create_instructor_first_document(self): First created document should be the default one. """ classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.post( f"/api/classrooms/{classroom.id}/classroomdocuments/", @@ -110,7 +110,7 @@ def test_api_classroom_document_create_instructor_second_document(self): classroom=classroom, is_default=True, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.post( f"/api/classrooms/{classroom.id}/classroomdocuments/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -346,7 +346,7 @@ def test_api_classroom_document_create_user_access_token_admin_other_playlist(se def test_api_classroom_document_create_file_too_large(self): """With a file size too large the request should fail""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.post( f"/api/classrooms/{classroom.id}/classroomdocuments/", @@ -370,7 +370,7 @@ def test_api_classroom_document_create_file_too_large(self): def test_api_classroom_document_create_file_no_size(self): """Without file size the request should fail""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.post( f"/api/classrooms/{classroom.id}/classroomdocuments/", diff --git a/src/backend/marsha/bbb/tests/api/classroomdocument/test_delete.py b/src/backend/marsha/bbb/tests/api/classroomdocument/test_delete.py index 82139e4c82..57be64c41b 100644 --- a/src/backend/marsha/bbb/tests/api/classroomdocument/test_delete.py +++ b/src/backend/marsha/bbb/tests/api/classroomdocument/test_delete.py @@ -42,7 +42,7 @@ def test_api_classroom_document_delete_student(self): classroom_document = ClassroomDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) self.assertEqual(ClassroomDocument.objects.count(), 1) @@ -63,7 +63,7 @@ def test_api_classroom_document_delete_instructor_document(self): """ classroom_document = ClassroomDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) self.assertEqual(ClassroomDocument.objects.count(), 1) @@ -97,7 +97,7 @@ def test_api_classroom_document_delete_instructor_first_document(self): classroom=classroom, is_default=False, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) self.assertEqual(ClassroomDocument.objects.count(), 3) response = self.client.delete( @@ -127,7 +127,7 @@ def test_api_classroom_document_delete_instructor_second_document(self): classroom=classroom, is_default=False, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) self.assertEqual(ClassroomDocument.objects.count(), 2) response = self.client.delete( diff --git a/src/backend/marsha/bbb/tests/api/classroomdocument/test_initiate_upload.py b/src/backend/marsha/bbb/tests/api/classroomdocument/test_initiate_upload.py index d925f1d6e7..fba3165bf0 100644 --- a/src/backend/marsha/bbb/tests/api/classroomdocument/test_initiate_upload.py +++ b/src/backend/marsha/bbb/tests/api/classroomdocument/test_initiate_upload.py @@ -48,7 +48,7 @@ def test_api_classroom_document_initiate_upload_instructor(self): classroom__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -107,7 +107,7 @@ def test_api_classroom_document_initiate_upload_instructor_without_extension(sel classroom__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -166,7 +166,7 @@ def test_api_classroom_document_initiate_upload_instructor_without_mimetype(self classroom__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -197,7 +197,7 @@ def test_api_classroom_document_initiate_upload_instructor_wrong_mimetype(self): classroom__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -476,7 +476,7 @@ def test_api_classroom_document_initiate_upload_file_too_large(self): classroom__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) diff --git a/src/backend/marsha/bbb/tests/api/classroomdocument/test_options.py b/src/backend/marsha/bbb/tests/api/classroomdocument/test_options.py index 712172a153..2bc0b95e18 100644 --- a/src/backend/marsha/bbb/tests/api/classroomdocument/test_options.py +++ b/src/backend/marsha/bbb/tests/api/classroomdocument/test_options.py @@ -47,7 +47,7 @@ def test_api_classroom_document_options_as_student(self): classroom_document = ClassroomDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) response = self.client.options( f"/api/classrooms/{classroom_document.classroom.id}/classroomdocuments/", @@ -60,7 +60,7 @@ def test_api_classroom_document_options_instructor(self): """An instructor can fetch the classroom document options endpoint""" classroom = ClassroomFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) response = self.client.options( f"/api/classrooms/{classroom.id}/classroomdocuments/", diff --git a/src/backend/marsha/bbb/tests/api/classroomdocument/test_update.py b/src/backend/marsha/bbb/tests/api/classroomdocument/test_update.py index 66b2076114..f9294ef40b 100644 --- a/src/backend/marsha/bbb/tests/api/classroomdocument/test_update.py +++ b/src/backend/marsha/bbb/tests/api/classroomdocument/test_update.py @@ -40,7 +40,7 @@ def test_api_classroom_document_update_student(self): """A student user should not be able to update a classroom_document.""" classroom_document = ClassroomDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) data = {"filename": "updated_name.pdf", "size": 100} @@ -57,7 +57,7 @@ def test_api_classroom_document_update_instructor(self): """An instructor should be able to update a classroom_document.""" classroom_document = ClassroomDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=classroom_document.classroom.playlist + playlist=classroom_document.classroom.playlist ) data = {"filename": "updated_name.pdf", "size": 100} @@ -90,7 +90,7 @@ def test_api_classroom_document_update_instructor_default(self): is_default=True, ) second_document = ClassroomDocumentFactory(classroom=classroom) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=classroom.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=classroom.playlist) data = {"is_default": True} response = self.client.patch( diff --git a/src/backend/marsha/bbb/tests/test_utils_tokens.py b/src/backend/marsha/bbb/tests/test_utils_tokens.py index 2ef1c4d0cc..10caf36ea6 100644 --- a/src/backend/marsha/bbb/tests/test_utils_tokens.py +++ b/src/backend/marsha/bbb/tests/test_utils_tokens.py @@ -39,10 +39,10 @@ def test_jwt_content_starting_at_and_duration(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["none"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -68,10 +68,10 @@ def test_jwt_content_starting_at_in_past(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["none"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -96,10 +96,10 @@ def test_jwt_content_starting_at_and_no_duration(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["none"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -127,10 +127,10 @@ def test_jwt_content_without_starting_at_and_no_duration(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["none"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -154,10 +154,10 @@ def test_jwt_content_without_starting_at_and_duration(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["none"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -186,10 +186,10 @@ def test_jwt_content_without_starting_at_and_no_duration_instructor(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["instructor"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -214,10 +214,10 @@ def test_jwt_content_without_starting_at_and_duration_instructor(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["instructor"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) @@ -277,10 +277,10 @@ def test_jwt_content_instructor(self): "locale": "en_US", "maintenance": False, "permissions": {"can_access_dashboard": False, "can_update": False}, - "resource_id": "ad0395fd-3023-45da-8801-93d1ce64acd5", + "playlist_id": str(classroom.playlist_id), "roles": ["instructor"], "session_id": "ad0395fd-3023-45da-8801-93d1ce64acd5-invite", - "token_type": "resource_access", + "token_type": "playlist_access", }, ) diff --git a/src/backend/marsha/bbb/tests/test_views_lti.py b/src/backend/marsha/bbb/tests/test_views_lti.py index e4b3aeef62..a48079a77f 100644 --- a/src/backend/marsha/bbb/tests/test_views_lti.py +++ b/src/backend/marsha/bbb/tests/test_views_lti.py @@ -21,7 +21,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.testing_utils import reload_urlconf from marsha.core.tests.views.test_lti_base import BaseLTIViewForPortabilityTestCase @@ -98,7 +98,7 @@ def test_views_lti_classroom_student(self, mock_get_consumer_site, mock_verify): ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "classrooms") @@ -249,8 +249,8 @@ def test_views_lti_classroom_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], str(classroom.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], str(classroom.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -437,7 +437,7 @@ def test_views_lti_classroom_student(self, mock_get_consumer_site, mock_verify): ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "classrooms") @@ -588,8 +588,8 @@ def test_views_lti_classroom_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], str(classroom.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], str(classroom.playlist.id)) self.assertEqual( jwt_token.payload["user"], { diff --git a/src/backend/marsha/bbb/utils/tokens.py b/src/backend/marsha/bbb/utils/tokens.py index 96ad2f686d..519ac3ef2b 100644 --- a/src/backend/marsha/bbb/utils/tokens.py +++ b/src/backend/marsha/bbb/utils/tokens.py @@ -5,11 +5,11 @@ from django.utils import timezone from marsha.core.models import INSTRUCTOR, NONE -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken def create_classroom_stable_invite_jwt(classroom, role=NONE, permissions=None): - """Create a resource JWT to be used in classroom invite links. + """Create a playlist JWT to be used in classroom invite links. Parameters ---------- @@ -24,24 +24,24 @@ def create_classroom_stable_invite_jwt(classroom, role=NONE, permissions=None): Returns ------- - ResourceAccessToken + PlaylistAccessToken The JWT. """ - resource_jwt = ResourceAccessToken.for_resource_id( - resource_id=str(classroom.id), + playlist_jwt = PlaylistAccessToken.for_playlist_id( + playlist_id=str(classroom.playlist_id), session_id=f"{classroom.id}-invite", roles=[role], permissions=permissions or {}, ) # Set a fixed JWT ID - resource_jwt.set_jti( + playlist_jwt.set_jti( f"classroom-invite-{classroom.id}-{classroom.created_on.strftime('%Y-%m-%d')}" ) # Set a fixed validity beginning: the classroom creation date - resource_jwt.set_iat(at_time=classroom.created_on) + playlist_jwt.set_iat(at_time=classroom.created_on) duration = settings.BBB_INVITE_JWT_DEFAULT_DAYS_DURATION if role == INSTRUCTOR: @@ -50,9 +50,9 @@ def create_classroom_stable_invite_jwt(classroom, role=NONE, permissions=None): hour=0, minute=0, second=0, microsecond=0 ) + timedelta(days=duration) - resource_jwt.set_exp( + playlist_jwt.set_exp( from_time=classroom.created_on, lifetime=validity_end - classroom.created_on, ) - return resource_jwt + return playlist_jwt diff --git a/src/backend/marsha/core/api/base.py b/src/backend/marsha/core/api/base.py index d949dbff9f..9de6eb6129 100644 --- a/src/backend/marsha/core/api/base.py +++ b/src/backend/marsha/core/api/base.py @@ -12,7 +12,7 @@ from ..defaults import SENTRY, VOD_CONVERT from ..models import SiteConfig, Video from ..signals import signal_object_uploaded -from ..simple_jwt.tokens import ResourceAccessToken +from ..simple_jwt.tokens import PlaylistAccessToken from ..utils.api_utils import get_uploadable_models_s3_mapping, validate_signature @@ -278,7 +278,7 @@ def check_permissions(self, request): we keep it as a TokenResource... """ request.resource = None - if isinstance(request.auth, ResourceAccessToken): # otherwise, nothing to do + if isinstance(request.auth, PlaylistAccessToken): # otherwise, nothing to do request.resource = request.user super().check_permissions(request) diff --git a/src/backend/marsha/core/api/file.py b/src/backend/marsha/core/api/file.py index 376d8966a7..a1cae34fcb 100644 --- a/src/backend/marsha/core/api/file.py +++ b/src/backend/marsha/core/api/file.py @@ -26,7 +26,7 @@ class DocumentViewSet( queryset = Document.objects.all() serializer_class = serializers.DocumentSerializer permission_classes = [ - permissions.IsPlaylistToken + permissions.IsPlaylistTokenMatchingRouteObject & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) ] @@ -38,7 +38,7 @@ def get_permissions(self): """ if self.action in ["create"]: permission_classes = [ - permissions.HasPlaylistToken + permissions.IsPlaylistToken & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) ] else: diff --git a/src/backend/marsha/core/api/live_session.py b/src/backend/marsha/core/api/live_session.py index a9423389c9..26ffac0c1e 100644 --- a/src/backend/marsha/core/api/live_session.py +++ b/src/backend/marsha/core/api/live_session.py @@ -89,10 +89,10 @@ class LiveSessionViewSet( def get_permissions(self): """Instantiate and return the list of permissions that this view requires.""" if self.action in ["list"]: - permission_classes = [permissions.UserOrResourceIsAuthenticated] + permission_classes = [permissions.UserOrPlaylistIsAuthenticated] elif self.action in ["create", "set_display_name", "push_attendance"]: permission_classes = [ - permissions.ResourceIsAuthenticated + permissions.PlaylistIsAuthenticated | permissions.IsParamsVideoAdminThroughOrganization | permissions.BaseIsParamsVideoRoleThroughPlaylist ] @@ -101,7 +101,7 @@ def get_permissions(self): "retrieve", ]: permission_classes = [ - permissions.IsTokenResourceRouteObjectRelatedVideo + permissions.IsTokenPlaylistRouteObjectRelatedVideo | permissions.IsParamsVideoAdminThroughOrganization | permissions.BaseIsParamsVideoRoleThroughPlaylist ] diff --git a/src/backend/marsha/core/api/playlist.py b/src/backend/marsha/core/api/playlist.py index 8521e1e329..28636c4a90 100644 --- a/src/backend/marsha/core/api/playlist.py +++ b/src/backend/marsha/core/api/playlist.py @@ -77,7 +77,7 @@ def get_permissions(self): # requests made with a JWT token granting instructor or administrator (permissions.IsTokenInstructor | permissions.IsTokenAdmin) # and to an object related to the playlist - & permissions.IsTokenResourceRouteObjectRelatedPlaylist + & permissions.IsTokenPlaylistRouteObjectRelatedPlaylist ) ] elif self.action in ["claim"]: @@ -99,7 +99,7 @@ def get_permissions(self): # requests made with a JWT token granting instructor or administrator (permissions.IsTokenInstructor | permissions.IsTokenAdmin) # and to an object related to the playlist - & permissions.IsTokenResourceRouteObjectRelatedPlaylist + & permissions.IsTokenPlaylistRouteObjectRelatedPlaylist ) ] elif self.action in ["destroy"]: diff --git a/src/backend/marsha/core/api/portability_request.py b/src/backend/marsha/core/api/portability_request.py index f7255cd956..9e3a290d94 100644 --- a/src/backend/marsha/core/api/portability_request.py +++ b/src/backend/marsha/core/api/portability_request.py @@ -20,10 +20,10 @@ HasPlaylistAdministratorAccess, HasPlaylistConsumerSiteAdministratorAccess, HasPlaylistOrganizationAdministratorAccess, - HasPlaylistToken, IsPlaylistOwner, IsPortabilityRequestOwner, NotAllowed, + PortToPlaylistExists, UserIsAuthenticated, ) from ..serializers import PortabilityRequestSerializer @@ -64,7 +64,7 @@ def get_permissions(self): Only the `create` view is available from LTI. """ if self.action in ["create"]: - permission_classes = [HasPlaylistToken] + permission_classes = [PortToPlaylistExists] elif self.action in ["destroy"]: permission_classes = [UserIsAuthenticated & IsPortabilityRequestOwner] elif self.action in ["retrieve"]: diff --git a/src/backend/marsha/core/api/shared_live_media.py b/src/backend/marsha/core/api/shared_live_media.py index 361398b493..aea137a079 100644 --- a/src/backend/marsha/core/api/shared_live_media.py +++ b/src/backend/marsha/core/api/shared_live_media.py @@ -76,13 +76,13 @@ def get_permissions(self): ] elif self.action in ["retrieve"]: permission_classes = [ - permissions.IsTokenResourceRouteObjectRelatedVideo + permissions.IsTokenPlaylistRouteObjectRelatedVideo | permissions.IsRelatedVideoPlaylistAdminOrInstructor | permissions.IsRelatedVideoOrganizationAdmin ] elif self.action in ["destroy", "initiate_upload", "update", "partial_update"]: permission_classes = [ - permissions.IsTokenResourceRouteObjectRelatedVideo + permissions.IsTokenPlaylistRouteObjectRelatedVideo & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) | permissions.IsRelatedVideoPlaylistAdminOrInstructor | permissions.IsRelatedVideoOrganizationAdmin diff --git a/src/backend/marsha/core/api/thumbnail.py b/src/backend/marsha/core/api/thumbnail.py index 59ef6c6cfa..49a0f13ad1 100644 --- a/src/backend/marsha/core/api/thumbnail.py +++ b/src/backend/marsha/core/api/thumbnail.py @@ -59,7 +59,7 @@ class ThumbnailViewSet( def get_permissions(self): """Instantiate and return the list of permissions that this view requires.""" if self.action == "metadata": - permission_classes = [permissions.UserOrResourceIsAuthenticated] + permission_classes = [permissions.UserOrPlaylistIsAuthenticated] elif self.action in ["create", "list"]: permission_classes = [ permissions.IsTokenInstructor @@ -69,7 +69,7 @@ def get_permissions(self): ] elif self.action in ["retrieve", "destroy", "initiate_upload"]: permission_classes = [ - permissions.IsPlaylistToken + permissions.IsPlaylistTokenMatchingRouteObject & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) | permissions.IsRelatedVideoPlaylistAdminOrInstructor | permissions.IsRelatedVideoOrganizationAdmin diff --git a/src/backend/marsha/core/api/timed_text_track.py b/src/backend/marsha/core/api/timed_text_track.py index 0fb8d4b1fd..7cc93aa6b9 100644 --- a/src/backend/marsha/core/api/timed_text_track.py +++ b/src/backend/marsha/core/api/timed_text_track.py @@ -55,7 +55,7 @@ class TimedTextTrackViewSet( def get_permissions(self): """Instantiate and return the list of permissions that this view requires.""" if self.action == "metadata": - permission_classes = [permissions.UserOrResourceIsAuthenticated] + permission_classes = [permissions.UserOrPlaylistIsAuthenticated] elif self.action in ["create", "list"]: permission_classes = [ permissions.IsTokenInstructor @@ -71,7 +71,7 @@ def get_permissions(self): "partial_update", ]: permission_classes = [ - permissions.IsTokenResourceRouteObjectRelatedVideo + permissions.IsTokenPlaylistRouteObjectRelatedVideo & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) | permissions.IsRelatedVideoPlaylistAdminOrInstructor | permissions.IsRelatedVideoOrganizationAdmin diff --git a/src/backend/marsha/core/api/video.py b/src/backend/marsha/core/api/video.py index d07e11fd6d..6cb648e71b 100644 --- a/src/backend/marsha/core/api/video.py +++ b/src/backend/marsha/core/api/video.py @@ -133,7 +133,7 @@ def get_permissions(self): # `VideoConsumer` websocket consumer. permission_classes = [ # With LTI: anyone with a valid token for the video can access - permissions.IsPlaylistToken + permissions.IsPlaylistTokenMatchingRouteObject # With standalone site, only playlist admin or organization admin can access | permissions.IsObjectPlaylistAdminOrInstructor | permissions.IsObjectPlaylistOrganizationAdmin @@ -141,7 +141,7 @@ def get_permissions(self): elif self.action in ["list", "metadata"]: # Anyone authenticated can list videos (results are filtered in action) # or access metadata - permission_classes = [permissions.UserOrResourceIsAuthenticated] + permission_classes = [permissions.UserOrPlaylistIsAuthenticated] elif self.action in ["create"]: permission_classes = [ # With standalone site, only playlist admin or organization admin can access @@ -149,7 +149,7 @@ def get_permissions(self): | permissions.IsParamsPlaylistAdminThroughOrganization # With LTI: playlist admin or instructor admin can access | ( - permissions.HasPlaylistToken + permissions.IsPlaylistToken & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) ) ] @@ -167,7 +167,7 @@ def get_permissions(self): permission_classes = [ # With LTI: playlist admin or instructor admin or playlist access can access ( - permissions.IsPlaylistToken + permissions.IsPlaylistTokenMatchingRouteObject & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) ) # With standalone site, only playlist admin or instructor @@ -196,7 +196,7 @@ def get_permissions(self): ]: permission_classes = [ # With LTI: playlist admin or instructor admin can access - permissions.IsPlaylistToken + permissions.IsPlaylistTokenMatchingRouteObject & (permissions.IsTokenInstructor | permissions.IsTokenAdmin) # With standalone site, playlist admin or instructor can access | permissions.IsObjectPlaylistAdminOrInstructor diff --git a/src/backend/marsha/core/api/xapi.py b/src/backend/marsha/core/api/xapi.py index 06bb8eb6de..54084cd708 100644 --- a/src/backend/marsha/core/api/xapi.py +++ b/src/backend/marsha/core/api/xapi.py @@ -23,7 +23,7 @@ class XAPIStatementView(APIViewMixin, APIView): """Viewset managing xAPI requests.""" - permission_classes = [permissions.UserOrResourceIsAuthenticated] + permission_classes = [permissions.UserOrPlaylistIsAuthenticated] http_method_names = ["post"] def _statement_from_lti( @@ -107,7 +107,7 @@ def post(self, request, resource_kind, resource_id): return Response(partial_xapi_statement.errors, status=400) if request.resource: - if request.resource.resource_id != str(object_instance.playlist.id): + if request.resource.playlist_id != str(object_instance.playlist.id): return HttpResponseNotFound() ( statement, diff --git a/src/backend/marsha/core/permissions/base.py b/src/backend/marsha/core/permissions/base.py index 72c34e75a6..ad2a8485bd 100644 --- a/src/backend/marsha/core/permissions/base.py +++ b/src/backend/marsha/core/permissions/base.py @@ -18,24 +18,24 @@ def has_permission(self, request, view): return False -class UserOrResourceIsAuthenticated(IsAuthenticated): - """This allows access for in user or resource context.""" +class UserOrPlaylistIsAuthenticated(IsAuthenticated): + """This allows access for in user or playlist context.""" class UserIsAuthenticated(IsAuthenticated): """This allows access only in user context.""" def has_permission(self, request, view): - """Simply checks we are NOT in a resource context.""" + """Simply checks we are NOT in a playlist context.""" has_permission = super().has_permission(request, view) return has_permission and request.resource is None -class ResourceIsAuthenticated(IsAuthenticated): - """This allows access only in resource context.""" +class PlaylistIsAuthenticated(IsAuthenticated): + """This allows access only in playlist context.""" def has_permission(self, request, view): - """Simply checks we are in a resource context.""" + """Simply checks we are in a playlist context.""" has_permission = super().has_permission(request, view) return has_permission and request.resource is not None diff --git a/src/backend/marsha/core/permissions/playlist.py b/src/backend/marsha/core/permissions/playlist.py index 15b944f700..c4b393b304 100644 --- a/src/backend/marsha/core/permissions/playlist.py +++ b/src/backend/marsha/core/permissions/playlist.py @@ -2,7 +2,6 @@ import uuid from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist -from django.db.models import Q from rest_framework import permissions @@ -16,17 +15,17 @@ ) -class IsTokenResourceRouteObjectRelatedPlaylist(permissions.BasePermission): +class IsTokenPlaylistRouteObjectRelatedPlaylist(permissions.BasePermission): """ Base permission class for JWT Tokens related to a playlist linked to a video. These permissions grants access to users authenticated with a JWT token built from a - resource ie related to a TokenResource. + playlist ie related to a TokenPlaylist. """ def has_permission(self, request, view): """ - Add a check to allow the request if the JWT resource matches the playlist in the url path. + Add a check to allow the request if the JWT playlist matches the playlist in the url path. Parameters ---------- @@ -41,28 +40,23 @@ def has_permission(self, request, view): True if the request is authorized, False otherwise """ return ( - request.resource - and models.Playlist.objects.filter( - Q(pk=view.get_object_pk()) - & ( - Q(videos__id=request.resource.id) - | Q(documents__id=request.resource.id) - ), - ).exists() + request.playlist + and request.playlist.id == view.get_object_pk() + and models.Playlist.objects.filter(pk=request.playlist.id).exists() ) -class IsTokenResourceRouteObjectRelatedVideo(permissions.BasePermission): +class IsTokenPlaylistRouteObjectRelatedVideo(permissions.BasePermission): """ - Base permission class for JWT Tokens related to a resource object linked to a video. + Base permission class for JWT Tokens related to a playlist object linked to a video. These permissions grants access to users authenticated with a JWT token built from a - resource ie related to a TokenResource. + playlist ie related to a TokenPlaylist. """ def has_permission(self, request, view): """ - Allow the request if the JWT resource matches the video related to the object in the url. + Allow the request if the JWT playlist matches the video related to the object in the url. Parameters ---------- @@ -78,8 +72,9 @@ def has_permission(self, request, view): """ try: return ( - request.resource - and str(view.get_related_object().video.id) == request.resource.id + request.playlist + and str(view.get_related_object().video.playlist.id) + == request.playlist.id ) except ObjectDoesNotExist: return False @@ -345,25 +340,6 @@ class IsRelatedVideoPlaylistAdminOrInstructor( """ -class HasPlaylistToken(permissions.BasePermission): - """ - Allow a request to proceed. Permission class. - - Only if the user has a playlist token payload. - """ - - def has_permission(self, request, view): - """ - Allow the request. - - Only if the playlist exists. - """ - if request.resource: - playlist_id = request.resource.playlist_id - return models.Playlist.objects.filter(id=playlist_id).exists() - return False - - class BaseObjectPermission(permissions.BasePermission): """Base permission to be used for detail views""" diff --git a/src/backend/marsha/core/permissions/token.py b/src/backend/marsha/core/permissions/token.py index 2178b0a7a0..b389d86ce6 100644 --- a/src/backend/marsha/core/permissions/token.py +++ b/src/backend/marsha/core/permissions/token.py @@ -11,7 +11,7 @@ class BaseTokenRolePermission(permissions.BasePermission): """Base permission class for JWT Tokens based on token roles. These permissions grants access to users authenticated with a JWT token built from a - resource ie related to a TokenResource. + playlist ie related to a TokenPlaylist. """ role = None @@ -62,7 +62,7 @@ def check_role(self, token): return bool(LTI_ROLES[STUDENT] & set(token.payload.get("roles", []))) -class IsTokenResourceRouteObject(permissions.BasePermission): +class IsTokenPlaylistRouteObject(permissions.BasePermission): """ Base permission class for JWT Tokens related to a resource object. @@ -89,7 +89,7 @@ def has_permission(self, request, view): return request.resource and view.get_object_pk() == request.resource.id -class IsTokenResourceRouteObjectRelatedPlaylist(permissions.BasePermission): +class IsTokenPlaylistRouteObjectRelatedPlaylist(permissions.BasePermission): """ Base permission class for JWT Tokens related to a playlist linked to a video. @@ -120,7 +120,7 @@ def has_permission(self, request, view): ) -class IsTokenResourceRouteObjectRelatedVideo(permissions.BasePermission): +class IsTokenPlaylistRouteObjectRelatedVideo(permissions.BasePermission): """ Base permission class for JWT Tokens related to a resource object linked to a video. @@ -154,7 +154,7 @@ def has_permission(self, request, view): return False -class IsPlaylistToken(permissions.BasePermission): +class IsPlaylistTokenMatchingRouteObject(permissions.BasePermission): """ Allow a request to proceed. Permission class. @@ -186,7 +186,7 @@ def has_permission(self, request, view): return False -class HasPlaylistToken(permissions.BasePermission): +class IsPlaylistToken(permissions.BasePermission): """ Allow a request to proceed. Permission class. @@ -200,6 +200,25 @@ def has_permission(self, request, view): Only if the playlist exists. """ if request.resource: - playlist_id = request.resource.playlist_id + playlist_id = request.resource.id + return models.Playlist.objects.filter(id=playlist_id).exists() + return False + + +class PortToPlaylistExists(permissions.BasePermission): + """ + Allow a request to proceed. Permission class. + + Only if the playlist is ported to exist. + """ + + def has_permission(self, request, view): + """ + Allow the request. + + Only if the playlist exists. + """ + if request.resource: + playlist_id = request.resource.port_to_playlist_id return models.Playlist.objects.filter(id=playlist_id).exists() return False diff --git a/src/backend/marsha/core/serializers/portability_request.py b/src/backend/marsha/core/serializers/portability_request.py index 251103e1f6..a777696fa3 100644 --- a/src/backend/marsha/core/serializers/portability_request.py +++ b/src/backend/marsha/core/serializers/portability_request.py @@ -84,7 +84,7 @@ def create(self, validated_data): # We allow to pass arguments for request creation, because on the "site" part # the provided information won't comme from the resource JWT token. - if str(validated_data["from_playlist"].id) != resource.playlist_id: + if str(validated_data["from_playlist"].id) != resource.port_to_playlist_id: raise serializers.ValidationError("Unexpected playlist") if str(validated_data["from_lti_consumer_site"].id) != resource.consumer_site: raise serializers.ValidationError("Unexpected consumer site") diff --git a/src/backend/marsha/core/simple_jwt/authentication.py b/src/backend/marsha/core/simple_jwt/authentication.py index a62ec67c5c..37a1705570 100644 --- a/src/backend/marsha/core/simple_jwt/authentication.py +++ b/src/backend/marsha/core/simple_jwt/authentication.py @@ -7,13 +7,13 @@ from rest_framework_simplejwt.models import TokenUser -class TokenResource(TokenUser): - """Same as TokenUser but for resource access JWT, with helpers for payload.""" +class TokenPlaylist(TokenUser): + """Same as TokenUser but for playlist access JWT, with helpers for payload.""" @cached_property def id(self): - """Returns the resource ID.""" - return self.token["resource_id"] + """Returns the playlist ID.""" + return self.token["playlist_id"] @cached_property def roles(self): @@ -26,7 +26,7 @@ def user(self): return self.token.get("user", {}) -class JWTStatelessUserOrResourceAuthentication(JWTStatelessUserAuthentication): +class JWTStatelessUserOrPlaylistAuthentication(JWTStatelessUserAuthentication): """ An authentication plugin that authenticates requests through a JSON web token provided in a request header without performing a database lookup @@ -41,15 +41,15 @@ def get_user(self, validated_token): We keep an actual user-like object to go through Django logic but this method can return: - TokenUser for user authentication - - TokenResource for resource authentication + - TokenPlaylist for playlist authentication """ try: user = super().get_user(validated_token) except InvalidToken as exc: - if "resource_id" not in validated_token: + if "playlist_id" not in validated_token: raise InvalidToken( - _("Token contained no recognizable resource identification") + _("Token contained no recognizable playlist identification") ) from exc - return TokenResource(validated_token) + return TokenPlaylist(validated_token) return user diff --git a/src/backend/marsha/core/simple_jwt/factories.py b/src/backend/marsha/core/simple_jwt/factories.py index 2dea956228..f4b8cfdb7a 100644 --- a/src/backend/marsha/core/simple_jwt/factories.py +++ b/src/backend/marsha/core/simple_jwt/factories.py @@ -8,12 +8,7 @@ from faker.utils.text import slugify from rest_framework_simplejwt.exceptions import TokenError -from marsha.core.factories import ( - ConsumerSiteFactory, - LiveSessionFactory, - PlaylistFactory, - UserFactory, -) +from marsha.core.factories import ConsumerSiteFactory, LiveSessionFactory, UserFactory from marsha.core.models import ( ADMINISTRATOR, INSTRUCTOR, @@ -22,11 +17,11 @@ STUDENT, Playlist, ) -from marsha.core.simple_jwt.permissions import ResourceAccessPermissions +from marsha.core.simple_jwt.permissions import PlaylistAccessPermissions from marsha.core.simple_jwt.tokens import ( ChallengeToken, LTIUserToken, - ResourceAccessToken, + PlaylistAccessToken, UserAccessToken, ) @@ -117,14 +112,14 @@ class Meta: # pylint:disable=missing-class-docstring model = ChallengeToken.for_user -class ResourcePermissionsFactory(factory.DictFactory): - """Factory for resource access permissions.""" +class PlaylistPermissionsFactory(factory.DictFactory): + """Factory for playlist access permissions.""" can_access_dashboard = False can_update = False class Meta: # pylint:disable=missing-class-docstring - model = ResourceAccessPermissions + model = PlaylistAccessPermissions @classmethod def _build(cls, model_class, *args, **kwargs): @@ -133,56 +128,56 @@ def _build(cls, model_class, *args, **kwargs): return permissions.as_dict() -class BaseResourceTokenFactory(BaseTokenFactory): +class BasePlaylistTokenFactory(BaseTokenFactory): """ - Base class for all resource token factories. + Base class for all playlist token factories. This forces to provide a playlist to forge the JWT, or nothing to use a random UUID. """ @staticmethod def get_playlist_id(params): - """Ensure the resource is a playlist.""" - resource_id = uuid.uuid4() - if not params.resource: + """Ensure the playlist in params is a Playlist instance.""" + playlist_id = uuid.uuid4() + if not params.playlist: pass - elif isinstance(params.resource, Playlist): - resource_id = params.resource.id + elif isinstance(params.playlist, Playlist): + playlist_id = params.playlist.id else: - raise TokenError("resource is not a playlist") + raise TokenError("playlist is not a Playlist instance") - return str(resource_id) + return str(playlist_id) - resource_id = factory.LazyAttribute(get_playlist_id) + playlist_id = factory.LazyAttribute(get_playlist_id) class Meta: # pylint:disable=missing-class-docstring abstract = True class Params: # pylint:disable=missing-class-docstring - resource = None + playlist = None -class ResourceAccessTokenFactory(BaseResourceTokenFactory): - """Simple resource token. Looks like a public resource token.""" +class PlaylistAccessTokenFactory(BasePlaylistTokenFactory): + """Simple playlist token. Looks like a public playlist token.""" session_id = factory.Faker("uuid4") class Meta: # pylint:disable=missing-class-docstring - model = ResourceAccessToken.for_resource_id + model = PlaylistAccessToken.for_playlist_id -class LTIResourceAccessTokenFactory(BaseResourceTokenFactory): +class LTIPlaylistAccessTokenFactory(BasePlaylistTokenFactory): """ - LTI resource forged token. + LTI playlist forged token. This token's payload is forged to remove a heavy call to `generate_passport_and_signed_lti_parameters` each time we want to have an LTI token. """ - # for_resource_id payload + # for_playlist_id payload session_id = factory.Faker("uuid4") - permissions = factory.SubFactory(ResourcePermissionsFactory) + permissions = factory.SubFactory(PlaylistPermissionsFactory) roles = factory.fuzzy.FuzzyChoice( [ADMINISTRATOR, INSTRUCTOR, STUDENT, NONE], getter=lambda x: [x], @@ -205,63 +200,50 @@ class LTIResourceAccessTokenFactory(BaseResourceTokenFactory): ) class Meta: # pylint:disable=missing-class-docstring - model = ResourceAccessToken + model = PlaylistAccessToken -class StudentLtiTokenFactory(LTIResourceAccessTokenFactory): - """LTI resource forged token for student.""" +class StudentLtiTokenFactory(LTIPlaylistAccessTokenFactory): + """LTI playlist forged token for student.""" roles = factory.fuzzy.FuzzyChoice(LTI_ROLES.get(STUDENT), getter=lambda x: [x]) -class InstructorOrAdminLtiTokenFactory(LTIResourceAccessTokenFactory): +class InstructorOrAdminLtiTokenFactory(LTIPlaylistAccessTokenFactory): """ - LTI resource forged token for instructor or administrators. + LTI playlist forged token for instructor or administrators. See `marsha.core.views.BaseLTIView`. Note: the `can_update` permission is set to True - to mean "the LTI request context ID is the resource playlist LTI ID". + to mean "the LTI request context ID is the playlist playlist LTI ID". When this is not the case, the test must explicitly add `permissions__can_update=False`. """ roles = factory.fuzzy.FuzzyChoice([ADMINISTRATOR, INSTRUCTOR], getter=lambda x: [x]) permissions = factory.SubFactory( - ResourcePermissionsFactory, + PlaylistPermissionsFactory, can_access_dashboard=True, can_update=True, ) -class PlaylistLtiTokenFactory(InstructorOrAdminLtiTokenFactory): - """ - LTI resource forged token for instructor or administrators with a playlist access. - See `marsha.core.views.LTISelectView`. - """ - - playlist_id = factory.LazyAttribute(lambda o: str(o.playlist.id)) - permissions = factory.SubFactory(ResourcePermissionsFactory, can_update=True) - - class Params: # pylint:disable=missing-class-docstring - playlist = factory.SubFactory(PlaylistFactory) - - -class LiveSessionResourceAccessTokenFactory(BaseTokenFactory): - """Generates a resource access token from a live session.""" +class LiveSessionPlaylistAccessTokenFactory(BaseTokenFactory): + """Generates a playlist access token from a live session.""" live_session = factory.SubFactory(LiveSessionFactory) session_id = factory.Faker("uuid4") class Meta: # pylint:disable=missing-class-docstring - model = ResourceAccessToken.for_live_session + model = PlaylistAccessToken.for_live_session -class LiveSessionLtiTokenFactory(LTIResourceAccessTokenFactory): +class LiveSessionLtiTokenFactory(LTIPlaylistAccessTokenFactory): """ - Prefer the use of LiveSessionResourceAccessTokenFactory, + Prefer the use of LiveSessionPlaylistAccessTokenFactory, but this one allows to deeply customize the final JWT. """ - resource_id = factory.LazyAttribute(lambda o: str(o.live_session.video.playlist.id)) + playlist_id = factory.LazyAttribute(lambda o: str(o.live_session.video.playlist.id)) roles = factory.fuzzy.FuzzyChoice([STUDENT, NONE], getter=lambda x: [x]) consumer_site = factory.LazyAttribute( @@ -278,7 +260,7 @@ class LiveSessionLtiTokenFactory(LTIResourceAccessTokenFactory): ) class Meta: # pylint:disable=missing-class-docstring - model = ResourceAccessToken + model = PlaylistAccessToken class Params: # pylint:disable=missing-class-docstring live_session = factory.SubFactory( diff --git a/src/backend/marsha/core/simple_jwt/permissions.py b/src/backend/marsha/core/simple_jwt/permissions.py index c68c583c78..10bf206d8f 100644 --- a/src/backend/marsha/core/simple_jwt/permissions.py +++ b/src/backend/marsha/core/simple_jwt/permissions.py @@ -3,8 +3,8 @@ @dataclass -class ResourceAccessPermissions: - """Permissions which can be provided in ResourceAccessToken""" +class PlaylistAccessPermissions: + """Permissions which can be provided in PlaylistAccessToken""" can_access_dashboard: bool = False can_update: bool = False diff --git a/src/backend/marsha/core/simple_jwt/tokens.py b/src/backend/marsha/core/simple_jwt/tokens.py index 817bcba93a..7e45623c15 100644 --- a/src/backend/marsha/core/simple_jwt/tokens.py +++ b/src/backend/marsha/core/simple_jwt/tokens.py @@ -12,7 +12,7 @@ from marsha.core.simple_jwt.utils import define_locales from marsha.core.utils.react_locales_utils import react_locale -from .permissions import ResourceAccessPermissions +from .permissions import PlaylistAccessPermissions class MarshaRefreshToken(RefreshToken): @@ -106,10 +106,10 @@ def verify(self): raise TokenError(_("Malformed LTI form token")) -class ResourceAccessMixin: +class PlaylistAccessMixin: """ - Methods dedicated to access JWT. They are both used by the ResourceAccessToken - and the ResourceRefreshToken classes. + Methods dedicated to access JWT. They are both used by the PlaylistAccessToken + and the PlaylistRefreshToken classes. """ def verify(self): @@ -117,9 +117,9 @@ def verify(self): super().verify() try: - ResourceAccessPermissions(**self.payload["permissions"]) + PlaylistAccessPermissions(**self.payload["permissions"]) except TypeError as exc: - raise TokenError(_("Malformed resource access token")) from exc + raise TokenError(_("Malformed playlist access token")) from exc @classmethod def for_lti( @@ -127,10 +127,10 @@ def for_lti( lti, permissions, session_id, - playlist_id, + port_to_playlist_id, ): """ - Returns an authorization token for the resource in the LTI request that will be provided + Returns an authorization token for the playlist in the LTI request that will be provided after authenticating the credentials. Parameters @@ -144,15 +144,15 @@ def for_lti( session_id: Type[str] session id to add to the token. - playlist_id: Type[str] - optional, playlist id to give access to in addition to the resource. + port_to_playlist_id: Type[str] + optional, playlist id to give access to in addition to the playlist. Returns ------- - ResourceAccessToken + PlaylistAccessToken JWT containing: - session_id - - resource_id + - playlist_id - roles - locale - permissions @@ -166,8 +166,8 @@ def for_lti( - username - user_fullname """ - token = cls.for_resource_id( - str(playlist_id), + token = cls.for_playlist_id( + str(port_to_playlist_id), session_id, permissions=permissions, roles=lti.roles, @@ -180,7 +180,7 @@ def for_lti( } ) - token.payload["playlist_id"] = playlist_id + token.payload["port_to_playlist_id"] = port_to_playlist_id user_id = getattr(lti, "user_id", None) if user_id: @@ -198,10 +198,10 @@ def for_lti_portability_request( cls, lti, session_id, - playlist_id, + port_to_playlist_id, ): """ - Returns an authorization token without resource + Returns an authorization token without playlist to allow only portability requests creation. Parameters @@ -212,15 +212,15 @@ def for_lti_portability_request( session_id: Type[str] session id to add to the token. - playlist_id: Type[str] - playlist id to give access to in addition to the resource. + port_to_playlist_id: Type[str] + playlist id to give access to in addition to the playlist. Returns ------- - ResourceAccessToken + PlaylistAccessToken JWT containing: - session_id - - resource_id + - playlist_id - roles - locale - permissions @@ -250,30 +250,30 @@ def for_lti_portability_request( lti, None, # not any permission provided session_id, # not mandatory - playlist_id=playlist_id, + port_to_playlist_id=port_to_playlist_id, ) - # Important: this token must not provide any access to the resource - token.payload["resource_id"] = "" + # Important: this token must not provide any access to the playlist + token.payload["playlist_id"] = "" return token @classmethod - def for_resource_id( # pylint: disable=too-many-arguments + def for_playlist_id( # pylint: disable=too-many-arguments cls, - resource_id, + playlist_id, session_id, permissions=None, roles=None, locale=None, ): """ - Returns an authorization token for the given resource that will be provided - after authenticating the resource's credentials. + Returns an authorization token for the given playlist that will be provided + after authenticating the playlist's credentials. Parameters ---------- - resource_id: Type[str] - resource id to add to the token. + playlist_id: Type[str] + playlist id to add to the token. session_id: Type[str] session id to add to the token. @@ -290,23 +290,23 @@ def for_resource_id( # pylint: disable=too-many-arguments Returns ------- - ResourceAccessToken + PlaylistAccessToken JWT containing: - session_id - - resource_id + - playlist_id - roles - locale - permissions - maintenance """ - permissions = ResourceAccessPermissions(**(permissions or {})) + permissions = PlaylistAccessPermissions(**(permissions or {})) - # Create a short-lived JWT token for the resource selection + # Create a short-lived JWT token for the playlist selection token = cls() token.payload.update( { "session_id": session_id, - "resource_id": resource_id, + "playlist_id": playlist_id, "roles": roles or [NONE], "locale": locale or settings.REACT_LOCALES[0], "permissions": asdict(permissions), @@ -318,8 +318,8 @@ def for_resource_id( # pylint: disable=too-many-arguments @classmethod def for_live_session(cls, live_session, session_id): """ - Returns an authorization token for the resource liked to the live session - that will be provided after authenticating the resource's credentials. + Returns an authorization token for the playlist liked to the live session + that will be provided after authenticating the playlist's credentials. Parameters ---------- @@ -331,9 +331,9 @@ def for_live_session(cls, live_session, session_id): Returns ------- - ResourceAccessToken + PlaylistAccessToken JWT containing: - - resource_id + - playlist_id - consumer_site (if from LTI connection) - context_id (if from LTI connection) - roles @@ -347,7 +347,7 @@ def for_live_session(cls, live_session, session_id): - username (if from LTI connection) - anonymous_id (if not from LTI connection) """ - token = cls.for_resource_id( + token = cls.for_playlist_id( str(live_session.video.playlist.id), session_id, locale=react_locale(live_session.language), @@ -375,15 +375,15 @@ def for_live_session(cls, live_session, session_id): return token -class ResourceAccessToken(ResourceAccessMixin, AccessToken): +class PlaylistAccessToken(PlaylistAccessMixin, AccessToken): """ - Resource dedicated access JWT. + Playlist dedicated access JWT. This token has the same lifetime as the default AccessToken (see `ACCESS_TOKEN_LIFETIME` setting). """ - token_type = "resource_access" # nosec + token_type = "playlist_access" # nosec def set_jti(self, jti=None): """ @@ -400,11 +400,11 @@ def set_jti(self, jti=None): self.payload[api_settings.JTI_CLAIM] = jti -class ResourceRefreshToken(ResourceAccessMixin, MarshaRefreshToken): - """Refresh token for resource access which relies on `ResourceAccessToken`""" +class PlaylistRefreshToken(PlaylistAccessMixin, MarshaRefreshToken): + """Refresh token for playlist access which relies on `PlaylistAccessToken`""" - access_token_class = ResourceAccessToken - access_token_type = ResourceAccessToken.token_type + access_token_class = PlaylistAccessToken + access_token_type = PlaylistAccessToken.token_type class LTIUserToken(AccessToken): diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_create.py b/src/backend/marsha/core/tests/api/live_sessions/test_create.py index 9df7a04c4c..62cc9a1fe7 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_create.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_create.py @@ -25,8 +25,8 @@ from marsha.core.serializers.live_session import timezone as LiveSessionTimezone from marsha.core.simple_jwt.factories import ( LiveSessionLtiTokenFactory, - LTIResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LTIPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) @@ -166,7 +166,7 @@ def test_api_livesession_create_send_mail_fails(self, mock_logger, _mock_send_ma ) self.assertTrue(video.is_scheduled) # token with no context_id and no user information - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) anonymous_id = uuid.uuid4() response = self.client.post( @@ -214,7 +214,7 @@ def test_api_livesession_create_public_token(self): ) self.assertTrue(video.is_scheduled) # token with no context_id and no user information - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) anonymous_id = uuid.uuid4() response = self.client.post( self._post_url(video), @@ -260,7 +260,7 @@ def test_api_livesession_create_public_token_is_registered_false(self): ) self.assertTrue(video.is_scheduled) # token with no context_id and no user information - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) anonymous_id = uuid.uuid4() now = datetime(2022, 4, 7, tzinfo=baseTimezone.utc) with mock.patch.object(LiveSessionTimezone, "now", return_value=now): @@ -310,7 +310,7 @@ def test_api_livesession_create_public_token_anonymous_mandatory( ) self.assertTrue(video.is_scheduled) # token with no context_id and no user information - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), { @@ -339,7 +339,7 @@ def test_api_livesession_create_public_partially_lti1(self): starting_at=timezone.now() + timedelta(days=100), ) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory(resource=video.playlist, user={}) + jwt_token = LTIPlaylistAccessTokenFactory(playlist=video.playlist, user={}) response = self.client.post( self._post_url(video), @@ -372,8 +372,8 @@ def test_api_livesession_create_public_partially_lti2(self): starting_at=timezone.now() + timedelta(days=100), ) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=None, ) @@ -408,8 +408,8 @@ def test_api_livesession_create_public_partially_lti3(self): starting_at=timezone.now() + timedelta(days=100), ) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=None, ) @@ -441,8 +441,8 @@ def test_api_livesession_create_token_lti_email_with(self): ) self.assertTrue(video.is_scheduled) # token has same consumer_site than the video - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id="Maths", # explicit to be found in response consumer_site=str(video.playlist.consumer_site.id), user__id="56255f3807599c377bf0e5bf072359fd", # explicit to be found in response @@ -492,8 +492,8 @@ def test_api_livesession_create_token_lti_is_registered_false(self): ) self.assertTrue(video.is_scheduled) # token has same consumer_site than the video - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id="Maths", # explicit to be found in response consumer_site=str(video.playlist.consumer_site.id), user__id="56255f3807599c377bf0e5bf072359fd", # explicit to be found in response @@ -544,8 +544,8 @@ def test_api_livesession_create_token_lti_email_none(self): self.assertTrue(video.is_scheduled) other_playlist = PlaylistFactory() # token has different context_id than the video - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(other_playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), user__id="56255f3807599c377bf0e5bf072359fd", # explicit to be found in response @@ -600,7 +600,7 @@ def test_api_livesession_create_public_token_record_email_other_livesession_lti( ) self.assertEqual(LiveSession.objects.count(), 1) self.assertTrue(video.is_scheduled) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) anonymous_id = uuid.uuid4() response = self.client.post( self._post_url(video), @@ -659,8 +659,8 @@ def test_api_livesession_create_lti_token_record_email_other_consumer_site( ) self.assertEqual(LiveSession.objects.count(), 1) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(other_consumer_site.id), context_id=live_session.lti_id, user__id=live_session.lti_user_id, @@ -720,8 +720,8 @@ def test_api_livesession_create_lti_token_record_email_other_context_id( self.assertTrue(video.is_scheduled) other_context_id = f"{live_session.lti_id}_diff" - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=other_context_id, user__id=live_session.lti_user_id, @@ -778,8 +778,8 @@ def test_api_livesession_create_lti_token_record_email_lti_user_id(self): ) self.assertEqual(LiveSession.objects.count(), 1) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(live_session.consumer_site.id), context_id=live_session.lti_id, user__id="NEW", # explicit to be found in response @@ -832,8 +832,8 @@ def test_api_livesession_create_token_lti_email_restricted_token(self): ) self.assertTrue(video.is_scheduled) # token with different context_id - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), ) @@ -864,7 +864,7 @@ def test_api_livesession_create_public_token_cant_register_when_not_scheduled( """Can't register if video is not scheduled.""" video = VideoFactory() self.assertFalse(video.is_scheduled) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), @@ -891,8 +891,8 @@ def test_api_livesession_create_lti_token_cant_register_when_not_scheduled( """LTI token can't register if video is not scheduled.""" video = VideoFactory() self.assertFalse(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -1064,7 +1064,7 @@ def test_api_livesession_create_cant_register_same_email_same_consumer_none( AnonymousLiveSessionFactory(email="salome@test-fun-mooc.fr", video=video) self.assertTrue(video.is_scheduled) # token with no context_id leading to an undefined consumer_site - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), { @@ -1141,7 +1141,7 @@ def test_api_livesession_create_public_token_same_email_different_video( # livesession with no consumer_site AnonymousLiveSessionFactory(email="chantal@test-fun-mooc.fr", video=video) # token with no context_id leading to no consumer_site - jwt_token = ResourceAccessTokenFactory(resource=video2.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video2.playlist) anonymous_id = uuid.uuid4() # With the same email but other video, livesession is possible @@ -1205,8 +1205,8 @@ def test_api_livesession_create_token_lti_same_email_different_video( lti_id="Maths", lti_user_id="56255f3807599c377bf0e5bf072359fd", ) - jwt_token = LTIResourceAccessTokenFactory( - resource=video2.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video2.playlist, context_id=live_session.lti_id, consumer_site=str(video.playlist.consumer_site.id), user__email=None, @@ -1259,8 +1259,8 @@ def test_api_livesession_create_username_doesnt_change( starting_at=timezone.now() + timedelta(days=100), ) self.assertTrue(video.is_scheduled) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id="Maths", consumer_site=str(video.playlist.consumer_site.id), user__email=None, @@ -1389,8 +1389,8 @@ def test_api_livesession_create_role_none_email_empty(self): ) self.assertTrue(video.is_scheduled) # token with context_id - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), roles=[NONE], @@ -1438,8 +1438,8 @@ def test_api_livesession_send_mail_i18n(self): self.assertTrue(video.is_scheduled) other_playlist = PlaylistFactory() # token has different context_id than the video - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(other_playlist.lti_id), user__id="56255f3807599c377bf0e5bf072359fd", diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_display_name.py b/src/backend/marsha/core/tests/api/live_sessions/test_display_name.py index d5a385fc4a..a1c2bfc788 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_display_name.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_display_name.py @@ -15,8 +15,8 @@ from marsha.core.models import ADMINISTRATOR, INSTRUCTOR, STUDENT, LiveSession from marsha.core.simple_jwt.factories import ( LiveSessionLtiTokenFactory, - LTIResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LTIPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) @@ -152,7 +152,7 @@ def test_api_livesession_put_username_public_no_anonymous( ): """Field anonymous_id is mandatory when the JWT token is a public one.""" video = VideoFactory() - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"display_name": "Antoine"}, @@ -167,7 +167,7 @@ def test_api_livesession_put_username_public_no_anonymous_no_displayname( ): """Field display_name is mandatory.""" video = VideoFactory() - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"anonymous_id": uuid.uuid4()}, @@ -188,7 +188,7 @@ def test_api_livesession_put_username_public_session_existing( ) self.assertEqual(LiveSession.objects.count(), 1) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"anonymous_id": anonymous_id, "display_name": "Antoine"}, @@ -232,7 +232,7 @@ def test_api_livesession_put_username_public_session_exists_other_video( live_session = AnonymousLiveSessionFactory(display_name="Samuel", video=video2) self.assertEqual(LiveSession.objects.count(), 1) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"anonymous_id": live_session.anonymous_id, "display_name": "Antoine"}, @@ -274,7 +274,7 @@ def test_api_livesession_put_username_public_session_no( anonymous_id = uuid.uuid4() self.assertEqual(LiveSession.objects.count(), 0) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"anonymous_id": anonymous_id, "display_name": "Antoine"}, @@ -315,7 +315,7 @@ def test_api_livesession_put_username_public_already_exists( video = VideoFactory() AnonymousLiveSessionFactory(display_name="Samuel", video=video) self.assertEqual(LiveSession.objects.count(), 1) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._put_url(video), {"anonymous_id": uuid.uuid4(), "display_name": "Samuel"}, @@ -331,8 +331,8 @@ def test_api_livesession_put_username_public_already_exists( def test_api_livesession_put_username_lti_no_displayname(self): """Field display_name is mandatory.""" video = VideoFactory() - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), ) response = self.client.put( @@ -417,8 +417,8 @@ def test_api_livesession_put_username_lti_session_exists_other_video(self): ) self.assertEqual(LiveSession.objects.count(), 1) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(live_session.consumer_site.id), context_id=live_session.lti_id, user__email="sabrina@fun-test.fr", @@ -462,8 +462,8 @@ def test_api_livesession_put_username_lti_session_no(self): video = VideoFactory() self.assertEqual(LiveSession.objects.count(), 0) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id="Maths", user__email="sabrina@fun-test.fr", @@ -510,8 +510,8 @@ def test_api_livesession_put_username_lti_already_exists( video = VideoFactory() AnonymousLiveSessionFactory(display_name="Samuel", video=video) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), ) response = self.client.put( diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_list.py b/src/backend/marsha/core/tests/api/live_sessions/test_list.py index a9b4e678ef..188cbe32a1 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_list.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_list.py @@ -22,8 +22,8 @@ from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, LiveSessionLtiTokenFactory, - LiveSessionResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LiveSessionPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) @@ -231,7 +231,7 @@ def test_list_livesession_public_token(self): AnonymousLiveSessionFactory(email=user.email, video=video2) # public token - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video), HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -245,7 +245,7 @@ def test_api_livesession_list_throttling(self): # first 3 requests shouldn't be throttled for _i in range(3): video = VideoFactory() - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.get( f"{self._get_url(video)}?anonymous_id={uuid.uuid4()}", @@ -293,7 +293,7 @@ def test_api_livesession_list_throttling_no_anonymous(self): # first 3 requests shouldn't be throttled for _i in range(3): video = VideoFactory() - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video), @@ -346,7 +346,7 @@ def test_list_livesession_public_token_anonymous(self): ) # public token - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.get( f"{self._get_url(video)}?anonymous_id={livesession.anonymous_id}", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -528,7 +528,7 @@ def test_list_livesession_lti_token_role_admin_instructors(self): # context_id in the token jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id="Maths", consumer_site=str(video.playlist.consumer_site.id), ) @@ -640,7 +640,7 @@ def test_list_livesession_token_lti_wrong_is_registered_field(self): ) # token has context_id and no email - jwt_token = LiveSessionResourceAccessTokenFactory(live_session=live_session) + jwt_token = LiveSessionPlaylistAccessTokenFactory(live_session=live_session) response = self.client.get( f"{self._get_url(video)}?is_registered=True", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_list_attendances.py b/src/backend/marsha/core/tests/api/live_sessions/test_list_attendances.py index 0fa45fe367..fce4b9660a 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_list_attendances.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_list_attendances.py @@ -222,7 +222,7 @@ def test_api_livesession_read_attendances_admin_video_unknown(self): # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -303,7 +303,7 @@ def test_api_livesession_read_attendances_admin(self): ) # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -386,7 +386,7 @@ def test_api_livesession_read_attendances_admin_target_record(self): # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -468,7 +468,7 @@ def test_api_livesession_read_attendances_well_computed_start_and_end(self): ) # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -588,7 +588,7 @@ def test_api_livesession_read_attendances_well_computed_before_start(self): # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -748,7 +748,7 @@ def test_api_livesession_read_attendances_well_computed_start_and_live_running( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -883,7 +883,7 @@ def test_api_livesession_read_attendances_well_computed_start_and_live_running_c # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -951,7 +951,7 @@ def test_api_livesession_read_attendances_well_computed_start_and_live_running_c # we now query the list of attendance for video2 jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video2.playlist, + playlist=video2.playlist, consumer_site=str(video2.playlist.consumer_site.id), context_id=str(video2.playlist.lti_id), ) @@ -1036,7 +1036,7 @@ def test_api_livesession_reset_cache( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1165,7 +1165,7 @@ def test_api_livesession_video_no_stopped_at_cache_has_timeout( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1260,7 +1260,7 @@ def test_api_livesession_video_ended_cache_no_timeout( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1340,7 +1340,7 @@ def test_api_livesession_read_attendances_same_keys( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1406,7 +1406,7 @@ def test_api_livesession_read_attendances_well_computed_running_between_info_att # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1516,7 +1516,7 @@ def test_api_livesession_read_attendances_well_computed_start_and_live_page(self # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1627,7 +1627,7 @@ def test_api_livesession_read_attendances_no_timeline_video(self): livesession.refresh_from_db() # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1681,7 +1681,7 @@ def test_api_livesession_read_attendances_admin_is_registered_att_null_or_empty( # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -1728,7 +1728,7 @@ def test_api_livesession_read_attendances_admin_live_attendance_key_string(self) # token with right context_id and lti_user_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=str(video.playlist.lti_id), ) diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_push_attendance.py b/src/backend/marsha/core/tests/api/live_sessions/test_push_attendance.py index 2de44fb8de..830a09fc19 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_push_attendance.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_push_attendance.py @@ -18,8 +18,8 @@ from marsha.core.models import ADMINISTRATOR, INSTRUCTOR, STUDENT, LiveSession from marsha.core.simple_jwt.factories import ( LiveSessionLtiTokenFactory, - LTIResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LTIPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) from marsha.core.utils.time_utils import to_timestamp @@ -183,8 +183,8 @@ def test_api_livesession_post_attendance_no_payload(self): def test_api_livesession_post_attendance_no_attendance(self): """Request without attendance should raise an error.""" video = VideoFactory() - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -204,8 +204,8 @@ def test_api_livesession_post_attendance_token_lti_consumer_site_not_existing( ): """Pushing an attendance on a not existing video should fail.""" video = VideoFactory() - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(video.playlist.lti_id), user__email=None, ) @@ -226,8 +226,8 @@ def test_api_livesession_post_attendance_token_lti_email_none_previous_none( ): """Endpoint push_attendance works with no email and no previous record.""" video = VideoFactory() - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), user__email=None, @@ -286,8 +286,8 @@ def test_api_livesession_post_attendance_token_lti_existing_record(self): video=video, ) self.assertEqual(LiveSession.objects.count(), 1) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, context_id=str(livesession.lti_id), consumer_site=str(video.playlist.consumer_site.id), user__email="chantal@aol.com", @@ -344,7 +344,7 @@ def test_api_livesession_post_new_attendance_token_public_unexisting_video( """Pushing an attendance on a not existing video should fail""" anonymous_id = uuid.uuid4() self.assertEqual(LiveSession.objects.count(), 0) - jwt_token = ResourceAccessTokenFactory() + jwt_token = PlaylistAccessTokenFactory() response = self.client.post( f"/api/videos/unexisting/livesessions/push_attendance/?anonymous_id={anonymous_id}", {"live_attendance": {}}, @@ -359,7 +359,7 @@ def test_api_livesession_post_new_attendance_token_public(self): video = VideoFactory() anonymous_id = uuid.uuid4() self.assertEqual(LiveSession.objects.count(), 0) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.post( f"/api/videos/{video.id}/livesessions/push_attendance/?anonymous_id={anonymous_id}", {"language": "fr", "live_attendance": {}}, @@ -395,7 +395,7 @@ def test_api_livesession_post_attendance_existing_token_public(self): self.assertEqual(LiveSession.objects.count(), 1) timestamp = to_timestamp(timezone.now()) - jwt_token = ResourceAccessTokenFactory(resource=livesession.video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=livesession.video.playlist) response = self.client.post( f"/api/videos/{livesession.video_id}/livesessions/push_attendance/" f"?anonymous_id={livesession.anonymous_id}", @@ -447,7 +447,7 @@ def test_api_livesession_post_attendance_token_public_missing_anonymous_id(self) self.assertEqual(LiveSession.objects.count(), 0) timestamp = to_timestamp(timezone.now()) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), { @@ -799,8 +799,8 @@ def test_api_livesession_post_attendance_token_with_could_match_other_records( nb_created = 6 self.assertEqual(LiveSession.objects.count(), nb_created) # token with same email - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id="Maths", user__id="55555", diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_retrieve.py b/src/backend/marsha/core/tests/api/live_sessions/test_retrieve.py index f6625bfddc..aa22e7b8ed 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_retrieve.py @@ -19,9 +19,9 @@ from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, LiveSessionLtiTokenFactory, - LiveSessionResourceAccessTokenFactory, - LTIResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LiveSessionPlaylistAccessTokenFactory, + LTIPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) @@ -181,7 +181,7 @@ def test_api_livesession_read_token_public(self): video = VideoFactory() livesession = AnonymousLiveSessionFactory(video=video) # token has no consumer_site, no context_id and no user's info - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(livesession.video, livesession), @@ -200,7 +200,7 @@ def test_api_livesession_read_token_public_with_anonymous(self): """ livesession = AnonymousLiveSessionFactory() # token has no consumer_site, no context_id and no user's info - jwt_token = ResourceAccessTokenFactory(resource=livesession.video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=livesession.video.playlist) response = self.client.get( f"{self._get_url(livesession.video, livesession)}" @@ -241,7 +241,7 @@ def test_api_livesession_read_token_lti_email_set(self): lti_user_id="56255f3807599c377bf0e5bf072359fd", ) # token from LTI has context_id, consumer_site and user.id - jwt_token = LiveSessionResourceAccessTokenFactory(live_session=livesession) + jwt_token = LiveSessionPlaylistAccessTokenFactory(live_session=livesession) response = self.client.get( self._get_url(livesession.video, livesession), HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -281,7 +281,7 @@ def test_api_livesession_read_token_lti_email_none( ) # token with right context_id and lti_user_id - jwt_token = LiveSessionResourceAccessTokenFactory(live_session=livesession) + jwt_token = LiveSessionPlaylistAccessTokenFactory(live_session=livesession) response = self.client.get( self._get_url(livesession.video, livesession), @@ -365,8 +365,8 @@ def test_api_livesession_read_token_lti_record_consumer_none(self): livesession = AnonymousLiveSessionFactory() # token has context_id so different consumer_site - jwt_token = LTIResourceAccessTokenFactory( - resource=livesession.video.playlist, # as usual + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=livesession.video.playlist, # as usual roles=[random.choice([STUDENT, NONE])], user__email=livesession.email, # as usual # below arguments are not usual for anonymous live session @@ -541,7 +541,7 @@ def test_api_livesession_read_token_lti_admin_instruct_token_email_ok(self): username="Sam", # explicit to be found in response ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=livesession.video.playlist, + playlist=livesession.video.playlist, context_id=str(livesession.video.playlist.lti_id), consumer_site=str(livesession.consumer_site.id), ) @@ -586,7 +586,7 @@ def test_api_livesession_read_token_lti_admin_instruct_token_email_none(self): ) # token with right context_id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=livesession.video.playlist, + playlist=livesession.video.playlist, context_id=str(livesession.video.playlist.lti_id), consumer_site=str(livesession.consumer_site.id), user__email=None, @@ -627,7 +627,7 @@ def test_api_livesession_read_token_lti_admin_instruct_email_diff(self): jwt_token = InstructorOrAdminLtiTokenFactory( # context_id and consumer_site are not determinant (random uuid here) - resource=livesession.video.playlist, + playlist=livesession.video.playlist, ) response = self.client.get( @@ -667,7 +667,7 @@ def test_api_livesession_read_token_lti_admin_instruct_record_consumer_diff(self # token with context_id leading to another consumer site jwt_token = InstructorOrAdminLtiTokenFactory( - resource=livesession.video.playlist, + playlist=livesession.video.playlist, context_id=str(livesession.video.playlist.lti_id), # consumer_site is not other_consumer_site consumer_site=str(livesession.video.playlist.consumer_site.id), @@ -710,7 +710,7 @@ def test_api_livesession_read_token_lti_admin_instruct_record_course_diff(self): # token with context_id leading to another consumer site jwt_token = InstructorOrAdminLtiTokenFactory( - resource=livesession.video.playlist, + playlist=livesession.video.playlist, context_id=f"{livesession.video.playlist.lti_id}_diff", # consumer_site is not other_consumer_site consumer_site=str(livesession.video.playlist.consumer_site.id), @@ -749,7 +749,7 @@ def test_api_livesession_read_token_public_wrong_video_token(self): livesession = AnonymousLiveSessionFactory() # token with no context_id leading to the same undefined consumer_site - jwt_token = ResourceAccessTokenFactory() + jwt_token = PlaylistAccessTokenFactory() response = self.client.get( self._get_url(livesession.video, livesession), @@ -762,7 +762,7 @@ def test_api_livesession_read_token_lti_wrong_video_token(self): # livesession with consumer_site livesession = LiveSessionFactory(is_from_lti_connection=True) # token with unexisting consumer_site - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( context_id=str(livesession.video.playlist.lti_id), consumer_site=str(livesession.video.playlist.consumer_site.id), user__email=None, @@ -779,7 +779,7 @@ def test_api_livesession_read_token_public_other_video_context_none_role(self): livesession = AnonymousLiveSessionFactory() # token with no context_id leading to the same undefined consumer_site - jwt_token = ResourceAccessTokenFactory(resource=VideoFactory().playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=VideoFactory().playlist) response = self.client.get( self._get_url(livesession.video, livesession), @@ -792,8 +792,8 @@ def test_api_livesession_read_token_lti_other_video_context_none_role(self): # livesession with no consumer_site livesession = LiveSessionFactory(is_from_lti_connection=True) - jwt_token = LTIResourceAccessTokenFactory( - resource=VideoFactory().playlist, # other video + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=VideoFactory().playlist, # other video context_id=str(livesession.video.playlist.lti_id), consumer_site=str(livesession.video.playlist.consumer_site.id), user__email=None, @@ -812,7 +812,7 @@ def test_api_livesession_read_detail_unknown_video(self): video = VideoFactory(live_state=IDLE, live_type=RAW, starting_at=starting_at) livesession = AnonymousLiveSessionFactory(video=video) # token with no user information - jwt_token = ResourceAccessTokenFactory() + jwt_token = PlaylistAccessTokenFactory() response = self.client.get( self._get_url(livesession.video, livesession), content_type="application/json", diff --git a/src/backend/marsha/core/tests/api/live_sessions/test_update.py b/src/backend/marsha/core/tests/api/live_sessions/test_update.py index 02de338b31..0e08f1314e 100644 --- a/src/backend/marsha/core/tests/api/live_sessions/test_update.py +++ b/src/backend/marsha/core/tests/api/live_sessions/test_update.py @@ -22,8 +22,8 @@ from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, LiveSessionLtiTokenFactory, - LTIResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LTIPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, UserAccessTokenFactory, ) @@ -210,7 +210,7 @@ def test_api_livesession_update_put_with_token_not_allowed(self): starting_at=timezone.now() + timedelta(days=100), ) live_session = AnonymousLiveSessionFactory(video=video) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) response = self.client.put( self._update_url(video, live_session), @@ -233,8 +233,8 @@ def test_api_livesession_put_not_allowed(self): video=video, ) - jwt_token = LTIResourceAccessTokenFactory( - resource=video.playlist, + jwt_token = LTIPlaylistAccessTokenFactory( + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id=live_session.lti_id, user__id=live_session.lti_user_id, @@ -631,7 +631,7 @@ def test_api_livesession_admin_can_patch_any_record_from_the_same_consumer_site( ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id="Maths", ) @@ -699,7 +699,7 @@ def test_api_live_session_admin_using_existing_email(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.playlist.consumer_site.id), context_id="Maths", ) @@ -732,7 +732,7 @@ def test_api_livesession_patch_email_from_anonymous_livesession(self): ) self.assertIsNone(live_session.registered_at) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) now = datetime(2022, 4, 7, tzinfo=baseTimezone.utc) with mock.patch.object(LiveSessionTimezone, "now", return_value=now): @@ -782,7 +782,7 @@ def test_api_livesession_update_email_with_another_anonymous_id(self): video=video, ) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) other_anonymous_id = uuid.uuid4() response = self.client.patch( @@ -813,7 +813,7 @@ def test_api_livesession_patch_language(self): self.assertIsNone(live_session.registered_at) self.assertEqual(live_session.language, "en") - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) # if a wrong language is set response = self.client.patch( diff --git a/src/backend/marsha/core/tests/api/playlists/test_is_claimed.py b/src/backend/marsha/core/tests/api/playlists/test_is_claimed.py index d1549b0f00..0f13704eb3 100644 --- a/src/backend/marsha/core/tests/api/playlists/test_is_claimed.py +++ b/src/backend/marsha/core/tests/api/playlists/test_is_claimed.py @@ -29,7 +29,7 @@ def test_playlist_is_claimed_anonymous(self): def test_playlist_is_claimed_student(self): """Random logged-in users cannot check if a playlist is claimed.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/playlists/{video.playlist.id}/is-claimed/", @@ -43,7 +43,7 @@ def test_playlist_is_claimed_LTI_administrator(self): video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, roles=[ADMINISTRATOR], ) @@ -61,7 +61,7 @@ def test_playlist_is_claimed_LTI_instructor(self): video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, roles=[INSTRUCTOR], ) @@ -79,7 +79,7 @@ def test_playlist_is_claimed_LTI_instructor_claimed(self): video = factories.VideoFactory(upload_state="pending") consumer_site = factories.ConsumerSiteFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, roles=[INSTRUCTOR], consumer_site=str(consumer_site.id), ) diff --git a/src/backend/marsha/core/tests/api/playlists/test_retrieve.py b/src/backend/marsha/core/tests/api/playlists/test_retrieve.py index 0daf0fd827..cf9ac90d3d 100644 --- a/src/backend/marsha/core/tests/api/playlists/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/playlists/test_retrieve.py @@ -54,7 +54,7 @@ def test_retrieve_playlist_through_video_token_instructor(self): """Playlist instructors can retrieve playlists through video token.""" video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/playlists/{video.playlist.id}/", @@ -67,7 +67,7 @@ def test_retrieve_playlist_through_document_token_instructor(self): """Playlist instructors can retrieve playlists through document token.""" document = factories.DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) response = self.client.get( f"/api/playlists/{document.playlist.id}/", diff --git a/src/backend/marsha/core/tests/api/playlists/test_update.py b/src/backend/marsha/core/tests/api/playlists/test_update.py index bfd6198a90..0eaeef1420 100644 --- a/src/backend/marsha/core/tests/api/playlists/test_update.py +++ b/src/backend/marsha/core/tests/api/playlists/test_update.py @@ -139,7 +139,7 @@ def test_update_playlist_through_video_token_instructor(self): """Playlist instructors or admins can update playlists through video token.""" video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/playlists/{video.playlist.id}/", @@ -163,7 +163,7 @@ def test_update_playlist_through_document_token_instructor(self): """Playlist instructors or admins can update playlists with document token.""" document = factories.DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) response = self.client.get( f"/api/playlists/{document.playlist.id}/", @@ -187,7 +187,7 @@ def test_partial_update_playlist_through_video_token_instructor(self): """Playlist instructors or admins can partially update playlists.""" video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.patch( f"/api/playlists/{video.playlist.id}/", diff --git a/src/backend/marsha/core/tests/api/portability_requests/test_create.py b/src/backend/marsha/core/tests/api/portability_requests/test_create.py index d61cef1bbd..92bb768718 100644 --- a/src/backend/marsha/core/tests/api/portability_requests/test_create.py +++ b/src/backend/marsha/core/tests/api/portability_requests/test_create.py @@ -14,7 +14,6 @@ from marsha.core.models import PortabilityRequest from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -94,7 +93,7 @@ def test_create_api_portability_request_student(self): """ video = UploadedVideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( "/api/portability-requests/", @@ -110,6 +109,7 @@ def test_create_api_portability_request_student(self): ), ) + # something is wrong here self.assertEqual(response.status_code, 403) # Forbidden self.assertEqual(PortabilityRequest.objects.count(), 0) @@ -119,7 +119,12 @@ def test_create_api_portability_request_instructor_no_playlist(self): when he has no access to the requesting playlist. """ video = UploadedVideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + consumer_site = ConsumerSiteFactory() + destination_playlist = PlaylistFactory() + lti_user_id = uuid4() + jwt_token = InstructorOrAdminLtiTokenFactory( + playlist=video.playlist, port_to_playlist=str(destination_playlist.pk) + ) response = self.client.post( "/api/portability-requests/", @@ -128,13 +133,18 @@ def test_create_api_portability_request_instructor_no_playlist(self): data=json.dumps( { "for_playlist": str(video.playlist_id), - "from_playlist": None, # not mandatory for 403 test - "from_lti_consumer_site": None, # not mandatory for 403 test - "from_lti_user_id": None, # not mandatory for 403 test + "from_playlist": str( + destination_playlist.pk + ), # not mandatory for 403 test + "from_lti_consumer_site": str( + consumer_site.pk + ), # not mandatory for 403 test + "from_lti_user_id": str(lti_user_id), # not mandatory for 403 test } ), ) + # something is wrong here self.assertEqual(response.status_code, 403) # Forbidden self.assertEqual(PortabilityRequest.objects.count(), 0) @@ -148,10 +158,10 @@ def test_create_api_portability_request_instructor_with_playlist(self): consumer_site = ConsumerSiteFactory() destination_playlist = PlaylistFactory() lti_user_id = uuid4() - jwt_token = PlaylistLtiTokenFactory( + jwt_token = InstructorOrAdminLtiTokenFactory( consumer_site=str(consumer_site.pk), - playlist_id=str(destination_playlist.pk), - resource=video.playlist, + port_to_playlist_id=str(destination_playlist.pk), + playlist=video.playlist, user__id=str(lti_user_id), ) @@ -224,10 +234,10 @@ def test_create_api_portability_request_instructor_with_associated_user(self): consumer_site = ConsumerSiteFactory() destination_playlist = PlaylistFactory() lti_user_id = uuid4() - jwt_token = PlaylistLtiTokenFactory( + jwt_token = InstructorOrAdminLtiTokenFactory( consumer_site=str(consumer_site.pk), - playlist_id=str(destination_playlist.pk), - resource=video.playlist, + port_to_playlist_id=str(destination_playlist.pk), + playlist=destination_playlist, user__id=str(lti_user_id), ) @@ -302,10 +312,10 @@ def test_create_api_portability_request_instructor_with_playlist_errors(self): consumer_site = ConsumerSiteFactory() destination_playlist = PlaylistFactory() lti_user_id = uuid4() - jwt_token = PlaylistLtiTokenFactory( + jwt_token = InstructorOrAdminLtiTokenFactory( consumer_site=str(consumer_site.pk), - playlist_id=str(destination_playlist.pk), - resource=video.playlist, + port_to_playlist_id=str(destination_playlist.pk), + playlist=video.playlist, user__id=str(lti_user_id), ) diff --git a/src/backend/marsha/core/tests/api/portability_requests/test_delete.py b/src/backend/marsha/core/tests/api/portability_requests/test_delete.py index ead74101f1..a1bb2bea5d 100644 --- a/src/backend/marsha/core/tests/api/portability_requests/test_delete.py +++ b/src/backend/marsha/core/tests/api/portability_requests/test_delete.py @@ -9,7 +9,7 @@ ) from marsha.core.models import PortabilityRequest from marsha.core.simple_jwt.factories import ( - PlaylistLtiTokenFactory, + InstructorOrAdminLtiTokenFactory, UserAccessTokenFactory, ) @@ -37,10 +37,10 @@ def test_delete_portability_request_by_random_lti_user(self): self.assertEqual(PortabilityRequest.objects.count(), 1) # Event the portability request "asker" cannot delete it from LTI - jwt_token = PlaylistLtiTokenFactory( + jwt_token = InstructorOrAdminLtiTokenFactory( consumer_site=str(portability_request.from_lti_consumer_site.pk), - playlist_id=str(portability_request.from_lti_consumer_site.pk), - resource=None, + port_to_playlist_id=str(portability_request.from_lti_consumer_site.pk), + playlist=None, user__id=str(portability_request.from_lti_user_id), ) diff --git a/src/backend/marsha/core/tests/api/portability_requests/test_list.py b/src/backend/marsha/core/tests/api/portability_requests/test_list.py index 299aa801b1..6d3673173f 100644 --- a/src/backend/marsha/core/tests/api/portability_requests/test_list.py +++ b/src/backend/marsha/core/tests/api/portability_requests/test_list.py @@ -14,7 +14,7 @@ ) from marsha.core.models import ADMINISTRATOR, PortabilityRequestState from marsha.core.simple_jwt.factories import ( - PlaylistLtiTokenFactory, + InstructorOrAdminLtiTokenFactory, UserAccessTokenFactory, ) @@ -60,10 +60,10 @@ def test_list_portability_request_by_random_lti_user(self): portability_request = PortabilityRequestFactory() # Event the portability request "asker" cannot delete it from LTI - jwt_token = PlaylistLtiTokenFactory( + jwt_token = InstructorOrAdminLtiTokenFactory( consumer_site=str(portability_request.from_lti_consumer_site.pk), - playlist_id=str(portability_request.from_lti_consumer_site.pk), - resource=None, + port_to_playlist_id=str(portability_request.from_lti_consumer_site.pk), + playlist=None, user__id=str(portability_request.from_lti_user_id), ) diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_create.py b/src/backend/marsha/core/tests/api/shared_live_media/test_create.py index 7aa643b3db..2d018bb918 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_create.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_create.py @@ -40,7 +40,7 @@ def test_api_shared_live_media_create_instructor(self): """An instructor should be able to create a shared live media for an existing video.""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), @@ -71,7 +71,7 @@ def test_api_shared_live_media_create_instructor_in_read_only(self): """An instructor in read only should not be able to create a shared live media.""" video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -86,7 +86,7 @@ def test_api_shared_live_media_create_instructor_in_read_only(self): def test_api_shared_live_media_create_student(self): """A student should not be able to create a shared live media.""" video = VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_delete.py b/src/backend/marsha/core/tests/api/shared_live_media/test_delete.py index 3e2c1ec468..db49efaf7c 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_delete.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_delete.py @@ -45,7 +45,7 @@ def test_api_shared_live_media_delete_student(self): """A student can not delete a shared live media.""" shared_live_media = SharedLiveMediaFactory() - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) response = self.client.delete( self._delete_url(shared_live_media.video, shared_live_media), @@ -61,7 +61,7 @@ def test_api_shared_live_media_delete_instructor(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) self.assertTrue(SharedLiveMedia.objects.exists()) @@ -250,7 +250,7 @@ def test_api_shared_live_media_delete_active(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) self.assertTrue(SharedLiveMedia.objects.exists()) diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_initiate_upload.py b/src/backend/marsha/core/tests/api/shared_live_media/test_initiate_upload.py index 3825a6c0d9..82b9a2b581 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_initiate_upload.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_initiate_upload.py @@ -56,7 +56,7 @@ def test_api_shared_live_media_initiate_upload_student(self): shared_live_media = SharedLiveMediaFactory() - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) response = self.client.post( self._post_url(shared_live_media.video, shared_live_media), @@ -80,7 +80,7 @@ def test_api_shared_live_media_initiate_upload_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) now = datetime(2021, 12, 2, tzinfo=baseTimezone.utc) @@ -144,7 +144,7 @@ def test_api_shared_live_media_initiate_upload_file_without_extension(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) now = datetime(2021, 12, 2, tzinfo=baseTimezone.utc) @@ -208,7 +208,7 @@ def test_api_shared_live_media_initiate_upload_file_without_mimetype(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) now = datetime(2021, 12, 2, tzinfo=baseTimezone.utc) @@ -239,7 +239,7 @@ def test_api_shared_live_media_initiate_upload_file_wrong_mimetype(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) now = datetime(2021, 12, 2, tzinfo=baseTimezone.utc) diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_list.py b/src/backend/marsha/core/tests/api/shared_live_media/test_list.py index 74fb32a025..334c4009dd 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_list.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_list.py @@ -62,7 +62,7 @@ def test_api_shared_live_media_list_student(self): nb_pages=3, ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video), @@ -94,7 +94,7 @@ def test_api_shared_live_media_list_instructor(self): nb_pages=3, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video), @@ -180,7 +180,7 @@ def test_api_shared_live_media_list_instructor_other_video(self): video=other_video, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(other_video), @@ -224,7 +224,7 @@ def test_api_shared_live_media_list_instructor_ready_to_show_and_signed_url_acti nb_pages=3, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # fix the time so that the url signature is deterministic and can be checked now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_retrieve.py b/src/backend/marsha/core/tests/api/shared_live_media/test_retrieve.py index a94c50ceeb..0abcd61a46 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_retrieve.py @@ -54,7 +54,7 @@ def test_api_shared_live_media_read_detail_student_not_ready_to_show(self): nb_pages=None, ) - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) response = self.client.get( self._get_url(shared_live_media.video, shared_live_media), @@ -92,7 +92,7 @@ def test_api_shared_live_media_read_detail_student_ready_to_show(self): video__id="d9d7049c-5a3f-4070-a494-e6bf0bd8b9fb", ) - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) response = self.client.get( self._get_url(shared_live_media.video, shared_live_media), @@ -154,7 +154,7 @@ def test_api_shared_live_media_read_detail_student_ready_to_show_and_signed_url_ video__id="d9d7049c-5a3f-4070-a494-e6bf0bd8b9fb", ) - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) # fix the time so that the url signature is deterministic and can be checked now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) @@ -244,7 +244,7 @@ def test_api_shared_live_media_read_detail_student_ready_to_show_and_show_downlo video__id="d9d7049c-5a3f-4070-a494-e6bf0bd8b9fb", ) - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) # fix the time so that the url signature is deterministic and can be checked now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) @@ -315,7 +315,7 @@ def test_api_shared_live_media_read_detail_instructor_not_ready_to_show(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, permissions__can_update=False, ) @@ -356,7 +356,7 @@ def test_api_shared_live_media_read_detail_instructor_ready_to_show(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, permissions__can_update=False, ) @@ -421,7 +421,7 @@ def test_api_shared_live_media_read_detail_instructor_ready_to_show_and_signed_u ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, permissions__can_update=False, ) @@ -497,7 +497,7 @@ def test_api_shared_live_media_read_detail_other_video(self): other_video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=other_video.playlist, + playlist=other_video.playlist, roles=[random.choice(["instructor", "administrator", "student"])], ) diff --git a/src/backend/marsha/core/tests/api/shared_live_media/test_update.py b/src/backend/marsha/core/tests/api/shared_live_media/test_update.py index ae735b411a..006a8f79f4 100644 --- a/src/backend/marsha/core/tests/api/shared_live_media/test_update.py +++ b/src/backend/marsha/core/tests/api/shared_live_media/test_update.py @@ -47,7 +47,7 @@ def test_api_shared_live_media_update_student(self): """A student can not update a shared live media.""" shared_live_media = SharedLiveMediaFactory() - jwt_token = StudentLtiTokenFactory(resource=shared_live_media.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=shared_live_media.video.playlist) response = self.client.put( self._update_url(shared_live_media.video, shared_live_media), @@ -63,7 +63,7 @@ def test_api_shared_live_media_update_instructor(self): shared_live_media = SharedLiveMediaFactory(title="update me!") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist + playlist=shared_live_media.video.playlist ) with mock.patch( diff --git a/src/backend/marsha/core/tests/api/thumbnails/test_create.py b/src/backend/marsha/core/tests/api/thumbnails/test_create.py index 5c985dc82e..ac2d16624f 100644 --- a/src/backend/marsha/core/tests/api/thumbnails/test_create.py +++ b/src/backend/marsha/core/tests/api/thumbnails/test_create.py @@ -159,7 +159,7 @@ def test_api_thumbnail_create_student(self): """Student users should not be able to create a thumbnail.""" video = VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -171,7 +171,7 @@ def test_api_thumbnail_create_instructor_or_admin(self): """LTI instructor or admin should be able to create a thumbnail.""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), @@ -199,7 +199,7 @@ def test_api_thumbnail_create_instructor_or_admin(self): def test_api_thumbnail_create_instructor_file_too_large(self): """Instructor users should not be able to create a thumbnail if file is too large""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), @@ -215,7 +215,7 @@ def test_api_thumbnail_create_instructor_file_too_large(self): def test_api_thumbnail_create_instructor_no_size_parameter_provided(self): """Instructor users shouldn't be able to create a thumbnail without a file size""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -232,7 +232,7 @@ def test_api_thumbnail_create_already_existing_instructor(self): video = VideoFactory() ThumbnailFactory(video=video) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( self._post_url(video), @@ -252,7 +252,7 @@ def test_api_thumbnail_instructor_create_in_read_only(self): thumbnail = ThumbnailFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/thumbnails/test_delete.py b/src/backend/marsha/core/tests/api/thumbnails/test_delete.py index cb96f8d2ee..551142711c 100644 --- a/src/backend/marsha/core/tests/api/thumbnails/test_delete.py +++ b/src/backend/marsha/core/tests/api/thumbnails/test_delete.py @@ -155,7 +155,7 @@ def test_api_thumbnail_delete_student(self): video = VideoFactory() thumbnail = ThumbnailFactory(video=video) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.delete( self._delete_url(video, thumbnail), @@ -165,7 +165,7 @@ def test_api_thumbnail_delete_student(self): def test_api_thumbnail_delete_instructor(self): """Instructor should be able to delete a thumbnail for its video.""" - jwt_token = InstructorOrAdminLtiTokenFactory(resource=self.some_video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=self.some_video.playlist) self.assertEqual(Thumbnail.objects.count(), 1) @@ -199,7 +199,7 @@ def test_api_thumbnail_delete_instructor_in_read_only(self): thumbnail = ThumbnailFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, permissions__can_update=False, ) @@ -216,7 +216,7 @@ def test_api_thumbnail_delete_instructor_other_video(self): video_other = VideoFactory() thumbnail = ThumbnailFactory(video=video_other) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video_token.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video_token.playlist) response = self.client.delete( self._delete_url(video_other, thumbnail), diff --git a/src/backend/marsha/core/tests/api/thumbnails/test_initiate_upload.py b/src/backend/marsha/core/tests/api/thumbnails/test_initiate_upload.py index c826021cc0..9ded4a0747 100644 --- a/src/backend/marsha/core/tests/api/thumbnails/test_initiate_upload.py +++ b/src/backend/marsha/core/tests/api/thumbnails/test_initiate_upload.py @@ -31,7 +31,7 @@ def test_api_thumbnail_initiate_upload_anonymous(self): def test_api_thumbnail_initiate_upload_student(self): """Student users should not be allowed to initiate an upload.""" thumbnail = ThumbnailFactory() - jwt_token = StudentLtiTokenFactory(resource=thumbnail.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=thumbnail.video.playlist) response = self.client.post( self._post_url(thumbnail.video, thumbnail), @@ -47,7 +47,7 @@ def test_api_thumbnail_initiate_upload_instructor(self): thumbnail = ThumbnailFactory( id="4ab8079e-ff4d-4d06-9922-4929e4f7a6eb", video=video, upload_state="ready" ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the upload policy for this thumbnail # It should generate a key file with the Unix timestamp of the present time @@ -101,7 +101,7 @@ def test_api_thumbnail_initiate_upload_instructor_read_only(self): thumbnail = ThumbnailFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, permissions__can_update=False, ) @@ -117,7 +117,7 @@ def test_api_thumbnail_initiate_upload_file_too_large(self): """It should not be possible to upload a thumbnail if its size is too large.""" video = VideoFactory(upload_state="ready") thumbnail = ThumbnailFactory(video=video, upload_state="ready") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the upload policy for this thumbnail # It should generate a key file with the Unix timestamp of the present time diff --git a/src/backend/marsha/core/tests/api/thumbnails/test_options.py b/src/backend/marsha/core/tests/api/thumbnails/test_options.py index 3a10e0c2a6..f18953dfa3 100644 --- a/src/backend/marsha/core/tests/api/thumbnails/test_options.py +++ b/src/backend/marsha/core/tests/api/thumbnails/test_options.py @@ -61,7 +61,7 @@ def test_api_thumbnail_options_as_instructor(self): can query the thumbnail options' endpoint. """ video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.options( self._options_url(video), HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -76,7 +76,7 @@ def test_api_thumbnail_options_as_student(self): can query the thumbnail options' endpoint. """ video = VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.options( self._options_url(video), HTTP_AUTHORIZATION=f"Bearer {jwt_token}" diff --git a/src/backend/marsha/core/tests/api/thumbnails/test_retrieve.py b/src/backend/marsha/core/tests/api/thumbnails/test_retrieve.py index 1a33a14f56..6286fa1c03 100644 --- a/src/backend/marsha/core/tests/api/thumbnails/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/thumbnails/test_retrieve.py @@ -172,7 +172,7 @@ def test_api_thumbnail_read_detail_student(self): video = VideoFactory() thumbnail = ThumbnailFactory(video=video) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video, thumbnail), @@ -186,7 +186,7 @@ def test_api_thumbnail_instructor_read_detail_in_read_only(self): thumbnail = ThumbnailFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, permissions__can_update=False, ) @@ -205,7 +205,7 @@ def test_api_thumbnail_read_detail_token_user(self): ) thumbnail = ThumbnailFactory(video=video, upload_state="pending") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(thumbnail.video, thumbnail), @@ -232,7 +232,7 @@ def test_api_thumbnail_administrator_read_detail_in_read_only(self): thumbnail = ThumbnailFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, permissions__can_update=False, ) @@ -252,7 +252,7 @@ def test_api_thumbnail_read_detail_admin_user(self): thumbnail = ThumbnailFactory(video=video, upload_state="pending") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, roles=["administrator"], ) @@ -289,7 +289,7 @@ def test_api_thumbnail_read_ready_thumbnail(self): upload_state="ready", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( self._get_url(video, thumbnail), diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_create.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_create.py index c9b7f2977c..7df0094255 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_create.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_create.py @@ -31,7 +31,7 @@ def test_api_timed_text_track_create_anonymous(self): def test_api_timed_text_track_create_token_user(self): """A token user should be able to create a timed text track for an existing video.""" video = VideoFactory(id="f8c30d0d-2bb4-440d-9e8d-f4b231511f1f") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"language": "fr", "size": 10} response = self.client.post( @@ -60,7 +60,7 @@ def test_api_timed_text_track_create_token_user(self): def test_api_timed_text_create_token_user_track_no_size(self): """A token user shouldn't be able to create a track if size param is not specified""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"language": "fr"} response = self.client.post( @@ -80,7 +80,7 @@ def test_api_timed_text_create_token_user_track_no_size(self): def test_api_timed_text_track_create_token_user_file_too_large(self): """A token user shouldn't be able to create a timed text track with a too large size""" video = VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"language": "fr", "video": str(video.pk), "size": 100} response = self.client.post( @@ -101,7 +101,7 @@ def test_api_timed_text_track_create_instructor_in_read_only(self): timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_delete.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_delete.py index 141d92eb59..709101bd2d 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_delete.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_delete.py @@ -74,7 +74,7 @@ def test_api_timed_text_track_delete_detail_token_user(self): # Delete the timed text tracks using the JWT token for timed_text_track in timed_text_tracks: jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, ) response = self.client.delete( self._delete_url(timed_text_track.video, timed_text_track), @@ -111,7 +111,7 @@ def test_api_timed_text_track_delete_instructor_in_read_only(self): timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_initiate_upload.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_initiate_upload.py index 413b4c7676..4862e75775 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_initiate_upload.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_initiate_upload.py @@ -47,7 +47,7 @@ def test_api_timed_text_track_initiate_upload_token_user(self): mode="cc", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Create other timed text tracks to check that their upload state are unaffected @@ -151,7 +151,7 @@ def test_api_timed_text_track_instructor_initiate_upload_in_read_only(self): timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) @@ -467,7 +467,7 @@ def test_api_timed_text_track_initiate_upload_file_too_large(self): upload_state=random.choice(["ready", "error"]), mode="cc", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=track.video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=track.video.playlist) # Get the upload policy for this timed text track # It should generate a key file with the Unix timestamp of the present time diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_list.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_list.py index 714900072a..a59a9c6b32 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_list.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_list.py @@ -38,7 +38,7 @@ def test_api_timed_text_track_read_list_token_user(self): TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track_one.video.playlist + playlist=timed_text_track_one.video.playlist ) response = self.client.get( diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_options.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_options.py index 8dc0948df5..fbbf863f21 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_options.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_options.py @@ -66,7 +66,7 @@ def test_api_timed_text_track_options_as_instructor(self): """The details of choices fields should be available via http options for an instructor.""" timed_text_track = TimedTextTrackFactory(language="af") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) @@ -75,7 +75,7 @@ def test_api_timed_text_track_options_as_instructor(self): def test_api_timed_text_track_options_as_student(self): """The details of choices fields should be available via http options for a student.""" timed_text_track = TimedTextTrackFactory(language="af") - jwt_token = StudentLtiTokenFactory(resource=timed_text_track.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=timed_text_track.video.playlist) self.assert_jwt_can_query_options(jwt_token, timed_text_track) @@ -83,7 +83,7 @@ def test_api_timed_text_track_options_as_administrator(self): """The details of choices fields should be available via http options for an admin.""" timed_text_track = TimedTextTrackFactory(language="af") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, roles=["administrator"], ) @@ -106,7 +106,7 @@ def test_api_timed_text_track_options_authenticated(self): mode="cc", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) self.assert_jwt_can_query_options(jwt_token, timed_text_track) diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_retrieve.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_retrieve.py index 0aac2a9a76..52408ce109 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_retrieve.py @@ -41,7 +41,7 @@ def test_api_timed_text_track_read_detail_anonymous(self): def test_api_timed_text_track_read_detail_student(self): """Student users should not be allowed to read a timed text track detail.""" timed_text_track = TimedTextTrackFactory() - jwt_token = StudentLtiTokenFactory(resource=timed_text_track.video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=timed_text_track.video.playlist) # Get the timed text track using the JWT token response = self.client.get( self._get_url(timed_text_track.video, timed_text_track), @@ -67,7 +67,7 @@ def test_api_timed_text_track_read_detail_token_user(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Get the timed text track using the JWT token @@ -126,7 +126,7 @@ def test_api_timed_text_track_without_extension_read_detail_token_user(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Get the timed text track using the JWT token @@ -182,7 +182,7 @@ def test_api_timed_text_track_read_detail_admin_user(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, roles=["administrator"], ) @@ -234,7 +234,7 @@ def test_api_timed_text_track_read_instructor_in_read_only(self): timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) @@ -252,7 +252,7 @@ def test_api_timed_text_track_read_detail_token_user_no_active_stamp(self): """ timed_text_track = TimedTextTrackFactory(uploaded_on=None) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Get the timed text track using the JWT token @@ -272,7 +272,7 @@ def test_api_timed_text_track_read_detail_token_user_not_ready(self): uploaded_on=None, upload_state=random.choice(["pending", "error", "ready"]) ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Get the timed_text_track linked to the JWT token @@ -302,7 +302,7 @@ def test_api_timed_text_track_read_detail_token_user_signed_urls(self, _mock_ope extension="srt", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) # Get the timed_text_track via the API using the JWT token diff --git a/src/backend/marsha/core/tests/api/timed_text_tracks/test_update.py b/src/backend/marsha/core/tests/api/timed_text_tracks/test_update.py index 9639ffa81a..24b5541c36 100644 --- a/src/backend/marsha/core/tests/api/timed_text_tracks/test_update.py +++ b/src/backend/marsha/core/tests/api/timed_text_tracks/test_update.py @@ -37,7 +37,7 @@ def test_api_timed_text_track_update_detail_token_user_language(self): """Token users should be able to update the language of their timed_text_track.""" timed_text_track = TimedTextTrackFactory(language="fr") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -60,7 +60,7 @@ def test_api_timed_text_track_update_detail_token_user_closed_captioning(self): """Token users should be able to update the mode flag through the API.""" timed_text_track = TimedTextTrackFactory(mode="cc") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -84,7 +84,7 @@ def test_api_timed_text_track_update_detail_token_user_active_stamp(self): """Token users trying to update "active_stamp" through the API should be ignored.""" timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -109,7 +109,7 @@ def test_api_timed_text_track_update_detail_token_user_upload_state(self): """Token users trying to update "upload_state" through the API should be ignored.""" timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -135,7 +135,7 @@ def test_api_timed_text_track_update_instructor_in_read_only(self): timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, permissions__can_update=False, ) @@ -322,7 +322,7 @@ def test_api_timed_text_track_patch_detail_token_user_stamp_and_state(self): """ timed_text_track = TimedTextTrackFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) self.assertEqual(timed_text_track.upload_state, "pending") self.assertIsNone(timed_text_track.uploaded_on) @@ -346,7 +346,7 @@ def test_api_timed_text_track_update_detail_token_id(self): timed_text_track = TimedTextTrackFactory() original_id = timed_text_track.id jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -371,7 +371,7 @@ def test_api_timed_text_track_update_detail_token_video(self): timed_text_track = TimedTextTrackFactory() original_video = timed_text_track.video jwt_token = InstructorOrAdminLtiTokenFactory( - resource=timed_text_track.video.playlist + playlist=timed_text_track.video.playlist ) response = self.client.get( @@ -395,7 +395,7 @@ def test_api_timed_text_track_update_detail_token_user_other_video(self): """Token users are not allowed to update a timed text track related to another video.""" other_video = VideoFactory() timed_text_track_update = TimedTextTrackFactory(language="en") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=other_video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=other_video.playlist) data = {"language": "fr", "size": 10} response = self.client.put( diff --git a/src/backend/marsha/core/tests/api/video/test_bulk_destroy.py b/src/backend/marsha/core/tests/api/video/test_bulk_destroy.py index e4483885f4..38c8c4cba6 100644 --- a/src/backend/marsha/core/tests/api/video/test_bulk_destroy.py +++ b/src/backend/marsha/core/tests/api/video/test_bulk_destroy.py @@ -34,7 +34,7 @@ def test_api_video_bulk_delete_detail_anonymous(self): def test_api_video_bulk_delete_detail_token_user(self): """A token user associated to a video should not be able to delete it or any other.""" video1 = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video1.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video1.playlist) # Try deleting the video linked to the JWT token and the other one response = self.client.delete( @@ -50,7 +50,7 @@ def test_api_video_bulk_delete_detail_token_user(self): def test_api_video_bulk_delete_detail_student(self): """Student users should not be able to delete a video.""" video1 = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video1.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video1.playlist) response = self.client.delete( self._api_url(), @@ -241,7 +241,7 @@ def test_api_video_instructor_bulk_delete_video_in_read_only(self): video1 = factories.VideoFactory() video2 = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video1.playlist, + playlist=video1.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/video/test_create.py b/src/backend/marsha/core/tests/api/video/test_create.py index 81e6b22a9e..b8191bbbab 100644 --- a/src/backend/marsha/core/tests/api/video/test_create.py +++ b/src/backend/marsha/core/tests/api/video/test_create.py @@ -9,7 +9,7 @@ from marsha.core.api import timezone from marsha.core.defaults import INITIALIZED, STATE_CHOICES from marsha.core.simple_jwt.factories import ( - PlaylistLtiTokenFactory, + InstructorOrAdminLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -39,7 +39,7 @@ def test_api_video_create_token_user_playlist_preexists(self): def test_api_video_create_student(self): """Student users should not be able to create videos.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( "/api/videos/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -47,18 +47,6 @@ def test_api_video_create_student(self): self.assertEqual(response.status_code, 403) self.assertEqual(models.Video.objects.count(), 1) - def test_api_video_create_student_with_playlist_token(self): - """A student with a playlist token should not be able to create a video.""" - jwt_token = PlaylistLtiTokenFactory(roles=["student"]) - - response = self.client.post( - "/api/videos/", - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - ) - - self.assertEqual(response.status_code, 403) - self.assertEqual(models.Video.objects.count(), 0) - def test_api_video_create_staff_or_user(self): """Users authenticated via a session should not be able to create videos.""" for user in [factories.UserFactory(), factories.UserFactory(is_staff=True)]: @@ -546,7 +534,7 @@ def test_api_video_create_instructor_with_playlist_token(self): """ playlist = factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(models.Video.objects.count(), 0) diff --git a/src/backend/marsha/core/tests/api/video/test_destroy.py b/src/backend/marsha/core/tests/api/video/test_destroy.py index 5ba977c630..749527989a 100644 --- a/src/backend/marsha/core/tests/api/video/test_destroy.py +++ b/src/backend/marsha/core/tests/api/video/test_destroy.py @@ -30,7 +30,7 @@ def test_api_video_delete_detail_anonymous(self): def test_api_video_delete_detail_token_user(self): """A token user associated to a video should not be able to delete it or any other.""" videos = factories.VideoFactory.create_batch(2) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=videos[0].playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=videos[0].playlist) # Try deleting the video linked to the JWT token and the other one for video in videos: @@ -44,7 +44,7 @@ def test_api_video_delete_detail_token_user(self): def test_api_video_delete_detail_student(self): """Student users should not be able to delete a video.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.delete( f"/api/videos/{video.id}/", @@ -180,7 +180,7 @@ def test_api_video_instructor_delete_video_in_read_only(self): """An instructor with read_only set to true should not be able to delete the video.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/video/test_harvest_live.py b/src/backend/marsha/core/tests/api/video/test_harvest_live.py index 789434b265..895ced95b9 100644 --- a/src/backend/marsha/core/tests/api/video/test_harvest_live.py +++ b/src/backend/marsha/core/tests/api/video/test_harvest_live.py @@ -180,7 +180,7 @@ def test_api_video_instructor_harvest_live_in_read_only(self): """An instructor with read_only set to true should not be able to harvest a live.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -193,7 +193,7 @@ def test_api_video_instructor_harvest_live_in_read_only(self): def test_api_video_student_harvest_live(self): """A student should not be able to harvest a live.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( f"/api/videos/{video.id}/harvest-live/", @@ -227,7 +227,7 @@ def test_api_video_instructor_harvest_idle_live(self): live_type=JITSI, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.post( f"/api/videos/{video.id}/harvest-live/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -280,7 +280,7 @@ def test_api_video_instructor_harvest_paused_live_recording_slice(self): }, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch.object(timezone, "now", return_value=stop), mock.patch.object( api.video, "delete_aws_element_stack" @@ -431,7 +431,7 @@ def test_api_video_instructor_harvest_paused_live_no_recording_slice(self): }, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch.object(timezone, "now", return_value=stop), mock.patch.object( api.video, "delete_aws_element_stack" @@ -495,7 +495,7 @@ def test_api_video_instructor_harvest_paused_live_missing_manifest(self): }, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch.object( api.video, "delete_aws_element_stack" @@ -595,7 +595,7 @@ def test_api_video_instructor_harvest_live_wrong_live_state(self): ), live_type=JITSI, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups" diff --git a/src/backend/marsha/core/tests/api/video/test_initiate_live.py b/src/backend/marsha/core/tests/api/video/test_initiate_live.py index 70b84f1489..7de52073a0 100644 --- a/src/backend/marsha/core/tests/api/video/test_initiate_live.py +++ b/src/backend/marsha/core/tests/api/video/test_initiate_live.py @@ -10,7 +10,6 @@ from marsha.core.defaults import JITSI from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, ) @@ -36,7 +35,7 @@ def test_api_video_instructor_initiate_live_in_read_only(self): """An instructor with read_only set to true should not be able to initiate a live.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -49,7 +48,7 @@ def test_api_video_instructor_initiate_live_in_read_only(self): def test_api_video_student_initiate_live(self): """A student should not be able to initiate a live.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( f"/api/videos/{video.id}/initiate-live/", @@ -82,82 +81,7 @@ def test_api_video_instructor_initiate_live(self): playlist__title="foo bar", playlist__lti_id="course-v1:ufr+mathematics+00001", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) - with mock.patch( - "marsha.websocket.utils.channel_layers_utils.dispatch_video" - ) as mock_dispatch_video: - response = self.client.post( - f"/api/videos/{video.id}/initiate-live/", - {"type": "raw"}, - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - ) - video.refresh_from_db() - mock_dispatch_video.assert_called_with(video, to_admin=True) - - self.assertEqual(response.status_code, 200) - content = json.loads(response.content) - - self.assertEqual( - content, - { - "active_shared_live_media": None, - "active_shared_live_media_page": None, - "allow_recording": True, - "can_edit": True, - "description": video.description, - "estimated_duration": None, - "has_chat": True, - "has_live_media": True, - "id": str(video.id), - "is_live": True, - "title": video.title, - "active_stamp": None, - "is_public": False, - "is_ready_to_show": True, - "is_recording": False, - "is_scheduled": False, - "join_mode": "approval", - "show_download": True, - "starting_at": None, - "upload_state": "pending", - "thumbnail": None, - "timed_text_tracks": [], - "urls": None, - "should_use_subtitle_as_transcript": False, - "has_transcript": False, - "participants_asking_to_join": [], - "participants_in_discussion": [], - "playlist": { - "id": str(video.playlist.id), - "title": "foo bar", - "lti_id": "course-v1:ufr+mathematics+00001", - }, - "recording_time": 0, - "retention_date": None, - "shared_live_medias": [], - "live_state": "idle", - "live_info": {}, - "xmpp": None, - "live_type": "raw", - "tags": [], - "license": None, - }, - ) - - def test_api_video_instructor_initiate_live_with_playlist_token(self): - """ - Initiate a live with playlist token. - - Used in the context of a lti select request (deep linking). - """ - video = factories.VideoFactory( - id="27a23f52-3379-46a2-94fa-697b59cfe3c7", - playlist__title="foo bar", - playlist__lti_id="course-v1:ufr+mathematics+00001", - ) - jwt_token = PlaylistLtiTokenFactory( - resource=video.playlist, playlist=video.playlist - ) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video" ) as mock_dispatch_video: @@ -226,7 +150,7 @@ def test_api_video_instructor_initiate_jitsi_live(self): playlist__title="foo bar", playlist__lti_id="course-v1:ufr+mathematics+00001", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video" @@ -307,7 +231,7 @@ def test_api_video_instructor_initiate_jitsi_live_with_token(self): playlist__title="foo bar", playlist__lti_id="course-v1:ufr+mathematics+00001", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) now = datetime(2022, 5, 4, tzinfo=baseTimezone.utc) with mock.patch( diff --git a/src/backend/marsha/core/tests/api/video/test_initiate_upload.py b/src/backend/marsha/core/tests/api/video/test_initiate_upload.py index 083c637763..73a94eedec 100644 --- a/src/backend/marsha/core/tests/api/video/test_initiate_upload.py +++ b/src/backend/marsha/core/tests/api/video/test_initiate_upload.py @@ -37,7 +37,7 @@ def test_api_video_instructor_initiate_upload_in_read_only(self): """An instructor with read_only set to true should not be able to initiate an upload.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -54,7 +54,7 @@ def test_api_video_initiate_upload_token_user(self): id="27a23f52-3379-46a2-94fa-697b59cfe3c7", upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Create another video to check that its upload state is unaffected other_video = factories.VideoFactory( @@ -374,7 +374,7 @@ def test_api_video_initiate_upload_file_without_size(self): id="27a23f52-3379-46a2-94fa-697b59cfe3c7", upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( @@ -399,7 +399,7 @@ def test_api_video_initiate_upload_file_too_large(self): id="27a23f52-3379-46a2-94fa-697b59cfe3c7", upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( diff --git a/src/backend/marsha/core/tests/api/video/test_jitsi_info.py b/src/backend/marsha/core/tests/api/video/test_jitsi_info.py index bc7a77b3f4..90432f2a44 100644 --- a/src/backend/marsha/core/tests/api/video/test_jitsi_info.py +++ b/src/backend/marsha/core/tests/api/video/test_jitsi_info.py @@ -33,7 +33,7 @@ def test_jitsi_info_anonymous(self): def test_jitsi_info_for_a_student(self): """A student user can not fetch jitsi info.""" video = VideoFactory(live_state=RUNNING, live_type=JITSI) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/", @@ -46,7 +46,7 @@ def test_jitsi_info_for_an_admin(self): An instructor or an adminstrator with a resource token should be able to fetch jitsi info. """ video = VideoFactory(live_state=RUNNING, live_type=JITSI) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/", @@ -75,7 +75,7 @@ def test_jitsi_info_for_an_admin_moderator_not_specified(self): When the moderator query string is not specified, the False value should be used. """ video = VideoFactory(live_state=RUNNING, live_type=JITSI) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/", @@ -117,7 +117,7 @@ def test_jitsi_info_admin_user_moderator_false_specified(self): not be in the response. """ video = VideoFactory(live_state=RUNNING, live_type=JITSI) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/?moderator=false", @@ -159,7 +159,7 @@ def test_jitsi_info_admin_user_moderator_true_specified(self): be in the response. """ video = VideoFactory(live_state=RUNNING, live_type=JITSI) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/?moderator=true", @@ -277,7 +277,7 @@ def test_jitsi_info_on_non_live_video(self): """ video = VideoFactory(live_state=None, live_type=None) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/", @@ -291,7 +291,7 @@ def test_jitsi_info_on_live_not_jitsi(self): """ video = VideoFactory(live_state=RUNNING, live_type=RAW) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/jitsi/", diff --git a/src/backend/marsha/core/tests/api/video/test_list.py b/src/backend/marsha/core/tests/api/video/test_list.py index 4642eafb7a..71e764e524 100644 --- a/src/backend/marsha/core/tests/api/video/test_list.py +++ b/src/backend/marsha/core/tests/api/video/test_list.py @@ -31,7 +31,7 @@ def test_api_video_read_list_token_user(self): """ video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/video/test_live_pairing.py b/src/backend/marsha/core/tests/api/video/test_live_pairing.py index ec00208085..2d03a24213 100644 --- a/src/backend/marsha/core/tests/api/video/test_live_pairing.py +++ b/src/backend/marsha/core/tests/api/video/test_live_pairing.py @@ -170,7 +170,7 @@ def test_pairing_secret_by_playlist_admin(self): def test_api_video_student_pairing_secret(self): """A student should not be able to request a live pairing secret.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/pairing-secret/", @@ -199,7 +199,7 @@ def test_api_video_pairing_secret_staff_or_user(self): def test_api_video_instructor_pairing_secret_non_jitsi(self): """A request related to a non jitsi video should raise a 400 error.""" video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/pairing-secret/", @@ -215,7 +215,7 @@ def test_api_video_instructor_pairing_secret_non_jitsi(self): def test_api_video_instructor_pairing_secret_1st_request(self): """An instructor should be able to request a live pairing secret.""" video = factories.VideoFactory(live_state=IDLE, live_type=JITSI) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/pairing-secret/", @@ -235,7 +235,7 @@ def test_api_video_instructor_pairing_secret_2nd_request(self): live_pairing = LivePairingFactory(video=video) previous_secret = live_pairing.secret - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/pairing-secret/", @@ -256,7 +256,7 @@ def test_api_video_pairing_secret_delete_expired(self): ) with mock.patch.object(timezone, "now", return_value=expired_date): video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) self.client.get( f"/api/videos/{video.id}/pairing-secret/", @@ -270,7 +270,7 @@ def test_api_video_pairing_secret_post(self): live_pairing = LivePairingFactory() initial_secret = live_pairing.secret jwt_token = InstructorOrAdminLtiTokenFactory( - resource=live_pairing.video.playlist + playlist=live_pairing.video.playlist ) response = self.client.post( @@ -289,7 +289,7 @@ def test_api_video_pairing_secret_patch(self): live_pairing = LivePairingFactory() initial_secret = live_pairing.secret jwt_token = InstructorOrAdminLtiTokenFactory( - resource=live_pairing.video.playlist + playlist=live_pairing.video.playlist ) response = self.client.patch( @@ -308,7 +308,7 @@ def test_api_video_pairing_secret_put(self): live_pairing = LivePairingFactory() initial_secret = live_pairing.secret jwt_token = InstructorOrAdminLtiTokenFactory( - resource=live_pairing.video.playlist + playlist=live_pairing.video.playlist ) response = self.client.put( diff --git a/src/backend/marsha/core/tests/api/video/test_live_participants_asking_to_join.py b/src/backend/marsha/core/tests/api/video/test_live_participants_asking_to_join.py index 0b844e7fc3..91e582373f 100644 --- a/src/backend/marsha/core/tests/api/video/test_live_participants_asking_to_join.py +++ b/src/backend/marsha/core/tests/api/video/test_live_participants_asking_to_join.py @@ -218,7 +218,7 @@ def test_api_video_participants_post_asking_to_join_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -267,7 +267,7 @@ def test_api_video_participants_post_asking_to_join_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -322,7 +322,7 @@ def test_api_video_participants_post_asking_to_join_invalid_participants(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -361,7 +361,7 @@ def test_api_video_participants_post_asking_to_join_invalid_empty(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -399,7 +399,7 @@ def test_api_video_participants_post_asking_to_join_extra_data(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -458,7 +458,7 @@ def test_api_video_participants_post_asking_to_join_no_change(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -496,7 +496,7 @@ def test_api_video_participants_post_asking_to_join_join_mode_denied(self): video = VideoFactory(join_mode=DENIED) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -543,7 +543,7 @@ def test_api_video_participants_delete_asking_to_join_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -592,7 +592,7 @@ def test_api_video_participants_delete_asking_to_join_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -639,7 +639,7 @@ def test_api_video_participants_delete_asking_to_join_invalid_participants(self) video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -678,7 +678,7 @@ def test_api_video_participants_delete_asking_to_join_invalid_empty(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -723,7 +723,7 @@ def test_api_video_participants_delete_asking_to_join_extra_data(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -777,7 +777,7 @@ def test_api_video_participants_delete_asking_to_join_no_change(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) diff --git a/src/backend/marsha/core/tests/api/video/test_live_participants_joined.py b/src/backend/marsha/core/tests/api/video/test_live_participants_joined.py index d6c8244ae1..82add9c79f 100644 --- a/src/backend/marsha/core/tests/api/video/test_live_participants_joined.py +++ b/src/backend/marsha/core/tests/api/video/test_live_participants_joined.py @@ -224,7 +224,7 @@ def test_api_video_participants_post_joined_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -273,7 +273,7 @@ def test_api_video_participants_post_joined_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -325,7 +325,7 @@ def test_api_video_participants_post_joined_invalid_participants(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -376,7 +376,7 @@ def test_api_video_participants_post_joined_instructor_join_mode_denied(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -423,7 +423,7 @@ def test_api_video_participants_delete_joined_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -472,7 +472,7 @@ def test_api_video_participants_delete_joined_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -519,7 +519,7 @@ def test_api_video_participants_delete_joined_invalid_participants(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -558,7 +558,7 @@ def test_api_video_participants_delete_joined_invalid_empty(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -603,7 +603,7 @@ def test_api_video_participants_delete_joined_extra_data(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -657,7 +657,7 @@ def test_api_video_participants_delete_joined_no_change(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) diff --git a/src/backend/marsha/core/tests/api/video/test_live_to_vod.py b/src/backend/marsha/core/tests/api/video/test_live_to_vod.py index 3117549688..c35275d2be 100644 --- a/src/backend/marsha/core/tests/api/video/test_live_to_vod.py +++ b/src/backend/marsha/core/tests/api/video/test_live_to_vod.py @@ -165,7 +165,7 @@ def test_api_video_instructor_harvested_live_to_vod(self): uploaded_on="2019-09-24 07:24:40+00", resolutions=[240, 480, 720], ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups" @@ -277,7 +277,7 @@ def test_api_video_instructor_non_harvested_live_to_vod(self): uploaded_on="2019-09-24 07:24:40+00", resolutions=[240, 480, 720], ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups" diff --git a/src/backend/marsha/core/tests/api/video/test_metadata.py b/src/backend/marsha/core/tests/api/video/test_metadata.py index 5ef34af42d..0bf230326c 100644 --- a/src/backend/marsha/core/tests/api/video/test_metadata.py +++ b/src/backend/marsha/core/tests/api/video/test_metadata.py @@ -20,7 +20,7 @@ def test_api_video_options_as_student(self): """A student can fetch the video options endpoint""" video = VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.options( "/api/videos/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" ) @@ -61,7 +61,7 @@ def test_api_video_options_as_instructor(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/core/tests/api/video/test_retrieve.py b/src/backend/marsha/core/tests/api/video/test_retrieve.py index c5a75d86ed..301b67b1c9 100644 --- a/src/backend/marsha/core/tests/api/video/test_retrieve.py +++ b/src/backend/marsha/core/tests/api/video/test_retrieve.py @@ -48,7 +48,7 @@ def test_api_video_read_detail_anonymous(self): def test_api_video_read_detail_student(self): """Student users should be allowed to read a video detail.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( f"/api/videos/{video.id}/", @@ -63,7 +63,7 @@ def test_api_video_read_detail_scheduled_video_student(self): live_state=IDLE, live_type=RAW, starting_at=starting_at ) self.assertTrue(video.is_scheduled) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( f"/api/videos/{video.id}/", @@ -83,7 +83,7 @@ def test_api_video_read_detail_scheduled_past_video_student(self): with mock.patch.object(timezone, "now", return_value=now): self.assertFalse(video.is_scheduled) self.assertEqual(video.live_state, IDLE) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( f"/api/videos/{video.id}/", @@ -95,7 +95,7 @@ def test_api_video_read_detail_student_other_video(self): """Student users should not be allowed to read an other video detail.""" video = factories.VideoFactory() other_video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( f"/api/videos/{other_video.id}/", @@ -111,7 +111,7 @@ def test_api_video_read_detail_student_join_modes(self): live_state=RUNNING, live_type=JITSI, ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( f"/api/videos/{video.id}/", @@ -126,7 +126,7 @@ def test_api_video_read_detail_admin_token_user(self): video = factories.VideoFactory(upload_state="pending") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, roles=["administrator"], ) @@ -173,7 +173,7 @@ def test_api_video_read_detail_token_user(self): video=video, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( @@ -369,7 +369,7 @@ def test_api_video_read_detail_token_user_nested_shared_live_media_urls_signed( video=video, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # fix the time so that the url signature is deterministic and can be checked now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) @@ -588,7 +588,7 @@ def test_api_video_read_detail_token_student_user_nested_shared_live_media_urls_ video=video, ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) # fix the time so that the url signature is deterministic and can be checked now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) @@ -779,7 +779,7 @@ def test_api_video_read_detail_xmpp_enabled_live_state_idle(self): ) jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id="Maths", consumer_site=str(video.playlist.consumer_site.id), ) @@ -842,7 +842,7 @@ def test_api_video_read_detail_as_instructor_in_read_only(self): video = factories.VideoFactory(upload_state="ready") jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -861,7 +861,7 @@ def test_api_video_read_detail_token_user_no_active_stamp(self): playlist__title="foo bar", playlist__lti_id="course-v1:ufr+mathematics+00001", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( @@ -929,7 +929,7 @@ def test_api_video_read_detail_token_user_not_sucessfully_uploaded(self): playlist__title="foo bar", playlist__lti_id="course-v1:ufr+mathematics+00001", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( @@ -1000,7 +1000,7 @@ def test_api_video_read_detail_token_user_signed_urls(self, _mock_open): resolutions=[144], playlist__title="foo", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token # fix the time so that the url signature is deterministic and can be checked @@ -1275,7 +1275,7 @@ def test_api_video_with_a_thumbnail(self): upload_state="ready", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Get the video linked to the JWT token response = self.client.get( diff --git a/src/backend/marsha/core/tests/api/video/test_shared_live_media.py b/src/backend/marsha/core/tests/api/video/test_shared_live_media.py index b2e0f041f4..0224bc5e28 100644 --- a/src/backend/marsha/core/tests/api/video/test_shared_live_media.py +++ b/src/backend/marsha/core/tests/api/video/test_shared_live_media.py @@ -547,7 +547,7 @@ def test_api_video_shared_live_media_start_student(self): shared_live_media = SharedLiveMediaFactory() jwt_token = StudentLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, context_id=str(shared_live_media.video.playlist.lti_id), consumer_site=str(shared_live_media.video.playlist.consumer_site.id), ) @@ -569,7 +569,7 @@ def test_api_video_shared_live_media_navigate_student(self): shared_live_media = SharedLiveMediaFactory() jwt_token = StudentLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) response = self.client.patch( @@ -589,7 +589,7 @@ def test_api_video_shared_live_media_end_student(self): shared_live_media = SharedLiveMediaFactory() jwt_token = StudentLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) response = self.client.patch( @@ -692,7 +692,7 @@ def test_api_video_shared_live_media_start_instructor_ready(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( channel_layers_utils, "dispatch_video_to_groups" @@ -906,7 +906,7 @@ def test_api_video_shared_live_media_start_not_ready(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -932,7 +932,7 @@ def test_api_video_shared_live_media_start_wrong_video_id(self): other_shared_live_media = SharedLiveMediaFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=other_shared_live_media.video.playlist, + playlist=other_shared_live_media.video.playlist, ) response = self.client.patch( @@ -959,7 +959,7 @@ def test_api_video_shared_live_media_start_wrong_sharedlivemedia_id(self): other_shared_live_media = SharedLiveMediaFactory(upload_state=READY) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1016,7 +1016,7 @@ def test_api_video_shared_live_media_start_already_started(self): shared_live_media = SharedLiveMediaFactory(video=video) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1075,7 +1075,7 @@ def test_api_video_shared_live_media_navigate_instructor(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1234,7 +1234,7 @@ def test_api_video_shared_live_media_navigate_no_active(self): ) video.shared_live_medias.set([shared_live_media]) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch.object( channel_layers_utils, "dispatch_video_to_groups" @@ -1295,7 +1295,7 @@ def test_api_video_shared_live_media_navigate_unexisting_page(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1357,7 +1357,7 @@ def test_api_video_shared_live_media_navigate_undefined_page(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1419,7 +1419,7 @@ def test_api_video_shared_live_media_navigate_missing_page(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1480,7 +1480,7 @@ def test_api_video_shared_live_media_end_instructor(self): video.shared_live_medias.set([shared_live_media]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=shared_live_media.video.playlist, + playlist=shared_live_media.video.playlist, ) with mock.patch.object( @@ -1626,7 +1626,7 @@ def test_api_video_shared_live_media_end_no_active(self): ) video.shared_live_medias.set([shared_live_media]) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch.object( channel_layers_utils, "dispatch_video_to_groups" diff --git a/src/backend/marsha/core/tests/api/video/test_start_live.py b/src/backend/marsha/core/tests/api/video/test_start_live.py index fd30440d3a..32c4d02bc9 100644 --- a/src/backend/marsha/core/tests/api/video/test_start_live.py +++ b/src/backend/marsha/core/tests/api/video/test_start_live.py @@ -203,7 +203,7 @@ def test_api_instructor_start_non_created_live(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -372,7 +372,7 @@ def test_api_instructor_start_already_created_live(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -527,7 +527,7 @@ def test_api_instructor_start_stopped_live(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -686,7 +686,7 @@ def test_api_instructor_start_harvested_live(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -867,7 +867,7 @@ def test_api_instructor_start_non_live_video(self): id="27a23f52-3379-46a2-94fa-697b59cfe3c7", upload_state=random.choice([s[0] for s in STATE_CHOICES]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # start a live video, with mock.patch.object(api.video, "start_live_channel"), mock.patch( @@ -894,7 +894,7 @@ def test_api_instructor_start_aws_raising_exception(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -944,7 +944,7 @@ def test_api_instructor_start_non_idle_or_stopped_live(self): ), live_type=RAW, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) with mock.patch( "marsha.websocket.utils.channel_layers_utils.dispatch_video_to_groups" diff --git a/src/backend/marsha/core/tests/api/video/test_start_stop_recording.py b/src/backend/marsha/core/tests/api/video/test_start_stop_recording.py index b734f6d921..3e1924751b 100644 --- a/src/backend/marsha/core/tests/api/video/test_start_stop_recording.py +++ b/src/backend/marsha/core/tests/api/video/test_start_stop_recording.py @@ -319,7 +319,7 @@ def test_api_video_recording_start_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -341,7 +341,7 @@ def test_api_video_recording_stop_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -419,7 +419,7 @@ def test_api_video_recording_start_instructor(self): self.assertEqual(video.recording_slices, []) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -553,7 +553,7 @@ def test_api_video_recording_start_not_allowed(self): self.assertEqual(video.recording_slices, []) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -618,7 +618,7 @@ def test_api_video_recording_start_live_not_running(self): self.assertEqual(video.recording_slices, []) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) @@ -685,7 +685,7 @@ def test_api_video_recording_stop_instructor_started_slice(self): self.assertEqual(video.recording_slices, [{"start": to_timestamp(start)}]) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, user__id="56255f3807599c377bf0e5bf072359fd", ) diff --git a/src/backend/marsha/core/tests/api/video/test_stats.py b/src/backend/marsha/core/tests/api/video/test_stats.py index 74237f3076..af17f1fb1a 100644 --- a/src/backend/marsha/core/tests/api/video/test_stats.py +++ b/src/backend/marsha/core/tests/api/video/test_stats.py @@ -173,7 +173,7 @@ def test_api_video_stats_student(self): video = VideoFactory() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, context_id=str(video.playlist.lti_id), consumer_site=str(video.playlist.consumer_site.id), ) @@ -218,7 +218,7 @@ def test_api_video_stats_instructor(self): video = VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, ) with mock.patch( diff --git a/src/backend/marsha/core/tests/api/video/test_stop_live.py b/src/backend/marsha/core/tests/api/video/test_stop_live.py index 2b4076757a..baf6e3452f 100644 --- a/src/backend/marsha/core/tests/api/video/test_stop_live.py +++ b/src/backend/marsha/core/tests/api/video/test_stop_live.py @@ -178,7 +178,7 @@ def test_api_video_instructor_stop_live_in_read_only(self): """An instructor with read_only set to true should not be able to stop a live.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -191,7 +191,7 @@ def test_api_video_instructor_stop_live_in_read_only(self): def test_api_video_student_stop_live(self): """A student should not be able to stop a live.""" video = factories.VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) response = self.client.post( f"/api/videos/{video.id}/stop-live/", @@ -249,7 +249,7 @@ def test_api_video_instructor_stop_live(self): }, live_type=RAW, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # stop a live video, now = datetime(2021, 11, 16, tzinfo=baseTimezone.utc) @@ -334,7 +334,7 @@ def test_api_instructor_stop_non_live_video(self): id="27a23f52-3379-46a2-94fa-697b59cfe3c7", upload_state=random.choice([s[0] for s in STATE_CHOICES]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # stop a live video, with mock.patch.object( @@ -359,7 +359,7 @@ def test_api_instructor_stop_non_running_live(self): live_state=random.choice([s[0] for s in LIVE_CHOICES if s[0] != "running"]), live_type=RAW, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # stop a live video, with mock.patch.object( @@ -410,7 +410,7 @@ def test_api_video_instructor_stop_live_recording_slice(self): }, live_type=RAW, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # stop a live video, with mock.patch.object(timezone, "now", return_value=stop), mock.patch.object( diff --git a/src/backend/marsha/core/tests/api/video/test_update.py b/src/backend/marsha/core/tests/api/video/test_update.py index 2fd877a773..d5a535f107 100644 --- a/src/backend/marsha/core/tests/api/video/test_update.py +++ b/src/backend/marsha/core/tests/api/video/test_update.py @@ -52,7 +52,7 @@ def test_api_video_update_detail_anonymous(self): def test_api_video_update_detail_student(self): """Student users should not be allowed to update a video through the API.""" video = factories.VideoFactory(title="my title") - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = {"title": "my new title"} response = self.client.put( @@ -72,7 +72,7 @@ def test_api_video_update_detail_student(self): def test_api_video_update_detail_token_user_title(self): """Token users should be able to update the title of their video through the API.""" video = factories.VideoFactory(title="my title") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"title": "my new title"} response = self.client.put( f"/api/videos/{video.id}/", @@ -87,7 +87,7 @@ def test_api_video_update_detail_token_user_title(self): def test_api_video_update_detail_token_user_title_null(self): """Token users can not set a null title.""" video = factories.VideoFactory(title="my title") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"title": None} response = self.client.put( f"/api/videos/{video.id}/", @@ -103,7 +103,7 @@ def test_api_video_update_detail_token_user_title_null(self): def test_api_video_update_detail_token_user_title_empty(self): """Token users can not set an empty title.""" video = factories.VideoFactory(title="my title") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"title": " "} response = self.client.put( f"/api/videos/{video.id}/", @@ -128,7 +128,7 @@ def test_api_video_update_detail_token_scheduled_date_future(self): live_state=IDLE, live_type=JITSI, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # set microseconds to 0 to compare date surely as serializer truncate them starting_at = (timezone.now() + timedelta(hours=1)).replace(microsecond=0) data = { @@ -220,7 +220,7 @@ def test_api_video_update_detail_token_scheduled_date_future_live_session(self): should_send_reminders=True, video=video, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # we only change the title response = self.client.put( f"/api/videos/{video.id}/", @@ -292,7 +292,7 @@ def test_api_video_update_detail_token_scheduled_date_past(self): title="my title", ) self.assertTrue(video.is_scheduled) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # try to set a date in the past # set microseconds to 0 to compare date surely as serializer truncate them @@ -330,7 +330,7 @@ def test_api_video_update_detail_token_scheduled_date_to_none(self): live_state=IDLE, live_type=JITSI, starting_at=starting_at, title="my title" ) self.assertTrue(video.is_scheduled) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"title": "title required", "starting_at": None} response = self.client.put( @@ -352,7 +352,7 @@ def test_api_video_update_detail_token_scheduled_with_previous_starting_at_alrea video = factories.VideoFactory( live_state=IDLE, live_type=RAW, starting_at=intial_starting_at ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # now is set to after initial starting_at now = intial_starting_at + timedelta(days=10) with mock.patch.object(timezone, "now", return_value=now): @@ -382,7 +382,7 @@ def test_api_video_update_detail_token_scheduled_with_previous_starting_at_alrea def test_api_video_update_detail_token_user_description(self): """Token users should be able to update the description of their video through the API.""" video = factories.VideoFactory(description="my description") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/", @@ -403,7 +403,7 @@ def test_api_video_update_detail_token_user_description(self): def test_api_video_update_detail_token_user_uploaded_on(self): """Token users trying to update "uploaded_on" through the API should be ignored.""" video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/", @@ -438,7 +438,7 @@ def test_api_video_update_detail_token_user_upload_state(self): uploaded_on="2019-09-24 07:24:40+00", resolutions=[240, 480, 720], ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/", @@ -540,7 +540,7 @@ def test_api_video_update_detail_token_user_join_mode(self): description="my description", join_mode=APPROVAL, ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/", @@ -564,7 +564,7 @@ def test_api_video_instructor_update_video_in_read_only(self): """An instructor with read_only set to true should not be able to update the video.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -594,7 +594,7 @@ def test_api_video_patch_video_anonymous(self): def test_api_video_patch_video_student(self): """Student users should not be allowed to patch a video through the API.""" video = factories.VideoFactory(title="my title") - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = {"title": "my new title"} response = self.client.patch( @@ -615,7 +615,7 @@ def test_api_video_instructor_patch_video_in_read_only(self): """An instructor with read_only set to true should not be able to patch the video.""" video = factories.VideoFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, permissions__can_update=False, ) @@ -635,7 +635,7 @@ def test_api_video_patch_detail_token_user_stamp(self): this field can only be updated by AWS via the separate update-state API endpoint. """ video = factories.VideoFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) self.assertIsNone(video.uploaded_on) data = {"active_stamp": "1533686400"} @@ -655,7 +655,7 @@ def test_api_video_update_detail_token_user_id(self): """Token users trying to update the ID of a video they own should be ignored.""" video = factories.VideoFactory() original_id = video.id - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) response = self.client.get( f"/api/videos/{video.id}/", @@ -678,7 +678,7 @@ def test_api_video_update_detail_token_user_other_video(self): """Token users should not be allowed to update another video through the API.""" video_token = factories.VideoFactory() video_update = factories.VideoFactory(title="my title") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video_token.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video_token.playlist) data = {"title": "my new title"} response = self.client.put( @@ -695,7 +695,7 @@ def test_api_video_update_detail_token_user_other_video(self): def test_api_video_patch_detail_token_user_description(self): """Token users should be able to patch fields on their video through the API.""" video = factories.VideoFactory(description="my description") - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"description": "my new description"} @@ -713,7 +713,7 @@ def test_api_video_patch_detail_token_user_is_public(self): """Instructors and administrators should be able to patch the public flag of their video through the API.""" video = factories.VideoFactory(is_public=False) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"is_public": True} response = self.client.patch( f"/api/videos/{video.id}/", @@ -731,7 +731,7 @@ def test_api_video_patch_detail_token_user_allow_recording(self): video = factories.VideoFactory() self.assertTrue(video.allow_recording) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"allow_recording": False} response = self.client.patch( f"/api/videos/{video.id}/", @@ -749,7 +749,7 @@ def test_api_video_patch_detail_token_user_tags(self): video = factories.VideoFactory() self.assertEqual(video.tags, []) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"tags": ["foo", "bar"]} response = self.client.patch( f"/api/videos/{video.id}/", @@ -767,7 +767,7 @@ def test_api_video_patch_detail_token_user_license(self): video = factories.VideoFactory() self.assertIsNone(video.license) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"license": CC_BY_SA} response = self.client.patch( f"/api/videos/{video.id}/", @@ -785,7 +785,7 @@ def test_api_video_patch_detail_token_user_estimated_duration(self): video = factories.VideoFactory() self.assertIsNone(video.estimated_duration) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) estimated_duration = timedelta(seconds=2100) data = {"estimated_duration": estimated_duration} response = self.client.patch( @@ -804,7 +804,7 @@ def test_api_video_patch_detail_token_user_estimated_duration_negative(self): video = factories.VideoFactory() self.assertIsNone(video.estimated_duration) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # from -7 days to -1 second estimated_duration = timedelta(seconds=random.randint(-604800, -1)) data = {"estimated_duration": estimated_duration} @@ -833,7 +833,7 @@ def test_api_video_patch_detail_token_user_estimated_duration_negative_one_secon video = factories.VideoFactory() self.assertIsNone(video.estimated_duration) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) estimated_duration = timedelta(seconds=-1) data = {"estimated_duration": estimated_duration} @@ -861,7 +861,7 @@ def test_api_video_patch_detail_token_user_has_chat(self): video = factories.VideoFactory() self.assertTrue(video.has_chat) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"has_chat": False} response = self.client.patch( f"/api/videos/{video.id}/", @@ -879,7 +879,7 @@ def test_api_video_patch_detail_token_user_has_live_media(self): video = factories.VideoFactory() self.assertTrue(video.has_live_media) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) data = {"has_live_media": False} response = self.client.patch( f"/api/videos/{video.id}/", @@ -928,7 +928,7 @@ def test_api_video_patch_by_instructor_scheduling_date_future(self): # starting_at is None there is no event scheduled self.assertFalse(video.is_scheduled) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # starting_at gets updated to a date in the future # set microseconds to 0 to compare date surely as serializer truncate them @@ -991,7 +991,7 @@ def test_api_patch_video_with_previous_starting_at_already_past(self): video = factories.VideoFactory( live_state=IDLE, live_type=RAW, starting_at=intial_starting_at ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # now is set after video.starting_at now = intial_starting_at + timedelta(days=10) with mock.patch.object(timezone, "now", return_value=now): @@ -1028,7 +1028,7 @@ def test_api_patch_video_with_live_state_set(self): ) self.assertFalse(video.is_scheduled) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) starting_at = timezone.now() + timedelta(days=10) response = self.client.patch( @@ -1221,7 +1221,7 @@ def test_api_update_video_with_live_state_set(self): ) self.assertFalse(video.is_scheduled) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) starting_at = timezone.now() + timedelta(hours=1) response = self.client.put( f"/api/videos/{video.id}/", @@ -1259,7 +1259,7 @@ def test_api_update_video_with_starting_at_past(self): self.assertTrue(video.starting_at > timezone.now()) self.assertTrue(video.is_scheduled) self.assertEqual(video.live_state, IDLE) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) # Mock now to the future to check video gets set to not scheduled future = timezone.now() + timedelta(hours=1) with mock.patch.object(timezone, "now", return_value=future): diff --git a/src/backend/marsha/core/tests/management_commands/test_send_reminders.py b/src/backend/marsha/core/tests/management_commands/test_send_reminders.py index 8af0693ec2..e18b213b28 100644 --- a/src/backend/marsha/core/tests/management_commands/test_send_reminders.py +++ b/src/backend/marsha/core/tests/management_commands/test_send_reminders.py @@ -1201,7 +1201,7 @@ def test_scenario_video_date_has_changed(self): video = VideoFactory( title="my title", live_state=IDLE, live_type=JITSI, starting_at=None ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=video.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=video.playlist) self.assertFalse(video.is_scheduled) livesession = LiveSessionFactory( anonymous_id=uuid.uuid4(), diff --git a/src/backend/marsha/core/tests/simple_jwt/test_factories.py b/src/backend/marsha/core/tests/simple_jwt/test_factories.py index 889f1172a1..269fb1b2ef 100644 --- a/src/backend/marsha/core/tests/simple_jwt/test_factories.py +++ b/src/backend/marsha/core/tests/simple_jwt/test_factories.py @@ -8,9 +8,9 @@ from marsha.core.models import INSTRUCTOR from marsha.core.simple_jwt.factories import ( LiveSessionLtiTokenFactory, - LTIResourceAccessTokenFactory, + LTIPlaylistAccessTokenFactory, ) -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.testing_utils import generate_passport_and_signed_lti_parameters @@ -44,9 +44,11 @@ def test_payload_keys(self): self.assertTrue(lti.verify()) session_id = uuid.uuid4() - jwt = ResourceAccessToken.for_lti(lti, {}, session_id, playlist_id) + jwt = PlaylistAccessToken.for_lti(lti, {}, session_id, playlist_id) - jwt_from_factory = LTIResourceAccessTokenFactory(playlist_id=playlist_id) + jwt_from_factory = LTIPlaylistAccessTokenFactory( + port_to_playlist_id=playlist_id + ) self.assertSetEqual( set(jwt.payload.keys()), @@ -60,13 +62,12 @@ class LiveSessionLtiTokenFactoryTestCase(TestCase): def test_payload_keys(self): """Tests the factory generates a payload with the same keys as the original method.""" session_id = uuid.uuid4() - jwt = ResourceAccessToken.for_live_session( + jwt = PlaylistAccessToken.for_live_session( LiveSessionFactory(is_from_lti_connection=True), session_id, ) jwt_from_factory = LiveSessionLtiTokenFactory() - self.assertSetEqual( set(jwt.payload.keys()), set(jwt_from_factory.payload.keys()), diff --git a/src/backend/marsha/core/tests/simple_jwt/test_tokens.py b/src/backend/marsha/core/tests/simple_jwt/test_tokens.py index aab360cd93..db727be623 100644 --- a/src/backend/marsha/core/tests/simple_jwt/test_tokens.py +++ b/src/backend/marsha/core/tests/simple_jwt/test_tokens.py @@ -10,8 +10,8 @@ from marsha.core.models import INSTRUCTOR, NONE, STUDENT from marsha.core.simple_jwt.tokens import ( LTISelectFormAccessToken, - ResourceAccessToken, - ResourceRefreshToken, + PlaylistAccessToken, + PlaylistRefreshToken, UserAccessToken, ) from marsha.core.tests.testing_utils import generate_passport_and_signed_lti_parameters @@ -86,20 +86,20 @@ def make_lti_instance(self, resource_id=None, role=None): return lti, passport - def test_for_resource_id(self): - """Test JWT initialization from `for_resource_id` method without LTI""" + def test_for_playlist_id(self): + """Test JWT initialization from `for_playlist_id` method without LTI""" session_id = str(uuid.uuid4()) - resource_id = str(uuid.uuid4()) + playlist_id = str(uuid.uuid4()) - refresh_token = ResourceRefreshToken.for_resource_id(resource_id, session_id) + refresh_token = PlaylistRefreshToken.for_playlist_id(playlist_id, session_id) token = refresh_token.access_token refresh_token.verify() # Must not raise token.verify() # Must not raise - self.assertEqual(refresh_token.payload["access_token_type"], "resource_access") - self.assertEqual(token.payload["token_type"], "resource_access") + self.assertEqual(refresh_token.payload["access_token_type"], "playlist_access") + self.assertEqual(token.payload["token_type"], "playlist_access") self.assertEqual(token.payload["session_id"], session_id) - self.assertEqual(token.payload["resource_id"], resource_id) + self.assertEqual(token.payload["playlist_id"], playlist_id) self.assertListEqual(token.payload["roles"], [NONE]) self.assertEqual(token.payload["locale"], "en_US") # settings.REACT_LOCALES[0] self.assertDictEqual( @@ -108,24 +108,24 @@ def test_for_resource_id(self): ) self.assertFalse(token.payload["maintenance"]) # settings.MAINTENANCE_MODE - token = ResourceAccessToken.for_resource_id( - resource_id, + token = PlaylistAccessToken.for_playlist_id( + playlist_id, session_id, roles=[STUDENT], ) token.verify() # Must not raise self.assertEqual(token.payload["roles"], [STUDENT]) - token = ResourceAccessToken.for_resource_id( - resource_id, + token = PlaylistAccessToken.for_playlist_id( + playlist_id, session_id, locale="fr_FR", ) token.verify() # Must not raise self.assertEqual(token.payload["locale"], "fr_FR") - token = ResourceAccessToken.for_resource_id( - resource_id, + token = PlaylistAccessToken.for_playlist_id( + playlist_id, session_id, permissions={"can_access_dashboard": True}, ) @@ -143,20 +143,20 @@ def test_for_lti(self): lti, passport = self.make_lti_instance(resource_id=resource_id) playlist_id = str(uuid.uuid4()) - refresh_token = ResourceRefreshToken.for_lti( + refresh_token = PlaylistRefreshToken.for_lti( lti, permissions, session_id, - playlist_id=playlist_id, + port_to_playlist_id=playlist_id, ) token = refresh_token.access_token refresh_token.verify() # Must not raise token.verify() # Must not raise - self.assertEqual(refresh_token.payload["access_token_type"], "resource_access") - self.assertEqual(token.payload["token_type"], "resource_access") + self.assertEqual(refresh_token.payload["access_token_type"], "playlist_access") + self.assertEqual(token.payload["token_type"], "playlist_access") self.assertEqual(token.payload["session_id"], session_id) - self.assertEqual(token.payload["resource_id"], playlist_id) + self.assertEqual(token.payload["playlist_id"], playlist_id) self.assertEqual(token.payload["roles"], [INSTRUCTOR]) self.assertEqual(token.payload["locale"], "en_US") self.assertDictEqual(token.payload["permissions"], permissions) @@ -182,20 +182,20 @@ def test_for_lti_with_playlist(self): lti, passport = self.make_lti_instance(resource_id=resource_id) playlist_id = str(uuid.uuid4()) - refresh_token = ResourceRefreshToken.for_lti( + refresh_token = PlaylistRefreshToken.for_lti( lti, permissions, session_id, - playlist_id=playlist_id, + port_to_playlist_id=playlist_id, ) token = refresh_token.access_token refresh_token.verify() # Must not raise token.verify() # Must not raise - self.assertEqual(refresh_token.payload["access_token_type"], "resource_access") - self.assertEqual(token.payload["token_type"], "resource_access") + self.assertEqual(refresh_token.payload["access_token_type"], "playlist_access") + self.assertEqual(token.payload["token_type"], "playlist_access") self.assertEqual(token.payload["session_id"], session_id) - self.assertEqual(token.payload["resource_id"], playlist_id) + self.assertEqual(token.payload["playlist_id"], playlist_id) self.assertEqual(token.payload["roles"], [INSTRUCTOR]) self.assertEqual(token.payload["locale"], "en_US") self.assertDictEqual(token.payload["permissions"], permissions) @@ -212,7 +212,7 @@ def test_for_lti_with_playlist(self): "username": "jane_doe", }, ) - self.assertEqual(token.payload["playlist_id"], playlist_id) + self.assertEqual(token.payload["port_to_playlist_id"], playlist_id) def test_for_live_session_anonymous(self): """Test JWT initialization from `for_live_session` method with public session.""" @@ -224,20 +224,20 @@ def test_for_live_session_anonymous(self): email="chantal@test-fun-mooc.fr", ) - refresh_token = ResourceRefreshToken.for_live_session(live_session, session_id) + refresh_token = PlaylistRefreshToken.for_live_session(live_session, session_id) token = refresh_token.access_token refresh_token.verify() # Must not raise token.verify() # Must not raise - self.assertEqual(refresh_token.payload["access_token_type"], "resource_access") - self.assertEqual(token.payload["token_type"], "resource_access") + self.assertEqual(refresh_token.payload["access_token_type"], "playlist_access") + self.assertEqual(token.payload["token_type"], "playlist_access") self.assertEqual(token.payload["session_id"], session_id) self.assertEqual(token.payload["locale"], "en_US") # settings.REACT_LOCALES[0] self.assertDictEqual(token.payload["permissions"], permissions) self.assertFalse(token.payload["maintenance"]) # settings.MAINTENANCE_MODE self.assertEqual( - token.payload["resource_id"], str(live_session.video.playlist.pk) + token.payload["playlist_id"], str(live_session.video.playlist.pk) ) self.assertDictEqual( token.payload["user"], @@ -264,13 +264,13 @@ def test_for_live_session_lti(self): self.assertTrue(live_session.is_from_lti_connection) - refresh_token = ResourceRefreshToken.for_live_session(live_session, session_id) + refresh_token = PlaylistRefreshToken.for_live_session(live_session, session_id) token = refresh_token.access_token refresh_token.verify() # Must not raise token.verify() # Must not raise - self.assertEqual(refresh_token.payload["access_token_type"], "resource_access") - self.assertEqual(token.payload["token_type"], "resource_access") + self.assertEqual(refresh_token.payload["access_token_type"], "playlist_access") + self.assertEqual(token.payload["token_type"], "playlist_access") self.assertEqual(token.payload["session_id"], session_id) self.assertEqual(token.payload["locale"], "en_US") # settings.REACT_LOCALES[0] self.assertDictEqual(token.payload["permissions"], permissions) @@ -280,7 +280,7 @@ def test_for_live_session_lti(self): token.payload["consumer_site"], str(video.playlist.consumer_site.pk) ) self.assertEqual(token.payload["context_id"], str(video.playlist.lti_id)) - self.assertEqual(token.payload["resource_id"], str(video.playlist.pk)) + self.assertEqual(token.payload["playlist_id"], str(video.playlist.pk)) self.assertDictEqual( token.payload["user"], { @@ -294,10 +294,10 @@ def test_for_live_session_lti(self): def test_verify_fails(self): """Test JWT when `verify` method fails.""" session_id = str(uuid.uuid4()) - resource_id = str(uuid.uuid4()) + playlist_id = str(uuid.uuid4()) # Build a proper token - token = ResourceAccessToken.for_resource_id(resource_id, session_id) + token = PlaylistAccessToken.for_playlist_id(playlist_id, session_id) # Mess with the permissions token.payload["permissions"] = {"can_break_everything": True} diff --git a/src/backend/marsha/core/tests/test_api_document.py b/src/backend/marsha/core/tests/test_api_document.py index 8d014d9d72..2a350c4b95 100644 --- a/src/backend/marsha/core/tests/test_api_document.py +++ b/src/backend/marsha/core/tests/test_api_document.py @@ -8,7 +8,6 @@ from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, ) @@ -42,7 +41,7 @@ def test_api_document_fetch_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=True, ) @@ -69,7 +68,7 @@ def test_api_document_fetch_instructor(self): title="bar baz", ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) response = self.client.get( f"/api/documents/{document.id}/", @@ -104,7 +103,7 @@ def test_api_document_fetch_instructor_read_only(self): document = DocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=False, ) @@ -128,7 +127,7 @@ def test_api_document_fetch_list_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=True, ) @@ -141,7 +140,7 @@ def test_api_fetch_list_instructor(self): """An instrustor should not be able to fetch a document list.""" document = DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) response = self.client.get( "/api/documents/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" @@ -158,19 +157,7 @@ def test_api_document_create_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, - permissions__can_update=True, - ) - - response = self.client.post( - "/api/documents/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - - def test_api_document_create_student_with_playlist_token(self): - """A student with a playlist token should not be able to create a document.""" - jwt_token = PlaylistLtiTokenFactory( - roles=["student"], + playlist=document.playlist, permissions__can_update=True, ) @@ -180,25 +167,10 @@ def test_api_document_create_student_with_playlist_token(self): self.assertEqual(response.status_code, 403) def test_api_document_create_instructor(self): - """An instrustor should not be able to create a document.""" - document = DocumentFactory() - - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) - - response = self.client.post( - "/api/documents/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - - def test_api_document_create_instructor_with_playlist_token(self): - """ - Create document with playlist token. - - Used in the context of a lti select request (deep linking). - """ + """An instructor should be able to create a document.""" playlist = PlaylistFactory(title="Playlist") - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(Document.objects.count(), 0) @@ -248,7 +220,7 @@ def test_api_document_delete_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=True, ) @@ -262,7 +234,7 @@ def test_api_document_delete_instructor(self): """An instructor should be able to delete a document.""" document = DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) response = self.client.delete( f"/api/documents/{document.id}/", @@ -281,7 +253,7 @@ def test_api_document_update_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=True, ) data = {"title": "new title"} @@ -299,7 +271,7 @@ def test_api_document_update_instructor_read_only(self): document = DocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=False, ) data = {"title": "new title"} @@ -316,7 +288,7 @@ def test_api_document_update_instructor(self): """An instructor should be able to update a document.""" document = DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) data = {"title": "new title"} response = self.client.put( @@ -334,7 +306,7 @@ def test_api_document_update_title_with_extension(self): """Serializer should remove the extension from the document title (if any).""" document = DocumentFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) data = {"title": "new title.pdf"} response = self.client.put( @@ -359,7 +331,7 @@ def test_api_document_initiate_upload_student(self): document = DocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=True, ) @@ -374,7 +346,7 @@ def test_api_document_initiate_upload_instructor_read_only(self): document = DocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=document.playlist, + playlist=document.playlist, permissions__can_update=False, ) @@ -391,7 +363,7 @@ def test_api_document_initiate_upload_instructor(self): upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( @@ -443,7 +415,7 @@ def test_api_document_initiate_upload_file_without_extension(self): upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( @@ -495,7 +467,7 @@ def test_api_document_initiate_upload_file_without_mimetype(self): upload_state=random.choice(["ready", "error"]), ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=document.playlist) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( diff --git a/src/backend/marsha/core/tests/test_api_playlist_portability.py b/src/backend/marsha/core/tests/test_api_playlist_portability.py index 5e608fd613..7fe8eb692b 100644 --- a/src/backend/marsha/core/tests/test_api_playlist_portability.py +++ b/src/backend/marsha/core/tests/test_api_playlist_portability.py @@ -14,7 +14,7 @@ class PlaylistPortabilityAPITest(TestCase): def _jwt_token(self, playlist): """Build JWT token for a playlist with admin or instructor role.""" - jwt_token = InstructorOrAdminLtiTokenFactory(resource=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) return jwt_token def _patch_video(self, video, params): diff --git a/src/backend/marsha/core/tests/test_api_xapi_statement.py b/src/backend/marsha/core/tests/test_api_xapi_statement.py index 2cafae252f..06e12a3741 100644 --- a/src/backend/marsha/core/tests/test_api_xapi_statement.py +++ b/src/backend/marsha/core/tests/test_api_xapi_statement.py @@ -29,7 +29,7 @@ def test_xapi_statement_api_with_anonymous_user(self): def test_xapi_statement_with_no_lrs_configured(self): """If no LRS configured a 200 status code should be returned.""" video = VideoFactory() - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = { "verb": { @@ -56,7 +56,7 @@ def test_xapi_statement_api_with_invalid_payload(self): playlist__consumer_site__lrs_url="http://lrs.com/data/xAPI", playlist__consumer_site__lrs_auth_token="Basic ThisIsABasicAuth", ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = {"foo": "bar"} @@ -107,7 +107,7 @@ def test_xapi_statement_with_request_error_to_lrs(self, xapi_send_mock): playlist__consumer_site__lrs_url="http://lrs.com/data/xAPI", playlist__consumer_site__lrs_auth_token="Basic ThisIsABasicAuth", ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = { "verb": { @@ -144,7 +144,7 @@ def test_xapi_statement_with_request_to_lrs_successful(self): playlist__consumer_site__lrs_url="http://lrs.com/data/xAPI", playlist__consumer_site__lrs_auth_token="Basic ThisIsABasicAuth", ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) data = { "verb": { @@ -172,7 +172,7 @@ def test_xapi_statement_with_missing_user(self): playlist__consumer_site__lrs_url="http://lrs.com/data/xAPI", playlist__consumer_site__lrs_auth_token="Basic ThisIsABasicAuth", ) - jwt_token = StudentLtiTokenFactory(resource=video.playlist) + jwt_token = StudentLtiTokenFactory(playlist=video.playlist) del jwt_token.payload["user"] data = { @@ -203,7 +203,7 @@ def test_xapi_statement_document_resource(self): ) session_id = str(uuid.uuid4()) jwt_token = StudentLtiTokenFactory( - resource=document.playlist, session_id=session_id + playlist=document.playlist, session_id=session_id ) data = { diff --git a/src/backend/marsha/core/tests/test_xapi.py b/src/backend/marsha/core/tests/test_xapi.py index b1a1021a7b..ea89c8af95 100644 --- a/src/backend/marsha/core/tests/test_xapi.py +++ b/src/backend/marsha/core/tests/test_xapi.py @@ -3,7 +3,7 @@ from django.test import TestCase, override_settings -from marsha.core.simple_jwt.factories import LTIResourceAccessTokenFactory +from marsha.core.simple_jwt.factories import LTIPlaylistAccessTokenFactory from ..defaults import ENDED, RAW, READY, RUNNING from ..factories import DocumentFactory, VideoFactory @@ -27,7 +27,7 @@ def test_xapi_statement_missing_user(self): title="test video xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", ) @@ -115,7 +115,7 @@ def test_xapi_statement_enrich_statement(self): title="test video xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", user__id="b2584aa405540758db2a6278521b6478", @@ -204,7 +204,7 @@ def test_xapi_statement_live_video(self): live_type=RAW, ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", user__id="b2584aa405540758db2a6278521b6478", @@ -294,7 +294,7 @@ def test_xapi_statement_live_video_ended(self): upload_state=READY, ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", user__id="b2584aa405540758db2a6278521b6478", @@ -381,7 +381,7 @@ def test_xapi_statement_missing_context_id(self): title="test video xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", ) del jwt_token.payload["user"] @@ -464,7 +464,7 @@ def test_xapi_statement_enrich_statement(self): title="test document xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", user__id="b2584aa405540758db2a6278521b6478", @@ -541,7 +541,7 @@ def test_xapi_statement_missing_context_id(self): title="test document xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", user__id="b2584aa405540758db2a6278521b6478", ) @@ -607,7 +607,7 @@ def test_xapi_statement_missing_user_id(self): title="test document xapi", ) - jwt_token = LTIResourceAccessTokenFactory( + jwt_token = LTIPlaylistAccessTokenFactory( session_id="326c0689-48c1-493e-8d2d-9fb0c289de7f", context_id="course-v1:ufr+mathematics+0001", ) diff --git a/src/backend/marsha/core/tests/views/test_lti_base.py b/src/backend/marsha/core/tests/views/test_lti_base.py index 13fff93c7f..cf09e70af7 100644 --- a/src/backend/marsha/core/tests/views/test_lti_base.py +++ b/src/backend/marsha/core/tests/views/test_lti_base.py @@ -18,7 +18,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR, INSTRUCTOR, STUDENT, Playlist -from marsha.core.simple_jwt.tokens import LTIUserToken, ResourceAccessToken +from marsha.core.simple_jwt.tokens import LTIUserToken, PlaylistAccessToken @override_settings(SENTRY_DSN="https://sentry.dsn") @@ -70,7 +70,7 @@ def assertContextContainsStatic(self, context): }, ) - def assertResourceJWTCommonValuesAreWellDefined(self, jwt_token, lti_role): + def assertPlaylistJWTCommonValuesAreWellDefined(self, jwt_token, lti_role): """Assert common values in the JWT token are properly defined.""" self.assertEqual(jwt_token.payload["context_id"], "other:lti:context") self.assertEqual( @@ -140,14 +140,14 @@ def assertLTIViewReturnsPortabilityContextForAdminOrInstructor( newly_create_playlist = Playlist.objects.get(lti_id="other:lti:context") - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], "") # important + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], "") # important self.assertEqual( - jwt_token.payload["playlist_id"], str(newly_create_playlist.id) + jwt_token.payload["port_to_playlist_id"], str(newly_create_playlist.id) ) # Test common JWT attributes - self.assertResourceJWTCommonValuesAreWellDefined(jwt_token, lti_role) + self.assertPlaylistJWTCommonValuesAreWellDefined(jwt_token, lti_role) # Test context when portability already exists and user is already associated PortabilityRequestFactory( @@ -186,14 +186,14 @@ def assertLTIViewReturnsPortabilityContextForAdminOrInstructor( newly_create_playlist = Playlist.objects.get(lti_id="other:lti:context") - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], "") # important + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], "") # important self.assertEqual( - jwt_token.payload["playlist_id"], str(newly_create_playlist.id) + jwt_token.payload["port_to_playlist_id"], str(newly_create_playlist.id) ) # Test common JWT attributes - self.assertResourceJWTCommonValuesAreWellDefined(jwt_token, lti_role) + self.assertPlaylistJWTCommonValuesAreWellDefined(jwt_token, lti_role) def assertLTIViewReturnsNoResourceForStudent(self, resource): """Assert the LTI view will never return a resource for a student.""" @@ -201,6 +201,7 @@ def assertLTIViewReturnsNoResourceForStudent(self, resource): initial_playlist_count = Playlist.objects.all().count() lti_data = self._get_lti_data(resource, lti_role) + # breakpoint() response = self._client_post_on_resource_lti_view(resource, lti_data) context = self._get_context_from_response(response) diff --git a/src/backend/marsha/core/tests/views/test_lti_document.py b/src/backend/marsha/core/tests/views/test_lti_document.py index 36025d3ff7..21629e22f1 100644 --- a/src/backend/marsha/core/tests/views/test_lti_document.py +++ b/src/backend/marsha/core/tests/views/test_lti_document.py @@ -24,7 +24,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR -from marsha.core.simple_jwt.tokens import ResourceAccessToken, ResourceRefreshToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken, PlaylistRefreshToken from .test_lti_base import BaseLTIViewForPortabilityTestCase @@ -70,9 +70,9 @@ def test_views_lti_document_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(document.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(document.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -135,9 +135,9 @@ def test_views_lti_document_instructor_other_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(document.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(document.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -196,9 +196,9 @@ def test_views_lti_document_student_with_video( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(document.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(document.playlist.id)) self.assertEqual( jwt_token.payload["user"], { diff --git a/src/backend/marsha/core/tests/views/test_lti_select.py b/src/backend/marsha/core/tests/views/test_lti_select.py index 6069d7cf17..db6a175ea6 100644 --- a/src/backend/marsha/core/tests/views/test_lti_select.py +++ b/src/backend/marsha/core/tests/views/test_lti_select.py @@ -13,7 +13,7 @@ from marsha.core.defaults import ENDED, IDLE, JITSI from marsha.core.factories import DocumentFactory, PlaylistFactory, VideoFactory from marsha.core.models import Playlist -from marsha.core.simple_jwt.tokens import LTISelectFormAccessToken, ResourceAccessToken +from marsha.core.simple_jwt.tokens import LTISelectFormAccessToken, PlaylistAccessToken from marsha.core.tests.testing_utils import generate_passport_and_signed_lti_parameters @@ -142,7 +142,7 @@ def test_views_lti_select(self): lti_parameters.update({"lti_message_type": "ContentItemSelection"}) self.assertEqual(initial_jwt_token.get("lti_select_form_data"), lti_parameters) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual( jwt_token.get("permissions"), {"can_access_dashboard": False, "can_update": True}, @@ -235,7 +235,7 @@ def test_views_lti_select_video(self): lti_parameters.update({"lti_message_type": "ContentItemSelection"}) self.assertEqual(initial_jwt_token.get("lti_select_form_data"), lti_parameters) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual( jwt_token.get("permissions"), {"can_access_dashboard": False, "can_update": True}, diff --git a/src/backend/marsha/core/tests/views/test_lti_video.py b/src/backend/marsha/core/tests/views/test_lti_video.py index 59b4df871c..e68adc8022 100644 --- a/src/backend/marsha/core/tests/views/test_lti_video.py +++ b/src/backend/marsha/core/tests/views/test_lti_video.py @@ -38,7 +38,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR -from marsha.core.simple_jwt.tokens import ResourceAccessToken, ResourceRefreshToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken, PlaylistRefreshToken from .test_lti_base import BaseLTIViewForPortabilityTestCase @@ -90,10 +90,10 @@ def test_views_lti_video_post_instructor(self, mock_get_consumer_site, mock_veri ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual(context.get("frontend_home_url"), "https://marsha.education") - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual( jwt_token.payload["consumer_site"], str(passport.consumer_site.id) @@ -247,9 +247,9 @@ def test_views_lti_video_instructor_live_mode_on( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -428,9 +428,9 @@ def test_views_lti_video_instructor_live_mode_and_chat_on( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -649,9 +649,9 @@ def test_views_lti_video_student_live_mode_on( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -806,9 +806,9 @@ def test_views_lti_video_post_administrator( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -922,8 +922,8 @@ def test_views_lti_video_read_other_playlist( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], {"can_access_dashboard": True, "can_update": False}, @@ -1054,9 +1054,9 @@ def test_views_lti_video_restricted_resolutions_list( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -1194,9 +1194,9 @@ def test_views_lti_video_harvested_live_state_student( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -1308,9 +1308,9 @@ def test_views_lti_video_harvested_live_state_instructor( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -1450,9 +1450,9 @@ def test_views_lti_video_post_student_with_video( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -1594,9 +1594,9 @@ def test_views_lti_video_without_user_id_parameter( ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual( jwt_token.payload["consumer_site"], str(passport.consumer_site.id) @@ -1728,9 +1728,9 @@ def test_views_lti_video_with_timed_text(self, mock_get_consumer_site, mock_veri ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual(jwt_token.payload["context_id"], data["context_id"]) self.assertEqual( jwt_token.payload["consumer_site"], str(passport.consumer_site.id) diff --git a/src/backend/marsha/core/tests/views/test_public_document.py b/src/backend/marsha/core/tests/views/test_public_document.py index fcb971d29d..9d97bf67cf 100644 --- a/src/backend/marsha/core/tests/views/test_public_document.py +++ b/src/backend/marsha/core/tests/views/test_public_document.py @@ -10,7 +10,7 @@ from marsha.core.defaults import STATE_CHOICES from marsha.core.factories import DocumentFactory, OrganizationFactory, PlaylistFactory -from marsha.core.simple_jwt.tokens import ResourceAccessToken, ResourceRefreshToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken, PlaylistRefreshToken # We don't enforce arguments documentation in tests @@ -58,8 +58,8 @@ def test_document_publicly_accessible(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], @@ -138,8 +138,8 @@ def test_public_document_without_consumer_site(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], diff --git a/src/backend/marsha/core/tests/views/test_public_video.py b/src/backend/marsha/core/tests/views/test_public_video.py index e467c4af31..29e6a337f4 100644 --- a/src/backend/marsha/core/tests/views/test_public_video.py +++ b/src/backend/marsha/core/tests/views/test_public_video.py @@ -23,7 +23,7 @@ PlaylistFactory, VideoFactory, ) -from marsha.core.simple_jwt.tokens import ResourceAccessToken, ResourceRefreshToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken, PlaylistRefreshToken # We don't enforce arguments documentation in tests @@ -73,8 +73,8 @@ def test_video_publicly_accessible(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], @@ -283,8 +283,8 @@ def test_video_live_publicly_available(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], @@ -388,8 +388,8 @@ def test_video_accessible_from_mail(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], @@ -405,7 +405,7 @@ def test_video_accessible_from_mail(self): "username": livesession.username, }, ) - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual(jwt_token.payload["locale"], "fr_FR") self.assertEqual(jwt_token.payload["context_id"], video.playlist.lti_id) self.assertEqual( @@ -438,8 +438,8 @@ def test_video_ressource_public_accessible_from_mail(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], @@ -455,7 +455,7 @@ def test_video_ressource_public_accessible_from_mail(self): }, ) self.assertEqual(jwt_token.payload["roles"], ["none"]) - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual(jwt_token.payload["locale"], "en_US") self.assertIsNone(jwt_token.payload.get("context_id")) self.assertIsNone(jwt_token.payload.get("consumer_site")) @@ -565,8 +565,8 @@ def test_video_public_without_consumer_site(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - ResourceRefreshToken(context.get("refresh_token")) # Must not raise + jwt_token = PlaylistAccessToken(context.get("jwt")) + PlaylistRefreshToken(context.get("refresh_token")) # Must not raise self.assertEqual( jwt_token.payload["permissions"], diff --git a/src/backend/marsha/core/views.py b/src/backend/marsha/core/views.py index 1da47d1c45..aeba07792e 100644 --- a/src/backend/marsha/core/views.py +++ b/src/backend/marsha/core/views.py @@ -38,7 +38,7 @@ from marsha.core.simple_jwt.tokens import ( LTISelectFormAccessToken, LTIUserToken, - ResourceRefreshToken, + PlaylistRefreshToken, ) from marsha.core.utils.lti_select_utils import get_lti_select_resources @@ -504,10 +504,10 @@ def _get_app_data(self): "redirect_to": redirect_to, "portability_request_exists": portability_request_exists, } - refresh_token = ResourceRefreshToken.for_lti_portability_request( + refresh_token = PlaylistRefreshToken.for_lti_portability_request( lti=self.lti, session_id=session_id, - playlist_id=str(destination_playlist.pk), + port_to_playlist_id=str(destination_playlist.pk), ) jwt_token = refresh_token.access_token app_data["jwt"] = str(jwt_token) @@ -535,11 +535,11 @@ def _get_app_data(self): cache.set(self.cache_key, app_data, settings.APP_DATA_CACHE_DURATION) if app_data["resource"] is not None: - refresh_token = ResourceRefreshToken.for_lti( + refresh_token = PlaylistRefreshToken.for_lti( lti=self.lti, permissions=permissions, session_id=session_id, - playlist_id=str(app_data["resource"]["playlist"]["id"]), + port_to_playlist_id=str(app_data["resource"]["playlist"]["id"]), ) jwt_token = refresh_token.access_token app_data["jwt"] = str(jwt_token) @@ -620,8 +620,8 @@ def _get_app_data(self): ) if app_data["resource"] is not None: - refresh_token = ResourceRefreshToken.for_resource_id( - resource_id=app_data["resource"]["id"], + refresh_token = PlaylistRefreshToken.for_playlist_id( + playlist_id=app_data["resource"]["playlist"]["id"], session_id=session_id, ) jwt_token = refresh_token.access_token @@ -745,7 +745,7 @@ def get_direct_access_from_livesession(self, video_pk, livesession_pk, key): ) cache.set(cache_key, app_data, settings.APP_DATA_CACHE_DURATION) - refresh_token = ResourceRefreshToken.for_live_session(livesession, session_id) + refresh_token = PlaylistRefreshToken.for_live_session(livesession, session_id) jwt_token = refresh_token.access_token app_data["jwt"] = str(jwt_token) app_data["refresh_token"] = str(refresh_token) @@ -938,11 +938,11 @@ def _get_app_data(self): if self.request.POST.get("title") != settings.LTI_CONFIG_TITLE: activity_title = self.request.POST.get("title") - refresh_token = ResourceRefreshToken.for_lti( + refresh_token = PlaylistRefreshToken.for_lti( lti=self.lti, permissions={"can_access_dashboard": False, "can_update": True}, session_id=str(uuid.uuid4()), - playlist_id=str(playlist.id), + port_to_playlist_id=str(playlist.id), ) app_data.update( diff --git a/src/backend/marsha/deposit/api.py b/src/backend/marsha/deposit/api.py index 461982d494..809c5c4640 100644 --- a/src/backend/marsha/deposit/api.py +++ b/src/backend/marsha/deposit/api.py @@ -77,7 +77,7 @@ class FileDepositoryViewSet( filterset_class = FileDepositoryFilter permission_classes = [ - core_permissions.IsTokenResourceRouteObject + core_permissions.IsTokenPlaylistRouteObject & (core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin) ] @@ -91,7 +91,7 @@ def get_permissions(self): if self.action in ["create"]: permission_classes = [ ( - core_permissions.HasPlaylistToken + core_permissions.IsPlaylistToken & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -107,7 +107,7 @@ def get_permissions(self): ] elif self.action in ["retrieve"]: permission_classes = [ - core_permissions.IsPlaylistToken + core_permissions.IsPlaylistTokenMatchingRouteObject & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -118,7 +118,7 @@ def get_permissions(self): elif self.action in ["update", "partial_update", "destroy"]: permission_classes = [ ( - core_permissions.IsPlaylistToken + core_permissions.IsPlaylistTokenMatchingRouteObject & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -175,7 +175,7 @@ def create(self, request, *args, **kwargs): methods=["get"], detail=False, url_path="lti-select", - permission_classes=[core_permissions.HasPlaylistToken], + permission_classes=[core_permissions.IsPlaylistToken], ) def lti_select(self, request): """Get selectable content for LTI. @@ -197,7 +197,7 @@ def lti_select(self, request): new_url = self.request.build_absolute_uri(LTI_ROUTE) file_depositories = serializers.FileDepositorySelectLTISerializer( - FileDepository.objects.filter(playlist__id=request.resource.playlist_id), + FileDepository.objects.filter(playlist__id=request.resource.id), many=True, context={"request": self.request}, ).data diff --git a/src/backend/marsha/deposit/tests/api/depositedfiles/test_create.py b/src/backend/marsha/deposit/tests/api/depositedfiles/test_create.py index ada6fad42b..a177254647 100644 --- a/src/backend/marsha/deposit/tests/api/depositedfiles/test_create.py +++ b/src/backend/marsha/deposit/tests/api/depositedfiles/test_create.py @@ -42,7 +42,7 @@ def test_api_deposited_file_create_student_with_user_fullname(self): """ file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=file_depository.playlist) response = self.client.post( f"/api/filedepositories/{file_depository.id}/depositedfiles/", @@ -89,7 +89,7 @@ def test_api_deposited_file_create_student_with_username(self): file_depository = FileDepositoryFactory() jwt_token = StudentLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, user__user_fullname=None, user__username="student", ) @@ -123,7 +123,7 @@ def test_api_deposited_file_create_student_without_username(self): file_depository = FileDepositoryFactory() jwt_token = StudentLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, user__user_fullname=None, user__username=None, ) diff --git a/src/backend/marsha/deposit/tests/api/depositedfiles/test_delete.py b/src/backend/marsha/deposit/tests/api/depositedfiles/test_delete.py index 5a2412a3e6..d30f8dc734 100644 --- a/src/backend/marsha/deposit/tests/api/depositedfiles/test_delete.py +++ b/src/backend/marsha/deposit/tests/api/depositedfiles/test_delete.py @@ -30,7 +30,7 @@ def test_api_deposited_file_delete_student(self): """A student user should not be able to delete a deposited_file.""" deposited_file = DepositedFileFactory() jwt_token = StudentLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) self.assertEqual(DepositedFile.objects.count(), 1) @@ -47,7 +47,7 @@ def test_api_deposited_file_delete_instructor(self): """An instructor should be able to delete a deposited_file.""" deposited_file = DepositedFileFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) self.assertEqual(DepositedFile.objects.count(), 1) diff --git a/src/backend/marsha/deposit/tests/api/depositedfiles/test_initiate_upload.py b/src/backend/marsha/deposit/tests/api/depositedfiles/test_initiate_upload.py index 3368264df1..6032d7d0cf 100644 --- a/src/backend/marsha/deposit/tests/api/depositedfiles/test_initiate_upload.py +++ b/src/backend/marsha/deposit/tests/api/depositedfiles/test_initiate_upload.py @@ -50,7 +50,7 @@ def test_api_deposited_file_initiate_upload_student(self): file_depository__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = StudentLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -109,7 +109,7 @@ def test_api_deposited_file_initiate_upload_file_without_size(self): file_depository__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = StudentLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) @@ -139,7 +139,7 @@ def test_api_deposited_file_initiate_upload_file_too_large(self): file_depository__id="ed08da34-7447-4141-96ff-5740315d7b99", ) jwt_token = StudentLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) now = datetime(2018, 8, 8, tzinfo=baseTimezone.utc) diff --git a/src/backend/marsha/deposit/tests/api/depositedfiles/test_update.py b/src/backend/marsha/deposit/tests/api/depositedfiles/test_update.py index 091bfb0abb..1abd77372a 100644 --- a/src/backend/marsha/deposit/tests/api/depositedfiles/test_update.py +++ b/src/backend/marsha/deposit/tests/api/depositedfiles/test_update.py @@ -39,7 +39,7 @@ def test_api_deposited_file_update_student(self): """A student user should not be able to update a deposited_file.""" deposited_file = DepositedFileFactory() jwt_token = StudentLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) data = {"read": True} @@ -56,7 +56,7 @@ def test_api_deposited_file_update_instructor(self): """An instructor should be able to update a deposited_file.""" deposited_file = DepositedFileFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=deposited_file.file_depository.playlist + playlist=deposited_file.file_depository.playlist ) data = {"read": True} diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_create.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_create.py index 6d1a299402..b15ab232ef 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_create.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_create.py @@ -10,12 +10,10 @@ from marsha.core.models import ADMINISTRATOR from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) from marsha.core.tests.testing_utils import reload_urlconf -from marsha.deposit.factories import FileDepositoryFactory from marsha.deposit.models import FileDepository @@ -50,37 +48,10 @@ def test_api_file_depository_create_student(self): ) self.assertEqual(response.status_code, 403) - def test_api_file_depository_create_student_with_playlist_token(self): - """A student with a playlist token should not be able to create a file_depository.""" - jwt_token = PlaylistLtiTokenFactory( - roles=["student"], - permissions__can_update=True, - ) - - response = self.client.post( - "/api/filedepositories/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - self.assertEqual(FileDepository.objects.count(), 0) - def test_api_file_depository_create_instructor(self): - """An instructor without playlist token should not be able to create a file_depository.""" - file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) - - response = self.client.post( - "/api/filedepositories/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - - def test_api_file_depository_create_instructor_with_playlist_token(self): - """ - Create file_depository with playlist token. - - Used in the context of a lti select request (deep linking). - """ + """An instructor should be able to create a file_depository.""" playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(FileDepository.objects.count(), 0) diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_delete.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_delete.py index da261bf98f..553ed977d3 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_delete.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_delete.py @@ -54,7 +54,7 @@ def test_api_file_depository_delete_user_logged_in(self): def test_api_file_depository_delete_student(self): """A student user should not be able to delete a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=file_depository.playlist) self.assertEqual(FileDepository.objects.count(), 1) response = self.client.delete( @@ -69,7 +69,7 @@ def test_api_file_depository_delete_instructor_read_only(self): """An instructor should not be able to delete a file_depository in read_only.""" file_depository = FileDepositoryFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, permissions__can_update=False, ) @@ -85,7 +85,7 @@ def test_api_file_depository_delete_instructor_read_only(self): def test_api_file_depository_delete_instructor(self): """An instructor should be able to delete a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) self.assertEqual(FileDepository.objects.count(), 1) response = self.client.delete( diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_depositedfiles.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_depositedfiles.py index ccd9ddc59b..8df9514580 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_depositedfiles.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_depositedfiles.py @@ -51,7 +51,7 @@ def test_api_file_depository_list_deposited_files_student(self): DepositedFileFactory.create_batch(3, file_depository=file_depository) owned_deposited_file = DepositedFileFactory(file_depository=file_depository) jwt_token = StudentLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, permissions__can_update=True, user__id=owned_deposited_file.author_id, user__full_username=owned_deposited_file.author_name, @@ -90,7 +90,7 @@ def test_api_file_depository_list_deposited_files_instructor(self): deposited_files = DepositedFileFactory.create_batch( 3, file_depository=file_depository ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( f"/api/filedepositories/{file_depository.id}/depositedfiles/?limit=2", @@ -140,7 +140,7 @@ def test_api_file_depository_list_deposited_files_instructor_filtered(self): deposited_files_new = DepositedFileFactory.create_batch( 2, file_depository=file_depository ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( f"/api/filedepositories/{file_depository.id}/depositedfiles/?limit=10", @@ -291,7 +291,7 @@ def test_api_file_depository_list_deposited_files_instructor_signed_urls(self): deposited_files = DepositedFileFactory.create_batch( 3, file_depository=file_depository, uploaded_on=now ) - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) now = datetime(2021, 11, 30, tzinfo=baseTimezone.utc) with mock.patch.object(timezone, "now", return_value=now), mock.patch( diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_list.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_list.py index 5c49bf5d99..fc7d51c4b0 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_list.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_list.py @@ -43,7 +43,7 @@ def test_api_file_depository_fetch_list_student(self): """A student should not be able to fetch a list of file_depository.""" file_depository = FileDepositoryFactory() jwt_token = StudentLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, permissions__can_update=True, ) @@ -55,7 +55,7 @@ def test_api_file_depository_fetch_list_student(self): def test_api_file_depository_fetch_list_instructor(self): """An instructor should not be able to fetch a file_depository list.""" file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( "/api/filedepositories/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_lti_select.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_lti_select.py index 36d92ecc96..a5b26549e2 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_lti_select.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_lti_select.py @@ -2,7 +2,7 @@ from django.test import TestCase, override_settings from marsha.core import factories as core_factories -from marsha.core.simple_jwt.factories import PlaylistLtiTokenFactory +from marsha.core.simple_jwt.factories import InstructorOrAdminLtiTokenFactory from marsha.core.tests.testing_utils import reload_urlconf from marsha.deposit.factories import FileDepositoryFactory @@ -27,7 +27,7 @@ def setUpClass(cls): def test_api_select_instructor_no_file_depository(self): """An instructor should be able to fetch a file_depository lti select.""" playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) response = self.client.get( "/api/filedepositories/lti-select/", @@ -45,7 +45,7 @@ def test_api_select_instructor_no_file_depository(self): def test_api_select_instructor(self): """An instructor should be able to fetch a file_depository lti select.""" file_depository = FileDepositoryFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( "/api/filedepositories/lti-select/", diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_retrieve.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_retrieve.py index 69f95ed228..d41e08239a 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_retrieve.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_retrieve.py @@ -38,7 +38,7 @@ def setUpClass(cls): def test_api_file_depository_fetch_student(self): """A student should be allowed to fetch a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( f"/api/filedepositories/{file_depository.id!s}/", @@ -68,7 +68,7 @@ def test_api_file_depository_fetch_from_other_file_depository(self): """ file_depository = FileDepositoryFactory() other_file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=other_file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=other_file_depository.playlist) response = self.client.get( f"/api/filedepositories/{file_depository.id!s}/", @@ -79,7 +79,7 @@ def test_api_file_depository_fetch_from_other_file_depository(self): def test_api_file_depository_fetch_instructor(self): """An instructor should be able to fetch a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.get( f"/api/filedepositories/{file_depository.id!s}/", diff --git a/src/backend/marsha/deposit/tests/api/filedepositories/test_update.py b/src/backend/marsha/deposit/tests/api/filedepositories/test_update.py index 15cf962617..9f5ee409ef 100644 --- a/src/backend/marsha/deposit/tests/api/filedepositories/test_update.py +++ b/src/backend/marsha/deposit/tests/api/filedepositories/test_update.py @@ -55,7 +55,7 @@ def test_api_file_depository_update_user_logged_in(self): def test_api_file_depository_update_student(self): """A student user should not be able to update a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=file_depository.playlist) data = {"title": "new title"} response = self.client.patch( @@ -70,7 +70,7 @@ def test_api_file_depository_update_instructor_read_only(self): """An instructor should not be able to update a file_depository in read_only.""" file_depository = FileDepositoryFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=file_depository.playlist, + playlist=file_depository.playlist, permissions__can_update=False, ) data = {"title": "new title"} @@ -86,7 +86,7 @@ def test_api_file_depository_update_instructor_read_only(self): def test_api_file_depository_update_instructor(self): """An instructor should be able to update a file_depository.""" file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) data = {"title": "new title", "description": "Hello"} response = self.client.patch( diff --git a/src/backend/marsha/deposit/tests/api/test_options.py b/src/backend/marsha/deposit/tests/api/test_options.py index e7e111dbe6..7575197091 100644 --- a/src/backend/marsha/deposit/tests/api/test_options.py +++ b/src/backend/marsha/deposit/tests/api/test_options.py @@ -29,7 +29,7 @@ def test_api_deposited_files_options_as_student(self): """A student can fetch the deposited files options endpoint""" file_depository = FileDepositoryFactory() - jwt_token = StudentLtiTokenFactory(resource=file_depository.playlist) + jwt_token = StudentLtiTokenFactory(playlist=file_depository.playlist) response = self.client.options( f"/api/filedepositories/{file_depository.id}/depositedfiles/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}", @@ -42,7 +42,7 @@ def test_api_deposited_files_options_instructor(self): """An instructor can fetch the deposited files options endpoint""" file_depository = FileDepositoryFactory() - jwt_token = InstructorOrAdminLtiTokenFactory(resource=file_depository.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=file_depository.playlist) response = self.client.options( f"/api/filedepositories/{file_depository.id}/depositedfiles/", diff --git a/src/backend/marsha/deposit/tests/test_views_lti.py b/src/backend/marsha/deposit/tests/test_views_lti.py index 2995fa2159..58927adecf 100644 --- a/src/backend/marsha/deposit/tests/test_views_lti.py +++ b/src/backend/marsha/deposit/tests/test_views_lti.py @@ -17,7 +17,7 @@ UserFactory, ) from marsha.core.lti import LTI -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.testing_utils import reload_urlconf from marsha.core.tests.views.test_lti_base import BaseLTIViewForPortabilityTestCase from marsha.core.utils.lti_select_utils import get_lti_select_resources @@ -77,7 +77,7 @@ def test_views_lti_file_depository_student( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "filedepositories") @@ -130,7 +130,7 @@ def test_views_lti_file_depository_student_legacy( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "filedepositories") @@ -218,9 +218,9 @@ def test_views_lti_file_depository_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual( - jwt_token.payload["resource_id"], str(file_depository.playlist.id) + jwt_token.payload["playlist_id"], str(file_depository.playlist.id) ) self.assertEqual( jwt_token.payload["user"], diff --git a/src/backend/marsha/development/tests/test_views_lti_development.py b/src/backend/marsha/development/tests/test_views_lti_development.py index fb7a486875..d57bd0fe59 100644 --- a/src/backend/marsha/development/tests/test_views_lti_development.py +++ b/src/backend/marsha/development/tests/test_views_lti_development.py @@ -11,7 +11,7 @@ from marsha.core.defaults import STATE_CHOICES from marsha.core.factories import VideoFactory from marsha.core.models import ConsumerSite, Video -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken # We don't enforce arguments documentation in tests @@ -66,8 +66,8 @@ def test_views_lti_development_post_bypass_lti_student(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -120,8 +120,8 @@ def test_views_lti_development_post_bypass_lti_instructor(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + jwt_token = PlaylistAccessToken(context.get("jwt")) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { @@ -212,9 +212,9 @@ def test_views_lti_development_post_bypass_lti_instructor_no_video(self): ) context = json.loads(unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) video = Video.objects.get() - self.assertEqual(jwt_token.payload["resource_id"], str(video.playlist.id)) + self.assertEqual(jwt_token.payload["playlist_id"], str(video.playlist.id)) self.assertEqual( jwt_token.payload["user"], { diff --git a/src/backend/marsha/markdown/api.py b/src/backend/marsha/markdown/api.py index 733249aac6..e847fec385 100644 --- a/src/backend/marsha/markdown/api.py +++ b/src/backend/marsha/markdown/api.py @@ -73,7 +73,7 @@ class MarkdownDocumentViewSet( permission_classes = [ ( - core_permissions.IsPlaylistToken + core_permissions.IsPlaylistTokenMatchingRouteObject & (core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin) ) | markdown_permissions.IsMarkdownDocumentPlaylistOrOrganizationAdmin @@ -88,7 +88,7 @@ def get_permissions(self): if self.action in ["create"]: permission_classes = [ ( - core_permissions.HasPlaylistToken + core_permissions.IsPlaylistToken & ( core_permissions.IsTokenInstructor | core_permissions.IsTokenAdmin @@ -163,7 +163,7 @@ def create(self, request, *args, **kwargs): methods=["get"], detail=False, url_path="lti-select", - permission_classes=[core_permissions.HasPlaylistToken], + permission_classes=[core_permissions.IsPlaylistToken], ) def lti_select(self, request): """Get selectable content for LTI. @@ -186,7 +186,7 @@ def lti_select(self, request): markdown_documents = serializers.MarkdownDocumentSelectLTISerializer( MarkdownDocument.objects.filter( - playlist__id=request.resource.playlist_id, + playlist__id=request.resource.id, ), many=True, context={"request": self.request}, diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_create.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_create.py index 40a44a0b28..b5f0ff4cde 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_create.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_create.py @@ -10,7 +10,6 @@ from marsha.core.models import ADMINISTRATOR from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - PlaylistLtiTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -38,7 +37,7 @@ def test_api_document_create_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -47,43 +46,11 @@ def test_api_document_create_student(self): ) self.assertEqual(response.status_code, 403) - def test_api_document_create_student_with_playlist_token(self): - """A student with a playlist token should not be able to create a Markdown document.""" - jwt_token = PlaylistLtiTokenFactory(roles=["student"]) - - response = self.client.post( - "/api/markdown-documents/", HTTP_AUTHORIZATION=f"Bearer {jwt_token}" - ) - self.assertEqual(response.status_code, 403) - def test_api_document_create_instructor(self): """An instructor should not be able to create a Markdown document.""" - markdown_document = MarkdownDocumentFactory() - - jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist - ) - - response = self.client.post( - "/api/markdown-documents/", - { - "lti_id": "document_one", - "playlist": str(markdown_document.playlist.id), - "title": "Some document", - }, - HTTP_AUTHORIZATION=f"Bearer {jwt_token}", - ) - self.assertEqual(response.status_code, 403) - - def test_api_document_create_instructor_with_playlist_token(self): - """ - Create document with playlist token. - - Used in the context of a lti select request (deep linking). - """ playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(MarkdownDocument.objects.count(), 0) @@ -124,15 +91,11 @@ def test_api_document_create_instructor_with_playlist_token(self): }, ) - def test_api_document_create_instructor_with_playlist_token_no_title(self): - """ - Create document with playlist token. - - Used in the context of a lti select request (deep linking) without title. - """ + def test_api_document_create_instructor_no_title(self): + """An instructor should not be able to create a Markdown document without title.""" playlist = core_factories.PlaylistFactory() - jwt_token = PlaylistLtiTokenFactory(playlist=playlist) + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) self.assertEqual(MarkdownDocument.objects.count(), 0) diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_delete.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_delete.py index 09a597ae78..3497c81e66 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_delete.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_delete.py @@ -38,7 +38,7 @@ def test_api_document_delete_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -53,7 +53,7 @@ def test_api_document_delete_instructor(self): markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.delete( diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_list.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_list.py index b2826d860c..006fafc333 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_list.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_list.py @@ -36,7 +36,7 @@ def test_api_document_fetch_list_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -50,7 +50,7 @@ def test_api_document_fetch_list_instructor(self): markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.get( diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_lti_select.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_lti_select.py index 49d96a0bfd..b8af9f04f4 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_lti_select.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_lti_select.py @@ -1,7 +1,8 @@ """Tests for the Markdown application lti-select API.""" from django.test import TestCase, override_settings -from marsha.core.simple_jwt.factories import PlaylistLtiTokenFactory +from marsha.core.factories import PlaylistFactory +from marsha.core.simple_jwt.factories import InstructorOrAdminLtiTokenFactory from marsha.markdown.factories import MarkdownDocumentFactory @@ -17,7 +18,8 @@ class MarkdownLtiSelectAPITest(TestCase): def test_api_select_instructor_no_document(self): """An instructor should be able to fetch a Markdown document lti select.""" - jwt_token = PlaylistLtiTokenFactory() + playlist = PlaylistFactory() + jwt_token = InstructorOrAdminLtiTokenFactory(playlist=playlist) response = self.client.get( "/api/markdown-documents/lti-select/", @@ -40,7 +42,9 @@ def test_api_select_instructor(self): translations__rendered_content="

Heading1

\n

Some content

", ) - jwt_token = PlaylistLtiTokenFactory(playlist=markdown_document.playlist) + jwt_token = InstructorOrAdminLtiTokenFactory( + playlist=markdown_document.playlist + ) response = self.client.get( "/api/markdown-documents/lti-select/", diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_render_latex.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_render_latex.py index 9bee8a7969..146fa7f9f5 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_render_latex.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_render_latex.py @@ -32,7 +32,7 @@ def test_api_document_render_latex_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -49,7 +49,7 @@ def test_api_document_render_latex_instructor(self): markdown_document = MarkdownDocumentFactory(is_draft=True) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.post( diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_retrieve.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_retrieve.py index 35d622f707..1cad5e2002 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_retrieve.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_retrieve.py @@ -43,7 +43,7 @@ def test_api_document_fetch_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -70,7 +70,7 @@ def test_api_document_fetch_instructor(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.get( @@ -120,7 +120,7 @@ def test_api_document_fetch_from_other_document(self): other_markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=other_markdown_document.playlist + playlist=other_markdown_document.playlist ) response = self.client.get( @@ -134,7 +134,7 @@ def test_api_document_fetch_instructor_read_only(self): markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_update.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_update.py index cb2dd9d3cc..ad0364de06 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_update.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_update.py @@ -48,7 +48,7 @@ def test_api_document_update_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) data = {"title": "new title"} @@ -66,7 +66,7 @@ def test_api_document_update_instructor_read_only(self): markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=False, ) data = {"title": "new title"} @@ -100,7 +100,7 @@ def test_api_document_update_instructor(self): markdown_document = MarkdownDocumentFactory(is_draft=True) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) data = {"is_draft": False} diff --git a/src/backend/marsha/markdown/tests/api/markdown_documents/test_update_translations.py b/src/backend/marsha/markdown/tests/api/markdown_documents/test_update_translations.py index 7689c350c7..a07bacaccb 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_documents/test_update_translations.py +++ b/src/backend/marsha/markdown/tests/api/markdown_documents/test_update_translations.py @@ -30,7 +30,7 @@ def test_api_document_translation_update_student(self): markdown_document = MarkdownDocumentFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, permissions__can_update=True, ) @@ -54,7 +54,7 @@ def test_api_document_translation_update_instructor(self): markdown_document = MarkdownDocumentFactory(is_draft=True) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) data = { diff --git a/src/backend/marsha/markdown/tests/api/markdown_images/test_create.py b/src/backend/marsha/markdown/tests/api/markdown_images/test_create.py index 0d71c1342f..62e618b170 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_images/test_create.py +++ b/src/backend/marsha/markdown/tests/api/markdown_images/test_create.py @@ -35,7 +35,7 @@ def test_api_markdown_image_create_student(self): """Student users should not be able to create a Markdown image.""" markdown_document = MarkdownDocumentFactory() - jwt_token = StudentLtiTokenFactory(resource=markdown_document.playlist) + jwt_token = StudentLtiTokenFactory(playlist=markdown_document.playlist) response = self.client.post( f"/api/markdown-documents/{markdown_document.id}/markdown-images/", @@ -49,7 +49,7 @@ def test_api_markdown_image_create_instructor(self): markdown_document = MarkdownDocumentFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.post( @@ -83,7 +83,7 @@ def test_api_markdown_image_create_already_existing_instructor(self): MarkdownImageFactory(markdown_document=markdown_document) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.post( @@ -113,7 +113,7 @@ def test_api_markdown_image_instructor_create_in_read_only(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/markdown/tests/api/markdown_images/test_delete.py b/src/backend/marsha/markdown/tests/api/markdown_images/test_delete.py index 3d77546273..d295faa165 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_images/test_delete.py +++ b/src/backend/marsha/markdown/tests/api/markdown_images/test_delete.py @@ -36,7 +36,7 @@ def test_api_markdown_image_delete_student(self): markdown_image = MarkdownImageFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_image.markdown_document.playlist + playlist=markdown_image.markdown_document.playlist ) response = self.client.delete( @@ -51,7 +51,7 @@ def test_api_markdown_image_delete_instructor(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, ) self.assertEqual(MarkdownImage.objects.count(), 1) @@ -86,7 +86,7 @@ def test_api_markdown_image_delete_instructor_in_read_only(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, permissions__can_update=False, ) @@ -108,7 +108,7 @@ def test_api_markdown_image_delete_instructor_other_markdown_document(self): markdown_image = MarkdownImageFactory(markdown_document=markdown_document_other) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document_token.playlist + playlist=markdown_document_token.playlist ) response = self.client.delete( diff --git a/src/backend/marsha/markdown/tests/api/markdown_images/test_initiate_upload.py b/src/backend/marsha/markdown/tests/api/markdown_images/test_initiate_upload.py index 1bbdc4a255..8a32f9afdd 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_images/test_initiate_upload.py +++ b/src/backend/marsha/markdown/tests/api/markdown_images/test_initiate_upload.py @@ -39,7 +39,7 @@ def test_api_markdown_image_initiate_upload_student(self): """Student users should not be allowed to initiate an upload.""" markdown_image = MarkdownImageFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_image.markdown_document.playlist + playlist=markdown_image.markdown_document.playlist ) response = self.client.post( @@ -60,7 +60,7 @@ def test_api_markdown_image_initiate_upload_instructor(self): upload_state="ready", ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) # Get the upload policy for this Markdown image @@ -118,7 +118,7 @@ def test_api_markdown_image_initiate_upload_instructor_read_only(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, permissions__can_update=False, ) diff --git a/src/backend/marsha/markdown/tests/api/markdown_images/test_retrieve.py b/src/backend/marsha/markdown/tests/api/markdown_images/test_retrieve.py index 21dde7b8d8..cce0cf142e 100644 --- a/src/backend/marsha/markdown/tests/api/markdown_images/test_retrieve.py +++ b/src/backend/marsha/markdown/tests/api/markdown_images/test_retrieve.py @@ -41,7 +41,7 @@ def test_api_markdown_image_read_detail_student(self): markdown_image = MarkdownImageFactory() jwt_token = StudentLtiTokenFactory( - resource=markdown_image.markdown_document.playlist + playlist=markdown_image.markdown_document.playlist ) response = self.client.get( @@ -57,7 +57,7 @@ def test_api_markdown_image_instructor_read_detail_in_read_only(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, permissions__can_update=False, ) @@ -82,7 +82,7 @@ def test_api_markdown_image_read_detail_token_user(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.get( @@ -112,7 +112,7 @@ def test_api_markdown_image_administrator_read_detail_in_read_only(self): markdown_image = MarkdownImageFactory() jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_image.markdown_document.playlist, + playlist=markdown_image.markdown_document.playlist, permissions__can_update=False, ) @@ -137,7 +137,7 @@ def test_api_markdown_image_read_detail_admin_user(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist, + playlist=markdown_document.playlist, roles=["administrator"], ) @@ -177,7 +177,7 @@ def test_api_markdown_image_read_ready_markdown_image(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=markdown_document.playlist + playlist=markdown_document.playlist ) response = self.client.get( diff --git a/src/backend/marsha/markdown/tests/test_views_lti.py b/src/backend/marsha/markdown/tests/test_views_lti.py index 9fd6fa709b..b446d131b5 100644 --- a/src/backend/marsha/markdown/tests/test_views_lti.py +++ b/src/backend/marsha/markdown/tests/test_views_lti.py @@ -18,7 +18,7 @@ ) from marsha.core.lti import LTI from marsha.core.models import ADMINISTRATOR -from marsha.core.simple_jwt.tokens import ResourceAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken from marsha.core.tests.views.test_lti_base import BaseLTIViewForPortabilityTestCase from marsha.markdown.factories import MarkdownDocumentFactory @@ -66,7 +66,7 @@ def test_views_lti_markdown_document_student( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual(context.get("state"), "success") self.assertIsNotNone(context.get("resource")) self.assertEqual(context.get("modelName"), "markdown-documents") @@ -156,9 +156,9 @@ def test_views_lti_markdown_document_instructor_same_playlist( ) context = json.loads(html.unescape(match.group(1))) - jwt_token = ResourceAccessToken(context.get("jwt")) + jwt_token = PlaylistAccessToken(context.get("jwt")) self.assertEqual( - jwt_token.payload["resource_id"], str(markdown_document.playlist.id) + jwt_token.payload["playlist_id"], str(markdown_document.playlist.id) ) self.assertEqual( jwt_token.payload["user"], diff --git a/src/backend/marsha/settings.py b/src/backend/marsha/settings.py index 6dd5112fcf..843f76312c 100644 --- a/src/backend/marsha/settings.py +++ b/src/backend/marsha/settings.py @@ -208,7 +208,7 @@ class Base(Configuration): REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ( - "marsha.core.simple_jwt.authentication.JWTStatelessUserOrResourceAuthentication", + "marsha.core.simple_jwt.authentication.JWTStatelessUserOrPlaylistAuthentication", ), "EXCEPTION_HANDLER": "marsha.core.views.exception_handler", "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination", @@ -760,11 +760,11 @@ def SIMPLE_JWT(self): "AUTH_TOKEN_CLASSES": ( "rest_framework_simplejwt.tokens.AccessToken", "marsha.core.simple_jwt.tokens.ChallengeToken", - # For now ResourceAccessToken & UserAccessToken are also AccessToken + # For now PlaylistAccessToken & UserAccessToken are also AccessToken # but this will allow migration when types will differ. # Note: AccessToken must remain enabled during the migration and removed # only after (version N changes token types, N+1 removes AccessToken). - "marsha.core.simple_jwt.tokens.ResourceAccessToken", + "marsha.core.simple_jwt.tokens.PlaylistAccessToken", "marsha.core.simple_jwt.tokens.UserAccessToken", ), # Settings for authentication API diff --git a/src/backend/marsha/websocket/consumers/video.py b/src/backend/marsha/websocket/consumers/video.py index 97379f9c79..75076239e6 100644 --- a/src/backend/marsha/websocket/consumers/video.py +++ b/src/backend/marsha/websocket/consumers/video.py @@ -16,7 +16,7 @@ ) from marsha.core.permissions import IsTokenAdmin, IsTokenInstructor from marsha.core.services import live_session as LiveSessionServices -from marsha.core.simple_jwt.tokens import ResourceAccessToken, UserAccessToken +from marsha.core.simple_jwt.tokens import PlaylistAccessToken, UserAccessToken from marsha.websocket import defaults @@ -43,7 +43,7 @@ async def _check_permissions(self): # Check permissions, MUST be the same as in the `retrieve` method # of the Video API view set. - if isinstance(token, ResourceAccessToken): + if isinstance(token, PlaylistAccessToken): # With LTI: anyone with a valid token for the video can access if not await self._has_access_to_video(token): raise ConnectionRefusedError() @@ -62,7 +62,7 @@ async def _check_permissions(self): def _has_access_to_video(self, token): """Return if the user has access to the video.""" return Video.objects.filter( - pk=self.__get_video_id(), playlist_id=token.payload.get("resource_id") + pk=self.__get_video_id(), playlist_id=token.payload.get("playlist_id") ).exists() async def connect(self): @@ -155,7 +155,7 @@ async def _is_admin(self): if not token: return False - if isinstance(token, ResourceAccessToken): + if isinstance(token, PlaylistAccessToken): return IsTokenInstructor().check_role(token) or IsTokenAdmin().check_role( token ) diff --git a/src/backend/marsha/websocket/tests/test_consumers_video.py b/src/backend/marsha/websocket/tests/test_consumers_video.py index d51193139d..68963760d0 100644 --- a/src/backend/marsha/websocket/tests/test_consumers_video.py +++ b/src/backend/marsha/websocket/tests/test_consumers_video.py @@ -29,8 +29,8 @@ ) from marsha.core.simple_jwt.factories import ( InstructorOrAdminLtiTokenFactory, - LiveSessionResourceAccessTokenFactory, - ResourceAccessTokenFactory, + LiveSessionPlaylistAccessTokenFactory, + PlaylistAccessTokenFactory, StudentLtiTokenFactory, UserAccessTokenFactory, ) @@ -270,7 +270,7 @@ async def test_connect_matching_video_student(self): self.assertIsNone(live_session.channel_name) - jwt_token = LiveSessionResourceAccessTokenFactory(live_session=live_session) + jwt_token = LiveSessionPlaylistAccessTokenFactory(live_session=live_session) communicator = WebsocketCommunicator( base_application, @@ -300,7 +300,7 @@ async def test_connect_matching_video_anonymous(self): self.assertIsNone(live_session.channel_name) - jwt_token = ResourceAccessTokenFactory(resource=video.playlist) + jwt_token = PlaylistAccessTokenFactory(playlist=video.playlist) communicator = WebsocketCommunicator( base_application, @@ -331,7 +331,7 @@ async def test_connect_matching_video_admin(self): self.assertIsNone(live_session.channel_name) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.consumer_site.id), context_id=str(video.playlist.lti_id), user__id=live_session.lti_user_id, @@ -361,7 +361,7 @@ async def test_connect_no_matching_video(self): other_video = await self._get_video() jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.consumer_site.id), context_id=str(video.playlist.lti_id), ) @@ -432,7 +432,7 @@ async def test_video_update_channel_layer(self): ) jwt_token = StudentLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.consumer_site.id), ) @@ -551,7 +551,7 @@ async def test_video_update_instructor_channel_layer(self): ) jwt_token = InstructorOrAdminLtiTokenFactory( - resource=video.playlist, + playlist=video.playlist, consumer_site=str(video.consumer_site.id), ) @@ -684,7 +684,7 @@ async def test_thumbnail_update_channel_layer(self): thumbnail = await self._get_thumbnail() jwt_token = StudentLtiTokenFactory( - resource=thumbnail.video.playlist, + playlist=thumbnail.video.playlist, consumer_site=str(thumbnail.video.consumer_site.id), ) @@ -728,7 +728,7 @@ async def test_timed_text_track_update_channel_layer(self): timed_text_track = await self._get_timed_text_track() jwt_token = StudentLtiTokenFactory( - resource=timed_text_track.video.playlist, + playlist=timed_text_track.video.playlist, consumer_site=str(timed_text_track.video.consumer_site.id), ) diff --git a/src/backend/marsha/websocket/tests/test_middleware_jwt.py b/src/backend/marsha/websocket/tests/test_middleware_jwt.py index c635c9efc9..e8293738b1 100644 --- a/src/backend/marsha/websocket/tests/test_middleware_jwt.py +++ b/src/backend/marsha/websocket/tests/test_middleware_jwt.py @@ -7,7 +7,7 @@ from channels.generic.websocket import AsyncWebsocketConsumer from channels.testing import WebsocketCommunicator -from marsha.core.simple_jwt.factories import ResourceAccessTokenFactory +from marsha.core.simple_jwt.factories import PlaylistAccessTokenFactory from marsha.websocket.middlewares import JWTMiddleware @@ -28,7 +28,7 @@ async def test_missing_token(self): async def test_invalid_token(self): """With an invalid token the connection is refused.""" - token = ResourceAccessTokenFactory() + token = PlaylistAccessTokenFactory() token.set_exp( from_time=timezone.now() - timedelta(minutes=30), lifetime=timedelta(minutes=1), @@ -48,7 +48,7 @@ async def test_invalid_token(self): async def test_valid_token(self): """With a valid token the connection is accepted.""" - token = ResourceAccessTokenFactory() + token = PlaylistAccessTokenFactory() token.set_exp(lifetime=timedelta(minutes=20)) application = JWTMiddleware(AsyncWebsocketConsumer()) diff --git a/src/frontend/apps/lti_site/components/App/AppContentLoader/index.spec.tsx b/src/frontend/apps/lti_site/components/App/AppContentLoader/index.spec.tsx index 8bb821ae62..3e2aff4c74 100644 --- a/src/frontend/apps/lti_site/components/App/AppContentLoader/index.spec.tsx +++ b/src/frontend/apps/lti_site/components/App/AppContentLoader/index.spec.tsx @@ -41,7 +41,7 @@ describe('', () => { it('initialize current user before loading content', async () => { useJwt.setState({ - jwt: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzZXNzaW9uX2lkIjoic29tZV9zZXNzaW9uX2lkIiwidXNlciI6eyJhbm9ueW1vdXNfaWQiOiJhbm9ueW1vdXMgaWQiLCJlbWFpbCI6InNvbWUgZW1haWwiLCJpZCI6ImlkIiwidXNlcm5hbWUiOiJ1c2VyIG5hbWUiLCJ1c2VyX2Z1bGxuYW1lIjoidXNlciBmdWxsIG5hbWUifSwibG9jYWxlIjoicGwiLCJtYWludGVuYW5jZSI6ZmFsc2UsInBlcm1pc3Npb25zIjp7ImNhbl9hY2Nlc3NfZGFzaGJvYXJkIjpmYWxzZSwiY2FuX3VwZGF0ZSI6ZmFsc2V9LCJyZXNvdXJjZV9pZCI6InJlc291cmNlIGlkIiwicm9sZXMiOltdfQ.gv0kmitQfOv93TQuFTHsiqQJFWeTkbmb1h8J8uMVX70', + jwt: 'ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzZXNzaW9uX2lkIjogInNvbWVfc2Vzc2lvbl9pZCIsCiAgInVzZXIiOiB7CiAgICAiYW5vbnltb3VzX2lkIjogImFub255bW91cyBpZCIsCiAgICAiZW1haWwiOiAic29tZSBlbWFpbCIsCiAgICAiaWQiOiAiaWQiLAogICAgInVzZXJuYW1lIjogInVzZXIgbmFtZSIsCiAgICAidXNlcl9mdWxsbmFtZSI6ICJ1c2VyIGZ1bGwgbmFtZSIKICB9LAogICJsb2NhbGUiOiAicGwiLAogICJtYWludGVuYW5jZSI6IGZhbHNlLAogICJwZXJtaXNzaW9ucyI6IHsKICAgICJjYW5fYWNjZXNzX2Rhc2hib2FyZCI6IGZhbHNlLAogICAgImNhbl91cGRhdGUiOiBmYWxzZQogIH0sCiAgInBsYXlsaXN0X2lkIjogInBsYXlsaXN0IGlkIiwKICAicm9sZXMiOiBbXQp9.gv0kmitQfOv93TQuFTHsiqQJFWeTkbmb1h8J8uMVX70', }); const playlist = playlistMockFactory({ id: '488db2d0' }); diff --git a/src/frontend/apps/lti_site/components/App/AppContentLoader/index.tsx b/src/frontend/apps/lti_site/components/App/AppContentLoader/index.tsx index 823c12917f..43852d5140 100644 --- a/src/frontend/apps/lti_site/components/App/AppContentLoader/index.tsx +++ b/src/frontend/apps/lti_site/components/App/AppContentLoader/index.tsx @@ -115,6 +115,7 @@ const AppContent = () => { }; const AppContentLoader = () => { + const appData = useAppConfig(); const [isLoaded, setIsLoaded] = useState(false); const queryClient = new QueryClient(); @@ -141,10 +142,14 @@ const AppContentLoader = () => { }; if (decodedJwt) { - return { ...decodedJwt }; + return { + ...decodedJwt, + resource_id: appData.resource?.id || '', + playlist_id: (decodedJwt.port_to_playlist_id as string) || '', + }; } return defaultResourceContext; - }, [decodedJwt]); + }, [appData.resource?.id, decodedJwt]); useEffect(() => { const loadIntl = async () => { diff --git a/src/frontend/apps/lti_site/components/ClaimLink/index.spec.tsx b/src/frontend/apps/lti_site/components/ClaimLink/index.spec.tsx index b69b3e8368..0eb2c59657 100644 --- a/src/frontend/apps/lti_site/components/ClaimLink/index.spec.tsx +++ b/src/frontend/apps/lti_site/components/ClaimLink/index.spec.tsx @@ -66,8 +66,8 @@ describe('', () => { ', () => { 'Please login to manage this resource on http://localhost:8000/', ); expect(link.getAttribute('href')).toEqual( - 'http://localhost:8000//claim-resource?lti_consumer_site_id=32a1c2d0&resource_id=e8c0b8d0&modelName=videos&playlist_id=488db2d0<i_user_id=6b45a4d6', + `http://localhost:8000//claim-resource?lti_consumer_site_id=32a1c2d0&resource_id=${video.id}&modelName=videos&playlist_id=488db2d0<i_user_id=6b45a4d6`, ); expect(link.getAttribute('target')).toEqual('_blank'); expect(link.getAttribute('rel')).toEqual('noopener noreferrer'); @@ -135,8 +135,8 @@ describe('', () => { ', () => { { let claimUrl = `${appConfig.frontend_home_url}/claim-resource`; if (showClaimLink) { claimUrl += `?lti_consumer_site_id=${decodedJwt.consumer_site}`; - claimUrl += `&resource_id=${decodedJwt.resource_id}`; + claimUrl += `&resource_id=${resource.id}`; claimUrl += `&modelName=${appConfig.modelName}`; claimUrl += `&playlist_id=${resource.playlist.id}`; claimUrl += `<i_user_id=${decodedJwt.user?.id}`; diff --git a/src/frontend/apps/standalone_site/src/features/Authentication/hooks/useAuthenticator.spec.tsx b/src/frontend/apps/standalone_site/src/features/Authentication/hooks/useAuthenticator.spec.tsx index c4b91b17b2..4ea501c78c 100644 --- a/src/frontend/apps/standalone_site/src/features/Authentication/hooks/useAuthenticator.spec.tsx +++ b/src/frontend/apps/standalone_site/src/features/Authentication/hooks/useAuthenticator.spec.tsx @@ -177,7 +177,7 @@ describe('', () => { featureContentLoader([]); const classroom = classroomMockFactory(); const legacyInvite = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVzb3VyY2VfYWNjZXNzIiwiZXhwIjoxNjg5MjA2NDAwLCJpYXQiOjE2ODY1ODYwMzgsImp0aSI6ImNsYXNzcm9vbS1pbnZpdGUtMGJjZWIxZDItM2IxOS00NGI3LWE2NDctNGMxNTU2ZjU5MmZlLTIwMjMtMDYtMTIiLCJzZXNzaW9uX2lkIjoiMGJjZWIxZDItM2IxOS00NGI3LWE2NDctNGMxNTU2ZjU5MmZlLWludml0ZSIsInJlc291cmNlX2lkIjoiMGJjZWIxZDItM2IxOS00NGI3LWE2NDctNGMxNTU2ZjU5MmZlIiwicm9sZXMiOlsibm9uZSJdLCJsb2NhbGUiOiJlbl9VUyIsInBlcm1pc3Npb25zIjp7ImNhbl9hY2Nlc3NfZGFzaGJvYXJkIjpmYWxzZSwiY2FuX3VwZGF0ZSI6ZmFsc2V9LCJtYWludGVuYW5jZSI6ZmFsc2V9.68xSZYUAzrLD49pLkoOQy-ud7uaJVHgZ69zgkoW7umA'; + 'ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJ0b2tlbl90eXBlIjogInBsYXlsaXN0X2FjY2VzcyIsCiAgImV4cCI6IDE2ODkyMDY0MDAsCiAgImlhdCI6IDE2ODY1ODYwMzgsCiAgImp0aSI6ICJjbGFzc3Jvb20taW52aXRlLTBiY2ViMWQyLTNiMTktNDRiNy1hNjQ3LTRjMTU1NmY1OTJmZS0yMDIzLTA2LTEyIiwKICAic2Vzc2lvbl9pZCI6ICIwYmNlYjFkMi0zYjE5LTQ0YjctYTY0Ny00YzE1NTZmNTkyZmUtaW52aXRlIiwKICAicGxheWxpc3RfaWQiOiAiMGJjZWIxZDItM2IxOS00NGI3LWE2NDctNGMxNTU2ZjU5MmZlIiwKICAicm9sZXMiOiBbCiAgICAibm9uZSIKICBdLAogICJsb2NhbGUiOiAiZW5fVVMiLAogICJwZXJtaXNzaW9ucyI6IHsKICAgICJjYW5fYWNjZXNzX2Rhc2hib2FyZCI6IGZhbHNlLAogICAgImNhbl91cGRhdGUiOiBmYWxzZQogIH0sCiAgIm1haW50ZW5hbmNlIjogZmFsc2UKfQ.68xSZYUAzrLD49pLkoOQy-ud7uaJVHgZ69zgkoW7umA'; fetchMock.get('/api/users/whoami/', whoAmIResponse200); const { result } = renderHook(() => useAuthenticator(), { diff --git a/src/frontend/packages/lib_components/src/types/jwt.ts b/src/frontend/packages/lib_components/src/types/jwt.ts index 54a9ca8f24..76658b10bc 100644 --- a/src/frontend/packages/lib_components/src/types/jwt.ts +++ b/src/frontend/packages/lib_components/src/types/jwt.ts @@ -12,9 +12,10 @@ export interface DecodedJwtUser { export type DecodedJwt = DecodedJwtLTI | DecodedJwtWeb; -export interface DecodedJwtLTI extends ResourceContext { +export interface DecodedJwtLTI extends Omit { locale: string; maintenance: boolean; + port_to_playlist_id?: string; session_id: string; user?: DecodedJwtUser; } diff --git a/src/frontend/packages/lib_components/src/utils/checkToken.spec.ts b/src/frontend/packages/lib_components/src/utils/checkToken.spec.ts index 1bdf3ddbfa..ed1b758095 100644 --- a/src/frontend/packages/lib_components/src/utils/checkToken.spec.ts +++ b/src/frontend/packages/lib_components/src/utils/checkToken.spec.ts @@ -14,7 +14,7 @@ describe('checkToken', () => { can_access_dashboard: false, can_update: false, }, - resource_id: '26debfee-8c3b-4c23-b08f-67f223de9832', + playlist_id: '26debfee-8c3b-4c23-b08f-67f223de9832', roles: ['student'], session_id: '6bbb8d1d-442d-4575-a0ad-d1e34f37cae3', user: { @@ -36,7 +36,7 @@ describe('checkToken', () => { can_access_dashboard: false, can_update: false, }, - resource_id: '26debfee-8c3b-4c23-b08f-67f223de9832', + playlist_id: '26debfee-8c3b-4c23-b08f-67f223de9832', roles: ['student'], session_id: '6bbb8d1d-442d-4575-a0ad-d1e34f37cae3', user: { @@ -59,7 +59,7 @@ describe('checkToken', () => { can_access_dashboard: false, can_update: false, }, - resource_id: '26debfee-8c3b-4c23-b08f-67f223de9832', + playlist_id: '26debfee-8c3b-4c23-b08f-67f223de9832', roles: ['student'], session_id: '6bbb8d1d-442d-4575-a0ad-d1e34f37cae3', user: { @@ -83,7 +83,7 @@ describe('checkToken', () => { can_access_dashboard: false, can_update: false, }, - resource_id: '26debfee-8c3b-4c23-b08f-67f223de9832', + playlist_id: '26debfee-8c3b-4c23-b08f-67f223de9832', roles: ['student'], session_id: '6bbb8d1d-442d-4575-a0ad-d1e34f37cae3', }; diff --git a/src/frontend/packages/lib_components/src/utils/decodeJwt.spec.ts b/src/frontend/packages/lib_components/src/utils/decodeJwt.spec.ts index 2398ef1621..c60ef16af1 100644 --- a/src/frontend/packages/lib_components/src/utils/decodeJwt.spec.ts +++ b/src/frontend/packages/lib_components/src/utils/decodeJwt.spec.ts @@ -28,9 +28,9 @@ describe('decodeJwt', () => { // "sub": "1234567890", // "name": "John Doe", // "iat": 1516239022 - // "resource_id": "" + // "playlist_id": "" const jwt = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZXNvdXJjZV9pZCI6IiJ9.2AAf0eZ75jFyAdREUMXr3CyOt9QPoqSuIZ5lNj3c7CE'; + 'ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJwbGF5bGlzdF9pZCI6ICIiCn0.2AAf0eZ75jFyAdREUMXr3CyOt9QPoqSuIZ5lNj3c7CE'; expect(() => { decodeJwt(jwt); @@ -41,13 +41,13 @@ describe('decodeJwt', () => { // "sub": "1234567890", // "name": "John Doe", // "iat": 1516239022, - // "resource_id": "2c85dc9e-4ee0-11ed-b9c1-635afde8841a" + // "playlist_id": "2c85dc9e-4ee0-11ed-b9c1-635afde8841a" const jwt = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZXNvdXJjZV9pZCI6IjJjODVkYzllLTRlZTAtMTFlZC1iOWMxLTYzNWFmZGU4ODQxYSJ9.fQuKBTccQyt9fJGctJsLK5KL5lRisAGDZGFrBRdVPg8'; + 'ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJwbGF5bGlzdF9pZCI6ICIyYzg1ZGM5ZS00ZWUwLTExZWQtYjljMS02MzVhZmRlODg0MWEiCn0.fQuKBTccQyt9fJGctJsLK5KL5lRisAGDZGFrBRdVPg8'; const decodedJwt = decodeJwt(jwt); expect(isDecodedJwtLTI(decodedJwt)).toBeTruthy(); - expect((decodedJwt as DecodedJwtLTI).resource_id).toEqual( + expect((decodedJwt as DecodedJwtLTI).playlist_id).toEqual( '2c85dc9e-4ee0-11ed-b9c1-635afde8841a', ); }); @@ -56,16 +56,16 @@ describe('decodeJwt', () => { // "sub": "1234567890", // "name": "John Doe", // "iat": 1516239022, - // "resource_id": "", - // "playlist_id": "8cb4b9fa-4ee0-11ed-a972-87a03ecac56f", + // "playlist_id": "", + // "port_to_playlist_id": "8cb4b9fa-4ee0-11ed-a972-87a03ecac56f", // "user": {"id": "8d6d0ec4-4ee0-11ed-8d9b-97f53b688cde"} const jwt = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJyZXNvdXJjZV9pZCI6IiIsInBsYXlsaXN0X2lkIjoiOGNiNGI5ZmEtNGVlMC0xMWVkLWE5NzItODdhMDNlY2FjNTZmIiwidXNlciI6eyJpZCI6IjhkNmQwZWM0LTRlZTAtMTFlZC04ZDliLTk3ZjUzYjY4OGNkZSJ9fQ._ha6x03gxBMYXPpofIAVDB3HBJXg0JRnmPUr2YPdG-A'; + 'ewogICJhbGciOiAiSFMyNTYiLAogICJ0eXAiOiAiSldUIgp9.ewogICJzdWIiOiAiMTIzNDU2Nzg5MCIsCiAgIm5hbWUiOiAiSm9obiBEb2UiLAogICJpYXQiOiAxNTE2MjM5MDIyLAogICJwbGF5bGlzdF9pZCI6ICIiLAogICJwb3J0X3RvX3BsYXlsaXN0X2lkIjogIjhjYjRiOWZhLTRlZTAtMTFlZC1hOTcyLTg3YTAzZWNhYzU2ZiIsCiAgInVzZXIiOiB7CiAgICAiaWQiOiAiOGQ2ZDBlYzQtNGVlMC0xMWVkLThkOWItOTdmNTNiNjg4Y2RlIgogIH0KfQ._ha6x03gxBMYXPpofIAVDB3HBJXg0JRnmPUr2YPdG-A'; const decodedJwt = decodeJwt(jwt); expect(isDecodedJwtLTI(decodedJwt)).toBeTruthy(); - expect((decodedJwt as DecodedJwtLTI).resource_id).toEqual(''); - expect((decodedJwt as DecodedJwtLTI).playlist_id).toEqual( + expect((decodedJwt as DecodedJwtLTI).playlist_id).toEqual(''); + expect((decodedJwt as DecodedJwtLTI).port_to_playlist_id).toEqual( '8cb4b9fa-4ee0-11ed-a972-87a03ecac56f', ); expect((decodedJwt as DecodedJwtLTI).user!.id).toEqual( diff --git a/src/frontend/packages/lib_components/src/utils/decodeJwt.ts b/src/frontend/packages/lib_components/src/utils/decodeJwt.ts index badd520e60..b17dccd886 100644 --- a/src/frontend/packages/lib_components/src/utils/decodeJwt.ts +++ b/src/frontend/packages/lib_components/src/utils/decodeJwt.ts @@ -8,14 +8,14 @@ import { export const isDecodedJwtLTI = (jwt: unknown): jwt is DecodedJwtLTI => { if (jwt && typeof jwt === 'object') { - const resourceId = (jwt as DecodedJwtLTI).resource_id; const playlistId = (jwt as DecodedJwtLTI).playlist_id; + const portToPlaylistId = (jwt as DecodedJwtLTI).port_to_playlist_id; const userId = (jwt as DecodedJwtLTI).user?.id; return ( // A resource is defined // Or we are in a portability request context and a playlist and user ID are mandatory - (!!resourceId && typeof resourceId === 'string') || - (!resourceId && !!playlistId && !!userId) + (!!playlistId && typeof playlistId === 'string') || + (!playlistId && !!portToPlaylistId && !!userId) ); } diff --git a/src/frontend/packages/lib_components/src/utils/tests/factories.ts b/src/frontend/packages/lib_components/src/utils/tests/factories.ts index 4077d78441..3a77cfca4a 100644 --- a/src/frontend/packages/lib_components/src/utils/tests/factories.ts +++ b/src/frontend/packages/lib_components/src/utils/tests/factories.ts @@ -296,7 +296,7 @@ export const ltiPublicTokenMockFactory = ( can_update: false, ...permission, }, - resource_id: faker.datatype.uuid(), + playlist_id: faker.datatype.uuid(), roles: ['none'], session_id: faker.datatype.uuid(), ...token, diff --git a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/RegistrationForm/index.spec.tsx b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/RegistrationForm/index.spec.tsx index db06d33895..aba881aec1 100644 --- a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/RegistrationForm/index.spec.tsx +++ b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/RegistrationForm/index.spec.tsx @@ -51,7 +51,7 @@ describe('', () => { can_access_dashboard: false, can_update: false, }, - resource_id: 'resource id', + playlist_id: 'playlist id', roles: ['student'], session_id: 'session id', user: { @@ -121,7 +121,7 @@ describe('', () => { can_access_dashboard: false, can_update: false, }, - resource_id: 'resource id', + playlist_id: 'playlist_id', roles: ['student'], session_id: 'session id', user: { diff --git a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/index.spec.tsx b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/index.spec.tsx index b541d4146c..58e9aa52e0 100644 --- a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/index.spec.tsx +++ b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/StudentLiveRegistration/index.spec.tsx @@ -62,7 +62,7 @@ describe('', () => { can_access_dashboard: false, can_update: false, }, - resource_id: 'ressource_id', + playlist_id: 'playlist_id', roles: [], session_id: 'session_id', user: { @@ -254,7 +254,7 @@ describe('', () => { can_access_dashboard: false, can_update: false, }, - resource_id: 'ressource_id', + playlist_id: 'playlist_id', roles: [], session_id: 'session_id', user: undefined, diff --git a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/index.spec.tsx b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/index.spec.tsx index 94d61c8dfb..8b130fde28 100644 --- a/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/index.spec.tsx +++ b/src/frontend/packages/lib_video/src/components/live/Student/StudentLiveStarter/StudentLiveAdvertising/index.spec.tsx @@ -40,7 +40,7 @@ jest.mock('lib-components', () => ({ can_access_dashboard: false, can_update: false, }, - resource_id: 'ressource_id', + playlist_id: 'playlist_id', roles: [], session_id: 'session_id', user: { diff --git a/src/frontend/packages/lib_video/src/utils/getOrInitAnonymousId.spec.ts b/src/frontend/packages/lib_video/src/utils/getOrInitAnonymousId.spec.ts index e0d8a37644..96a2b033fc 100644 --- a/src/frontend/packages/lib_video/src/utils/getOrInitAnonymousId.spec.ts +++ b/src/frontend/packages/lib_video/src/utils/getOrInitAnonymousId.spec.ts @@ -1,4 +1,9 @@ -import { decodeJwt, useCurrentUser, useJwt } from 'lib-components'; +import { + DecodedJwtLTI, + decodeJwt, + useCurrentUser, + useJwt, +} from 'lib-components'; import { v4 as uuidv4 } from 'uuid'; import { getOrInitAnonymousId } from './getOrInitAnonymousId'; @@ -34,7 +39,7 @@ const webToken = { user_id: '1324', }; -const ltiToken = { +const ltiToken: DecodedJwtLTI = { context_id: 'course-v1:ufr+mathematics+0001', consumer_site: '112cf553-b8c3-4b98-9d47-d0793284b9b3', locale: 'en_US', @@ -43,7 +48,7 @@ const ltiToken = { can_access_dashboard: false, can_update: false, }, - resource_id: '26debfee-8c3b-4c23-b08f-67f223de9832', + playlist_id: '26debfee-8c3b-4c23-b08f-67f223de9832', roles: ['student'], session_id: '6bbb8d1d-442d-4575-a0ad-d1e34f37cae3', user: {