def test_get_enterprise_consent_url_next_provided_not_course_specific( self, needed_for_course_mock): """ Verify that get_enterprise_consent_url correctly builds URLs. """ needed_for_course_mock.return_value = True request_mock = mock.MagicMock( user=None, build_absolute_uri=lambda x: 'http://localhost:8000' + x # Don't do it like this in prod. Ever. ) course_id = 'course-v1:edX+DemoX+Demo_Course' expected_url = ( '/enterprise/grant_data_sharing_permissions?course_id=course-v1%3AedX%2BDemoX%2BDemo_' 'Course&failure_url=http%3A%2F%2Flocalhost%3A8000%2Fdashboard%3Fconsent_failed%3Dcou' 'rse-v1%253AedX%252BDemoX%252BDemo_Course&next=http%3A%2F%2Flocalhost%3A8000%2Fdashboard' ) actual_url = get_enterprise_consent_url(request_mock, course_id, return_to='dashboard', course_specific_return=False) self.assertEqual(actual_url, expected_url)
def test_get_enterprise_consent_url( self, needed_for_course_mock, reverse_mock, enterprise_customer_uuid_for_request_mock, ): """ Verify that get_enterprise_consent_url correctly builds URLs. """ def fake_reverse(*args, **kwargs): if args[0] == 'grant_data_sharing_permissions': return '/enterprise/grant_data_sharing_permissions' return reverse(*args, **kwargs) enterprise_customer_uuid_for_request_mock.return_value = 'cf246b88-d5f6-4908-a522-fc307e0b0c59' reverse_mock.side_effect = fake_reverse needed_for_course_mock.return_value = True request_mock = mock.MagicMock( user=self.user, build_absolute_uri=lambda x: 'http://localhost:8000' + x # Don't do it like this in prod. Ever. ) course_id = 'course-v1:edX+DemoX+Demo_Course' return_to = 'info' expected_url = ( '/enterprise/grant_data_sharing_permissions?course_id=course-v1%3AedX%2BDemoX%2BDemo_' 'Course&failure_url=http%3A%2F%2Flocalhost%3A8000%2Fdashboard%3Fconsent_failed%3Dcou' 'rse-v1%253AedX%252BDemoX%252BDemo_Course&enterprise_customer_uuid=cf246b88-d5f6-4908' '-a522-fc307e0b0c59&next=http%3A%2F%2Flocalhost%3A8000%2Fcourses%2Fcourse-v1%3AedX%2B' 'DemoX%2BDemo_Course%2Finfo' ) actual_url = get_enterprise_consent_url(request_mock, course_id, return_to=return_to) self.assertEqual(actual_url, expected_url)
def test_get_enterprise_consent_url(self, needed_for_course_mock, reverse_mock): """ Verify that get_enterprise_consent_url correctly builds URLs. """ def fake_reverse(*args, **kwargs): if args[0] == 'grant_data_sharing_permissions': return '/enterprise/grant_data_sharing_permissions' return reverse(*args, **kwargs) reverse_mock.side_effect = fake_reverse needed_for_course_mock.return_value = True request_mock = mock.MagicMock( user=None, build_absolute_uri=lambda x: 'http://localhost:8000' + x # Don't do it like this in prod. Ever. ) course_id = 'course-v1:edX+DemoX+Demo_Course' return_to = 'info' expected_url = ( '/enterprise/grant_data_sharing_permissions?course_id=course-v1%3AedX%2BDemoX%2BDemo_' 'Course&failure_url=http%3A%2F%2Flocalhost%3A8000%2Fdashboard%3Fconsent_failed%3Dcou' 'rse-v1%253AedX%252BDemoX%252BDemo_Course&next=http%3A%2F%2Flocalhost%3A8000%2Fcours' 'es%2Fcourse-v1%3AedX%2BDemoX%2BDemo_Course%2Finfo') actual_url = get_enterprise_consent_url(request_mock, course_id, return_to=return_to) self.assertEqual(actual_url, expected_url)
def process_view(self, request, view_func, view_args, view_kwargs): # pylint: disable=unused-argument """ This function handles authentication logic for wiki urls and redirects from the "root wiki" to the "course wiki" if the user accesses the wiki from a course url """ # we care only about requests to wiki urls if not view_func.__module__.startswith('wiki.'): return # wiki pages are login required if not request.user.is_authenticated: return redirect(reverse('signin_user'), next=request.path) course_id = course_id_from_url(request.path) wiki_path = request.path.partition('/wiki/')[2] if course_id: # This is a /courses/org/name/run/wiki request course_path = "/courses/{}".format(text_type(course_id)) # HACK: django-wiki monkeypatches the reverse function to enable # urls to be rewritten reverse._transform_url = lambda url: course_path + url # pylint: disable=protected-access # Authorization Check # Let's see if user is enrolled or the course allows for public access try: course = get_course_with_access(request.user, 'load', course_id) except Http404: # course does not exist. redirect to root wiki. # clearing the referrer will cause process_response not to redirect # back to a non-existent course request.META['HTTP_REFERER'] = '' return redirect('/wiki/{}'.format(wiki_path)) if not course.allow_public_wiki_access: is_enrolled = CourseEnrollment.is_enrolled( request.user, course.id) is_staff = has_access(request.user, 'staff', course) if not (is_enrolled or is_staff): # if a user is logged in, but not authorized to see a page, # we'll redirect them to the course about page return redirect('about_course', text_type(course_id)) # If we need enterprise data sharing consent for this course, then redirect to the form. consent_url = get_enterprise_consent_url( request, text_type(course_id)) if consent_url: return redirect(consent_url) # set the course onto here so that the wiki template can show the course navigation request.course = course else: # this is a request for /wiki/... # Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs # this will help prevent people from writing pell-mell to the Wiki in an unstructured way if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False): raise PermissionDenied() return self._redirect_from_referrer(request, wiki_path)
def process_view(self, request, view_func, view_args, view_kwargs): # pylint: disable=unused-argument """ This function handles authentication logic for wiki urls and redirects from the "root wiki" to the "course wiki" if the user accesses the wiki from a course url """ # we care only about requests to wiki urls if not view_func.__module__.startswith('wiki.'): return # wiki pages are login required if not request.user.is_authenticated(): return redirect(reverse('signin_user'), next=request.path) course_id = course_id_from_url(request.path) wiki_path = request.path.partition('/wiki/')[2] if course_id: # This is a /courses/org/name/run/wiki request course_path = "/courses/{}".format(course_id.to_deprecated_string()) # HACK: django-wiki monkeypatches the reverse function to enable # urls to be rewritten reverse._transform_url = lambda url: course_path + url # pylint: disable=protected-access # Authorization Check # Let's see if user is enrolled or the course allows for public access try: course = get_course_with_access(request.user, 'load', course_id) except Http404: # course does not exist. redirect to root wiki. # clearing the referrer will cause process_response not to redirect # back to a non-existent course request.META['HTTP_REFERER'] = '' return redirect('/wiki/{}'.format(wiki_path)) if not course.allow_public_wiki_access: is_enrolled = CourseEnrollment.is_enrolled(request.user, course.id) is_staff = has_access(request.user, 'staff', course) if not (is_enrolled or is_staff): # if a user is logged in, but not authorized to see a page, # we'll redirect them to the course about page return redirect('about_course', course_id.to_deprecated_string()) # If we need enterprise data sharing consent for this course, then redirect to the form. consent_url = get_enterprise_consent_url(request, unicode(course_id)) if consent_url: return redirect(consent_url) # set the course onto here so that the wiki template can show the course navigation request.course = course else: # this is a request for /wiki/... # Check to see if we don't allow top-level access to the wiki via the /wiki/xxxx/yyy/zzz URLs # this will help prevent people from writing pell-mell to the Wiki in an unstructured way if not settings.FEATURES.get('ALLOW_WIKI_ROOT_ACCESS', False): raise PermissionDenied() return self._redirect_from_referrer(request, wiki_path)
def test_get_enterprise_consent_url( self, needed_for_course_mock, reverse_mock, enterprise_customer_uuid_for_request_mock, ): """ Verify that get_enterprise_consent_url correctly builds URLs. """ def fake_reverse(*args, **kwargs): if args[0] == 'grant_data_sharing_permissions': return '/enterprise/grant_data_sharing_permissions' return reverse(*args, **kwargs) enterprise_customer_uuid_for_request_mock.return_value = 'cf246b88-d5f6-4908-a522-fc307e0b0c59' reverse_mock.side_effect = fake_reverse needed_for_course_mock.return_value = True request_mock = mock.MagicMock( user=self.user, build_absolute_uri=lambda x: 'http://localhost:8000' + x # Don't do it like this in prod. Ever. ) course_id = 'course-v1:edX+DemoX+Demo_Course' return_to = 'info' expected_url_args = { 'course_id': ['course-v1:edX+DemoX+Demo_Course'], 'failure_url': [ 'http://localhost:8000/dashboard?consent_failed=course-v1%3AedX%2BDemoX%2BDemo_Course' ], 'enterprise_customer_uuid': ['cf246b88-d5f6-4908-a522-fc307e0b0c59'], 'next': [ 'http://localhost:8000/courses/course-v1:edX+DemoX+Demo_Course/info' ] } actual_url = get_enterprise_consent_url(request_mock, course_id, return_to=return_to) actual_url_args = parse_qs( actual_url.split('/enterprise/grant_data_sharing_permissions?')[1]) self.assertEqual(actual_url_args, expected_url_args)
def test_get_enterprise_consent_url_next_provided_not_course_specific(self, needed_for_course_mock): """ Verify that get_enterprise_consent_url correctly builds URLs. """ needed_for_course_mock.return_value = True request_mock = mock.MagicMock( user=None, build_absolute_uri=lambda x: 'http://localhost:8000' + x # Don't do it like this in prod. Ever. ) course_id = 'course-v1:edX+DemoX+Demo_Course' expected_url = ( '/enterprise/grant_data_sharing_permissions?course_id=course-v1%3AedX%2BDemoX%2BDemo_' 'Course&failure_url=http%3A%2F%2Flocalhost%3A8000%2Fdashboard%3Fconsent_failed%3Dcou' 'rse-v1%253AedX%252BDemoX%252BDemo_Course&next=http%3A%2F%2Flocalhost%3A8000%2Fdashboard' ) actual_url = get_enterprise_consent_url(request_mock, course_id, return_to='dashboard', course_specific_return=False) self.assertEqual(actual_url, expected_url)
def _get_redirect_url_for_audit_enrollment(self, request, course_id): """ After a user has been enrolled in a course in an audit mode, determine the appropriate location to which they ought to be redirected, bearing in mind enterprise data sharing consent considerations. """ enterprise_learner_data = enterprise_api.get_enterprise_learner_data( site=request.site, user=request.user) if enterprise_learner_data: enterprise_learner = enterprise_learner_data[0] # If we have an enterprise learner, check to see if the current course is in the enterprise's catalog. is_course_in_enterprise_catalog = enterprise_api.is_course_in_enterprise_catalog( site=request.site, course_id=course_id, enterprise_catalog_id=enterprise_learner['enterprise_customer'] ['catalog']) # If the course is in the catalog, check for an existing Enterprise enrollment if is_course_in_enterprise_catalog: client = enterprise_api.EnterpriseApiClient() if not client.get_enterprise_course_enrollment( enterprise_learner['id'], course_id): # If there's no existing Enterprise enrollment, create one. client.post_enterprise_course_enrollment( request.user.username, course_id, None) # Check if consent is required, and generate a redirect URL to the # consent service if so; this function returns None if consent # is not required or has already been granted. consent_url = get_enterprise_consent_url( request, course_id, user=request.user, return_to='dashboard', course_specific_return=False, ) # If we got a redirect URL for consent, go there. if consent_url: return consent_url # If the enrollment isn't Enterprise-linked, or if consent isn't necessary, go to the Dashboard. return reverse('dashboard')
def _get_redirect_url_for_audit_enrollment(self, request, course_id): """ After a user has been enrolled in a course in an audit mode, determine the appropriate location to which they ought to be redirected, bearing in mind enterprise data sharing consent considerations. """ enterprise_learner_data = enterprise_api.get_enterprise_learner_data(site=request.site, user=request.user) if enterprise_learner_data: enterprise_learner = enterprise_learner_data[0] # If we have an enterprise learner, check to see if the current course is in the enterprise's catalog. is_course_in_enterprise_catalog = enterprise_api.is_course_in_enterprise_catalog( site=request.site, course_id=course_id, enterprise_catalog_id=enterprise_learner['enterprise_customer']['catalog'] ) # If the course is in the catalog, check for an existing Enterprise enrollment if is_course_in_enterprise_catalog: client = enterprise_api.EnterpriseApiClient() if not client.get_enterprise_course_enrollment(enterprise_learner['id'], course_id): # If there's no existing Enterprise enrollment, create one. client.post_enterprise_course_enrollment(request.user.username, course_id, None) # Check if consent is required, and generate a redirect URL to the # consent service if so; this function returns None if consent # is not required or has already been granted. consent_url = get_enterprise_consent_url( request, course_id, user=request.user, return_to='dashboard', course_specific_return=False, ) # If we got a redirect URL for consent, go there. if consent_url: return consent_url # If the enrollment isn't Enterprise-linked, or if consent isn't necessary, go to the Dashboard. return reverse('dashboard')