Commit 22c8e4c6 by Robert Raposa

Redirect Course Home for course that hasn't started.

Includes the following:
- Move the redirect logic for before course that hasn't started to
share between Course Info and Course Home.
- Add audit comments for Course Info vs Course Home
- Other minor clean-up.

LEARNER-613
parent 13e06a37
......@@ -6,16 +6,10 @@ import logging
from collections import defaultdict
from datetime import datetime
import pytz
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import Http404
from fs.errors import ResourceNotFoundError
from opaque_keys.edx.keys import UsageKey
from path import Path as path
import branding
import pytz
from courseware.access import has_access
from courseware.access_response import StartDateError
from courseware.date_summary import (
CourseEndDate,
CourseStartDate,
......@@ -25,13 +19,20 @@ from courseware.date_summary import (
)
from courseware.model_data import FieldDataCache
from courseware.module_render import get_module, get_module_for_descriptor
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import Http404, QueryDict
from edxmako.shortcuts import render_to_string
from fs.errors import ResourceNotFoundError
from lms.djangoapps.courseware.courseware_access_exception import CoursewareAccessException
from lms.djangoapps.courseware.exceptions import CourseAccessRedirect
from opaque_keys.edx.keys import UsageKey
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from path import Path as path
from static_replace import replace_static_urls
from student.models import CourseEnrollment
from util.date_utils import strftime_localized
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.x_module import STUDENT_VIEW
......@@ -121,6 +122,16 @@ def check_course_access(course, user, action, check_if_enrolled=False):
access_response = has_access(user, action, course, course.id)
if not access_response:
# Redirect if StartDateError
if isinstance(access_response, StartDateError):
start_date = strftime_localized(course.start, 'SHORT_DATE')
params = QueryDict(mutable=True)
params['notlive'] = start_date
raise CourseAccessRedirect('{dashboard_url}?{params}'.format(
dashboard_url=reverse('dashboard'),
params=params.urlencode()
))
# Deliberately return a non-specific error message to avoid
# leaking info about access control settings
raise CoursewareAccessException(access_response)
......
......@@ -8,11 +8,10 @@ from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import QueryDict
from django.test.utils import override_settings
from nose.plugins.attrib import attr
from pyquery import PyQuery as pq
from lms.djangoapps.ccx.tests.factories import CcxFactory
from nose.plugins.attrib import attr
from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration
from pyquery import PyQuery as pq
from student.models import CourseEnrollment
from student.tests.factories import AdminFactory
from util.date_utils import strftime_localized
......@@ -58,6 +57,7 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase):
resp = self.client.get(url)
self.assertNotIn("You are not currently enrolled in this course", resp.content)
# TODO: LEARNER-611: If this is only tested under Course Info, does this need to move?
@mock.patch('openedx.features.enterprise_support.api.get_enterprise_consent_url')
def test_redirection_missing_enterprise_consent(self, mock_get_url):
"""
......@@ -120,7 +120,7 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase):
self.assertRedirects(response, expected_url)
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
@mock.patch("courseware.views.views.strftime_localized")
@mock.patch("util.date_utils.strftime_localized")
def test_non_live_course_other_language(self, mock_strftime_localized):
"""Ensure that a user accessing a non-live course sees a redirect to
the student dashboard, not a 404, even if the localized date is unicode
......@@ -385,7 +385,7 @@ class SelfPacedCourseInfoTestCase(LoginEnrollmentTestCase, SharedModuleStoreTest
self.assertEqual(resp.status_code, 200)
def test_num_queries_instructor_paced(self):
self.fetch_course_info_with_queries(self.instructor_paced_course, 26, 4)
self.fetch_course_info_with_queries(self.instructor_paced_course, 26, 3)
def test_num_queries_self_paced(self):
self.fetch_course_info_with_queries(self.self_paced_course, 26, 4)
self.fetch_course_info_with_queries(self.self_paced_course, 26, 3)
......@@ -60,7 +60,7 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
Check that non-staff don't have access to dark urls.
"""
names = ['courseware', 'instructor_dashboard', 'progress']
names = ['courseware', 'progress']
urls = self._reverse_urls(names, course)
urls.extend([
reverse('book', kwargs={'course_id': course.id.to_deprecated_string(),
......@@ -68,7 +68,11 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
for index, __ in enumerate(course.textbooks)
])
for url in urls:
self.assert_request_status_code(404, url)
self.assert_request_status_code(302, url)
self.assert_request_status_code(
404, reverse('instructor_dashboard', kwargs={'course_id': course.id.to_deprecated_string()})
)
def _check_staff(self, course):
"""
......@@ -97,7 +101,7 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
'student_id': self.enrolled_user.id,
}
)
self.assert_request_status_code(404, url)
self.assert_request_status_code(302, url)
# The courseware url should redirect, not 200
url = self._reverse_urls(['courseware'], course)[0]
......@@ -351,9 +355,9 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
self.enroll(self.test_course, True)
# should now be able to get to everything for self.course
self._check_staff(self.course)
self._check_non_staff_light(self.test_course)
self._check_non_staff_dark(self.test_course)
self._check_staff(self.course)
@patch.dict('courseware.access.settings.FEATURES', {'DISABLE_START_DATES': False})
def test_dark_launch_global_staff(self):
......
# coding=utf-8
"""
Tests for the course home page.
"""
import ddt
import mock
from courseware.tests.factories import StaffFactory
from django.conf import settings
from django.core.urlresolvers import reverse
from django.http import QueryDict
from django.utils.http import urlquote_plus
from openedx.core.djangoapps.waffle_utils.testutils import WAFFLE_TABLES, override_waffle_flag
from openedx.features.course_experience import SHOW_REVIEWS_TOOL_FLAG, UNIFIED_COURSE_TAB_FLAG
from student.models import CourseEnrollment
from student.tests.factories import UserFactory
from util.date_utils import strftime_localized
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.django_utils import CourseUserType, SharedModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls
......@@ -28,12 +32,25 @@ QUERY_COUNT_TABLE_BLACKLIST = WAFFLE_TABLES
def course_home_url(course):
"""
Returns the URL for the course's home page
Returns the URL for the course's home page.
Arguments:
course (CourseDescriptor): The course being tested.
"""
return course_home_url_from_string(unicode(course.id))
def course_home_url_from_string(course_key_string):
"""
Returns the URL for the course's home page.
Arguments:
course_key_string (String): The course key as string.
"""
return reverse(
'openedx.course_experience.course_home',
kwargs={
'course_id': unicode(course.id),
'course_id': course_key_string,
}
)
......@@ -211,3 +228,54 @@ class TestCourseHomePageAccess(CourseHomePageTestCase):
url = course_home_url(self.course)
response = self.client.get(url)
self.assertContains(response, '/login?next={url}'.format(url=urlquote_plus(url)))
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
def test_non_live_course(self):
"""
Ensure that a user accessing a non-live course sees a redirect to
the student dashboard, not a 404.
"""
self.user = self.create_user_for_course(self.course, CourseUserType.ENROLLED)
url = course_home_url(self.course)
response = self.client.get(url)
start_date = strftime_localized(self.course.start, 'SHORT_DATE')
expected_params = QueryDict(mutable=True)
expected_params['notlive'] = start_date
expected_url = '{url}?{params}'.format(
url=reverse('dashboard'),
params=expected_params.urlencode()
)
self.assertRedirects(response, expected_url)
@mock.patch.dict(settings.FEATURES, {'DISABLE_START_DATES': False})
@mock.patch("util.date_utils.strftime_localized")
def test_non_live_course_other_language(self, mock_strftime_localized):
"""
Ensure that a user accessing a non-live course sees a redirect to
the student dashboard, not a 404, even if the localized date is unicode
"""
self.user = self.create_user_for_course(self.course, CourseUserType.ENROLLED)
fake_unicode_start_time = u"üñîçø∂é_ßtå®t_tîµé"
mock_strftime_localized.return_value = fake_unicode_start_time
url = course_home_url(self.course)
response = self.client.get(url)
expected_params = QueryDict(mutable=True)
expected_params['notlive'] = fake_unicode_start_time
expected_url = u'{url}?{params}'.format(
url=reverse('dashboard'),
params=expected_params.urlencode()
)
self.assertRedirects(response, expected_url)
def test_nonexistent_course(self):
"""
Ensure a non-existent course results in a 404.
"""
self.user = self.create_user_for_course(self.course, CourseUserType.ANONYMOUS)
url = course_home_url_from_string('not/a/course')
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment