Redirect to dashboard from non-live courses.

TNL-2693
This commit is contained in:
Peter Fogg
2015-07-23 11:44:25 -04:00
parent ac0d79628f
commit c8ed59ac61
9 changed files with 114 additions and 8 deletions

View File

@@ -3,10 +3,13 @@ Test the course_info xblock
"""
import mock
from nose.plugins.attrib import attr
from urllib import urlencode
from django.conf import settings
from django.core.urlresolvers import reverse
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from util.date_utils import strftime_localized
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.django_utils import TEST_DATA_MIXED_CLOSED_MODULESTORE
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
@@ -62,6 +65,24 @@ class CourseInfoTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
).exists()
self.assertFalse(enrollment_exists)
@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.setup_user()
self.enroll(self.course)
url = reverse('info', args=[unicode(self.course.id)])
response = self.client.get(url)
start_date = strftime_localized(self.course.start, 'SHORT_DATE')
self.assertRedirects(response, '{0}?{1}'.format(reverse('dashboard'), urlencode({'notlive': start_date})))
def test_nonexistent_course(self):
self.setup_user()
url = reverse('info', args=['not/a/course'])
response = self.client.get(url)
self.assertEqual(response.status_code, 404)
@attr('shard_1')
class CourseInfoTestCaseXML(LoginEnrollmentTestCase, ModuleStoreTestCase):

View File

@@ -31,8 +31,9 @@ from markupsafe import escape
from courseware import grades
from courseware.access import has_access, in_preview_mode, _adjust_start_date_for_beta_testers
from courseware.access_response import StartDateError
from courseware.courses import (
get_courses, get_course,
get_courses, get_course, get_course_by_id,
get_studio_url, get_course_with_access,
sort_by_announcement,
sort_by_start_date,
@@ -60,6 +61,7 @@ from open_ended_grading.views import StaffGradingTab, PeerGradingTab, OpenEndedG
from student.models import UserTestGroup, CourseEnrollment
from student.views import is_course_blocked
from util.cache import cache, cache_if_anonymous
from util.date_utils import strftime_localized
from xblock.fragment import Fragment
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem
@@ -674,9 +676,23 @@ def course_info(request, course_id):
Assumes the course_id is in a valid format.
"""
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
with modulestore().bulk_operations(course_key):
course = get_course_with_access(request.user, 'load', course_key)
course = get_course_by_id(course_key, depth=2)
access_response = has_access(request.user, 'load', course, course_key)
if not access_response:
# The user doesn't have access to the course. If they're
# denied permission due to the course not being live yet,
# redirect to the dashboard page.
if isinstance(access_response, StartDateError):
start_date = strftime_localized(course.start, 'SHORT_DATE')
params = urllib.urlencode({'notlive': start_date})
return redirect('{0}?{1}'.format(reverse('dashboard'), params))
# Otherwise, give a 404 to avoid leaking info about access
# control.
raise Http404("Course not found.")
staff_access = has_access(request.user, 'staff', course)
masquerade, user = setup_masquerade(request, course_key, staff_access, reset_masquerade_data=True)

View File

@@ -6,7 +6,11 @@
var MessageBannerView = Backbone.View.extend({
initialize: function () {
initialize: function (options) {
if (_.isUndefined(options)) {
options = {};
}
this.options = _.defaults(options, {urgency: 'high', type: ''});
this.template = _.template($('#message_banner-tpl').text());
},
@@ -14,9 +18,9 @@
if (_.isUndefined(this.message) || _.isNull(this.message)) {
this.$el.html('');
} else {
this.$el.html(this.template({
this.$el.html(this.template(_.extend(this.options, {
message: this.message
}));
})));
}
return this;
},

View File

@@ -27,6 +27,7 @@
'js/student_account/views/account_settings_factory',
'js/student_account/views/finish_auth_factory',
'js/student_profile/views/learner_profile_factory',
'js/views/message_banner',
'teams/js/teams_tab_factory'
]),

View File

@@ -7,6 +7,7 @@ import third_party_auth
from third_party_auth import pipeline
from microsite_configuration import microsite
from django.core.urlresolvers import reverse
import json
%>
<%
@@ -24,6 +25,9 @@ from django.core.urlresolvers import reverse
<script type="text/template" id="${template_name}-tpl">
<%static:include path="dashboard/${template_name}.underscore" />
</script>
<script type="text/template" id="message_banner-tpl">
<%static:include path="fields/message_banner.underscore" />
</script>
% endfor
% for template_name in ["dashboard_search_item", "dashboard_search_results", "search_loading", "search_error"]:
@@ -49,6 +53,13 @@ from django.core.urlresolvers import reverse
DashboardSearchFactory();
</%static:require_module>
% endif
% if redirect_message:
<%static:require_module module_name="js/views/message_banner" class_name="MessageBannerView">
var banner = new MessageBannerView({urgency: 'low', type: 'warning'});
$('#content').prepend(banner.$el);
banner.showMessage(${json.dumps(redirect_message)})
</%static:require_module>
% endif
</%block>
<div class="dashboard-notifications" tabindex="-1">

View File

@@ -1,4 +1,4 @@
<div class="wrapper-msg urgency-high">
<div class="wrapper-msg urgency-<%= urgency %> <%= type %>">
<div class="msg">
<div class="msg-content">
<div class="copy">
@@ -6,4 +6,4 @@
</div>
</div>
</div>
</div>
</div>