From 7fba083a49f2480e7e51ce59db86158d5d186c1d Mon Sep 17 00:00:00 2001 From: AsadAzam Date: Tue, 21 Dec 2021 14:46:51 +0500 Subject: [PATCH] fix: added staff check for discussions iframe (#29617) --- .../learner_dashboard/permissions.py | 32 ----------------- .../learner_dashboard/tests/test_views.py | 34 ++++++++++++------- lms/djangoapps/learner_dashboard/views.py | 30 ++++++++++++++-- 3 files changed, 48 insertions(+), 48 deletions(-) delete mode 100644 lms/djangoapps/learner_dashboard/permissions.py diff --git a/lms/djangoapps/learner_dashboard/permissions.py b/lms/djangoapps/learner_dashboard/permissions.py deleted file mode 100644 index 44943b24dd..0000000000 --- a/lms/djangoapps/learner_dashboard/permissions.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Permissions for program discussion api -""" -from django.core.exceptions import ObjectDoesNotExist -from rest_framework import permissions, status -from rest_framework.exceptions import APIException - -from lms.djangoapps.program_enrollments.api import get_program_enrollment - - -class IsEnrolledInProgram(permissions.BasePermission): - """Permission that checks to see if the user is enrolled in the course or is staff.""" - def has_permission(self, request, view): - - """Returns true if the user is enrolled in program""" - if not view.program: - raise ProgramNotFound - - try: - get_program_enrollment(program_uuid=view.kwargs.get('program_uuid'), user=request.user) - except ObjectDoesNotExist: - return False - return True - - -class ProgramNotFound(APIException): - """ - custom exception class for Program not found error - """ - status_code = status.HTTP_404_NOT_FOUND - default_detail = 'Program not found for provided uuid' - default_code = 'program_not_found' diff --git a/lms/djangoapps/learner_dashboard/tests/test_views.py b/lms/djangoapps/learner_dashboard/tests/test_views.py index f5548c97c0..d39569e1d9 100644 --- a/lms/djangoapps/learner_dashboard/tests/test_views.py +++ b/lms/djangoapps/learner_dashboard/tests/test_views.py @@ -2,9 +2,10 @@ Unit tests covering the program discussion iframe API. """ +import ddt from uuid import uuid4 -from django.urls import reverse, reverse_lazy +from django.urls import reverse_lazy from edx_toggles.toggles.testutils import override_waffle_flag from lti_consumer.models import LtiConfiguration from markupsafe import Markup @@ -19,6 +20,7 @@ from openedx.core.djangoapps.catalog.tests.factories import CourseFactory, Cours from openedx.core.djangoapps.discussions.models import ProgramDiscussionsConfiguration +@ddt.ddt @override_waffle_flag(ENABLE_PROGRAM_TAB_VIEW, active=True) @override_waffle_flag(ENABLE_MASTERS_PROGRAM_TAB_VIEW, active=True) class TestProgramDiscussionIframeView(SharedModuleStoreTestCase, ProgramCacheMixin): @@ -93,10 +95,15 @@ class TestProgramDiscussionIframeView(SharedModuleStoreTestCase, ProgramCacheMix self.assertEqual(response.status_code, 200) self.assertEqual(response.data, expected_data) - def test_api_returns_discussions_iframe(self): + @ddt.data(True, False) + def test_api_returns_discussions_iframe(self, staff): """ - Test if API returns iframe in case ProgramDiscussionsConfiguration model contains proper data + Test if API returns iframe in case ProgramDiscussionsConfiguration model contains proper data for staff + and non staff. In case of non staff user must be be enrolled in program. """ + if staff: + self.user = UserFactory(is_staff=True) + self.client.login(username=self.user.username, password=self.password) discussion_config = ProgramDiscussionsConfiguration.objects.create( program_uuid=self.program_uuid, enabled=True, @@ -114,18 +121,19 @@ class TestProgramDiscussionIframeView(SharedModuleStoreTestCase, ProgramCacheMix self.assertIsInstance(response.data['discussion']['iframe'], Markup) self.assertIn('iframe', str(response.data['discussion']['iframe']), ) - def test_program_does_not_exist(self): + def test_program_without_enrollment(self): """ - Test if API returns 404 in case program does not exist - """ - response = self.client.get(reverse('program_discussion', kwargs={'program_uuid': str(uuid4())})) - self.assertEqual(response.status_code, 404) - - def test_program_access_denied(self): - """ - Test if API returns 403 in case user has no access to program + Test if API returns default response in case a non staff user has no enrollment in the program """ self.user = UserFactory() self.client.login(username=self.user.username, password=self.password) response = self.client.get(self.url) - self.assertEqual(response.status_code, 403) + default_response = { + 'tab_view_enabled': False, + 'discussion': { + 'configured': False, + 'iframe': '' + } + } + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data, default_response) diff --git a/lms/djangoapps/learner_dashboard/views.py b/lms/djangoapps/learner_dashboard/views.py index acd866e517..3f38b0209a 100644 --- a/lms/djangoapps/learner_dashboard/views.py +++ b/lms/djangoapps/learner_dashboard/views.py @@ -1,14 +1,17 @@ """Learner dashboard views""" from django.contrib.auth.decorators import login_required +from django.core.exceptions import ObjectDoesNotExist from django.views.decorators.http import require_GET +from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication from rest_framework import permissions, status from rest_framework.authentication import SessionAuthentication from rest_framework.response import Response from rest_framework.views import APIView from lms.djangoapps.learner_dashboard.utils import masters_program_tab_view_is_enabled +from lms.djangoapps.program_enrollments.api import get_program_enrollment from common.djangoapps.edxmako.shortcuts import render_to_response -from lms.djangoapps.learner_dashboard.permissions import IsEnrolledInProgram +from common.djangoapps.student.roles import GlobalStaff from lms.djangoapps.learner_dashboard.programs import ( ProgramDetailsFragmentView, ProgramDiscussionLTI, @@ -101,11 +104,32 @@ class ProgramDiscussionIframeView(APIView, ProgramSpecificViewMixin): } """ - authentication_classes = (BearerAuthentication, SessionAuthentication) - permission_classes = (permissions.IsAuthenticated, IsEnrolledInProgram) + authentication_classes = (JwtAuthentication, BearerAuthentication, SessionAuthentication) + permission_classes = (permissions.IsAuthenticated,) + + def is_enrolled_or_staff(self, request, program_uuid): + """Returns true if the user is enrolled in the program or staff""" + + if GlobalStaff().has_user(request.user): + return True + + try: + get_program_enrollment(program_uuid=program_uuid, user=request.user) + except ObjectDoesNotExist: + return False + return True def get(self, request, program_uuid): """ GET handler """ + if not self.is_enrolled_or_staff(request, program_uuid): + default_response = { + 'tab_view_enabled': False, + 'discussion': { + 'configured': False, + 'iframe': '' + } + } + return Response(default_response, status=status.HTTP_200_OK) program_discussion_lti = ProgramDiscussionLTI(program_uuid, request) response_data = { 'tab_view_enabled': masters_program_tab_view_is_enabled(),