Commit a83d0686 by Aamir

Merge pull request #7617 from edx/aamir-khan/ECOM-1290-redirect-to-courseware-new

ECOM-1290: added the redirection back to courseware after re-verificatio...
parents d45aecff ca08b979
"""
Module to define url helpers functions
"""
from xmodule.modulestore.search import path_to_location, navigation_index
from xmodule.modulestore.django import modulestore
from django.core.urlresolvers import reverse
def get_redirect_url(course_key, usage_key):
""" Returns the redirect url back to courseware
Args:
course_id(str): Course Id string
location(str): The location id of course component
Raises:
ItemNotFoundError if no data at the location or NoPathToItem if location not in any class
Returns:
Redirect url string
"""
(course_key, chapter, section, position) = path_to_location(modulestore(), usage_key)
# choose the appropriate view (and provide the necessary args) based on the
# args provided by the redirect.
# Rely on index to do all error handling and access control.
if chapter is None:
redirect_url = reverse('courseware', args=(unicode(course_key), ))
elif section is None:
redirect_url = reverse('courseware_chapter', args=(unicode(course_key), chapter))
elif position is None:
redirect_url = reverse(
'courseware_section',
args=(unicode(course_key), chapter, section)
)
else:
# Here we use the navigation_index from the position returned from
# path_to_location - we can only navigate to the topmost vertical at the
# moment
redirect_url = reverse(
'courseware_position',
args=(unicode(course_key), chapter, section, navigation_index(position))
)
return redirect_url
......@@ -60,7 +60,6 @@ from util.cache import cache, cache_if_anonymous
from xblock.fragment import Fragment
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem
from xmodule.modulestore.search import path_to_location, navigation_index
from xmodule.tabs import CourseTabList, StaffGradingTab, PeerGradingTab, OpenEndedGradingTab
from xmodule.x_module import STUDENT_VIEW
import shoppingcart
......@@ -82,6 +81,7 @@ import survey.views
from util.views import ensure_valid_course_key
from eventtracking import tracker
import analytics
from courseware.url_helpers import get_redirect_url
log = logging.getLogger("edx.courseware")
......@@ -642,37 +642,13 @@ def jump_to(_request, course_id, location):
except InvalidKeyError:
raise Http404(u"Invalid course_key or usage_key")
try:
(course_key, chapter, section, position) = path_to_location(modulestore(), usage_key)
redirect_url = get_redirect_url(course_key, usage_key)
except ItemNotFoundError:
raise Http404(u"No data at this location: {0}".format(usage_key))
except NoPathToItem:
raise Http404(u"This location is not in any class: {0}".format(usage_key))
# choose the appropriate view (and provide the necessary args) based on the
# args provided by the redirect.
# Rely on index to do all error handling and access control.
if chapter is None:
return redirect('courseware', course_id=unicode(course_key))
elif section is None:
return redirect('courseware_chapter', course_id=unicode(course_key), chapter=chapter)
elif position is None:
return redirect(
'courseware_section',
course_id=unicode(course_key),
chapter=chapter,
section=section
)
else:
# Here we use the navigation_index from the position returned from
# path_to_location - we can only navigate to the topmost vertical at the
# moment
return redirect(
'courseware_position',
course_id=unicode(course_key),
chapter=chapter,
section=section,
position=navigation_index(position)
)
return redirect(redirect_url)
@ensure_csrf_cookie
......
......@@ -34,7 +34,7 @@ class ReverificationService(object):
except ObjectDoesNotExist:
return None
def start_verification(self, course_id, checkpoint_name, item_id): # pylint: disable=W0613
def start_verification(self, course_id, checkpoint_name, item_id):
""" Get or create the verification checkpoint and return the re-verification link
Args:
......@@ -46,5 +46,5 @@ class ReverificationService(object):
"""
course_key = CourseKey.from_string(course_id)
VerificationCheckpoint.objects.get_or_create(course_id=course_key, checkpoint_name=checkpoint_name)
re_verification_link = reverse("verify_student_incourse_reverify", args=(course_id, checkpoint_name))
re_verification_link = reverse("verify_student_incourse_reverify", args=(course_id, checkpoint_name, item_id))
return re_verification_link
......@@ -20,7 +20,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core import mail
from bs4 import BeautifulSoup
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import ModuleStoreEnum
from opaque_keys.edx.locations import SlashSeparatedCourseKey
......@@ -1701,20 +1701,42 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
IMAGE_DATA = "abcd,1234"
MIDTERM = "midterm"
def setUp(self):
super(TestInCourseReverifyView, self).setUp()
self.user = UserFactory.create(username="rusty", password="test")
self.client.login(username="rusty", password="test")
def build_course(self):
"""
Build up a course tree with a Reverificaiton xBlock.
"""
# pylint: disable=attribute-defined-outside-init
self.course_key = SlashSeparatedCourseKey("Robot", "999", "Test_Course")
CourseFactory.create(org='Robot', number='999', display_name='Test Course')
self.course = CourseFactory.create(org='Robot', number='999', display_name='Test Course')
# Create the course modes
for mode in ('audit', 'honor', 'verified'):
min_price = 0 if mode in ["honor", "audit"] else 1
CourseModeFactory(mode_slug=mode, course_id=self.course_key, min_price=min_price)
# Create the 'edx-reverification-block' in course tree
section = ItemFactory.create(parent=self.course, category='chapter', display_name='Test Section')
subsection = ItemFactory.create(parent=section, category='sequential', display_name='Test Subsection')
vertical = ItemFactory.create(parent=subsection, category='vertical', display_name='Test Unit')
reverification = ItemFactory.create(
parent=vertical,
category='edx-reverification-block',
display_name='Test Verification Block'
)
self.section_location = section.location
self.subsection_location = subsection.location
self.vertical_location = vertical.location
self.reverification_location = reverification.location
def setUp(self):
super(TestInCourseReverifyView, self).setUp()
self.build_course()
self.user = UserFactory.create(username="rusty", password="test")
self.client.login(username="rusty", password="test")
# Enroll the user in the default mode (honor) to emulate
CourseEnrollment.enroll(self.user, self.course_key, mode="verified")
self.config = InCourseReverificationConfiguration(enabled=True)
......@@ -1863,4 +1885,8 @@ class TestInCourseReverifyView(ModuleStoreTestCase):
"""
return reverse('verify_student_incourse_reverify',
kwargs={"course_id": unicode(course_key), "checkpoint_name": checkpoint})
kwargs={
"course_id": unicode(course_key),
"checkpoint_name": checkpoint,
"location": unicode(self.reverification_location)
})
......@@ -143,7 +143,7 @@ urlpatterns = patterns(
# Users are sent to this end-point from within courseware
# to re-verify their identities by re-submitting face photos.
url(
r'^reverify/{course_id}/{checkpoint}/$'.format(
r'^reverify/{course_id}/{checkpoint}/(?P<location>.*)/$'.format(
course_id=settings.COURSE_ID_PATTERN, checkpoint=settings.CHECKPOINT_PATTERN
),
views.InCourseReverifyView.as_view(),
......
......@@ -24,9 +24,10 @@ from django.utils.decorators import method_decorator
from django.utils.translation import ugettext as _, ugettext_lazy
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from opaque_keys.edx.keys import CourseKey
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys import InvalidKeyError
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.exceptions import ItemNotFoundError, NoPathToItem
from edxmako.shortcuts import render_to_response, render_to_string
from openedx.core.djangoapps.user_api.accounts.api import get_account_settings, update_account_settings
......@@ -55,7 +56,7 @@ from util.json_request import JsonResponse
from util.date_utils import get_default_time_display
from eventtracking import tracker
import analytics
from courseware.url_helpers import get_redirect_url
log = logging.getLogger(__name__)
......@@ -1114,7 +1115,7 @@ class InCourseReverifyView(View):
Does not need to worry about pricing
"""
@method_decorator(login_required)
def get(self, request, course_id, checkpoint_name):
def get(self, request, course_id, checkpoint_name, location):
""" Display the view for face photo submission"""
# Check the in-course re-verification is enabled or not
incourse_reverify_enabled = InCourseReverificationConfiguration.current().enabled
......@@ -1145,11 +1146,12 @@ class InCourseReverifyView(View):
'course_name': course.display_name_with_default,
'checkpoint_name': checkpoint_name,
'platform_name': settings.PLATFORM_NAME,
'location': location
}
return render_to_response("verify_student/incourse_reverify.html", context)
@method_decorator(login_required)
def post(self, request, course_id, checkpoint_name):
def post(self, request, course_id, checkpoint_name, location):
"""Submits the re-verification attempt to SoftwareSecure
Args:
......@@ -1168,7 +1170,11 @@ class InCourseReverifyView(View):
raise Http404
user = request.user
course_key = CourseKey.from_string(course_id)
try:
course_key = CourseKey.from_string(course_id)
usage_key = UsageKey.from_string(location).replace(course_key=course_key)
except InvalidKeyError:
raise Http404(u"Invalid course_key or usage_key")
course = modulestore().get_course(course_key)
checkpoint = VerificationCheckpoint.get_verification_checkpoint(course_key, checkpoint_name)
if checkpoint is None:
......@@ -1181,6 +1187,7 @@ class InCourseReverifyView(View):
'error': True,
'errorMsg': _("No checkpoint found"),
'platform_name': settings.PLATFORM_NAME,
'location': location
}
return render_to_response("verify_student/incourse_reverify.html", context)
init_verification = SoftwareSecurePhotoVerification.get_initial_verification(user)
......@@ -1200,12 +1207,20 @@ class InCourseReverifyView(View):
EVENT_NAME_USER_SUBMITTED_INCOURSE_REVERIFY, user.id, course_id, checkpoint_name
)
return HttpResponse()
try:
redirect_url = get_redirect_url(course_key, usage_key)
except (ItemNotFoundError, NoPathToItem):
redirect_url = reverse("courseware", args=(unicode(course_key),))
return JsonResponse({'url': redirect_url})
except Http404 as expt:
log.exception("Invalid location during photo verification.")
return HttpResponseBadRequest(expt.message)
except IndexError:
log.exception("Invalid image data during photo verification.")
return HttpResponseBadRequest(_("Invalid image data during photo verification."))
except Exception: # pylint: disable=broad-except
log.exception("Could not submit verification attempt for user {}.").format(request.user.id)
log.exception("Could not submit verification attempt for user %s.", request.user.id)
msg = _("Could not submit photos")
return HttpResponseBadRequest(msg)
......
......@@ -22,6 +22,7 @@
courseKey: el.data('course-key'),
checkpointName: el.data('checkpoint-name'),
platformName: el.data('platform-name'),
location: el.data('location'),
errorModel: errorView.model
}).render();
......
......@@ -18,18 +18,20 @@ var edx = edx || {};
courseKey: '',
checkpointName: '',
faceImage: '',
location: ''
},
sync: function( method ) {
var model = this;
var headers = { 'X-CSRFToken': $.cookie( 'csrftoken' ) },
data = {
face_image: model.get( 'faceImage' ),
face_image: model.get( 'faceImage' )
},
url = _.str.sprintf(
'/verify_student/reverify/%(courseKey)s/%(checkpointName)s/', {
'/verify_student/reverify/%(courseKey)s/%(checkpointName)s/%(location)s/', {
courseKey: model.get('courseKey'),
checkpointName: model.get('checkpointName')
checkpointName: model.get('checkpointName'),
location: model.get('location')
}
);
......@@ -38,8 +40,8 @@ var edx = edx || {};
type: 'POST',
data: data,
headers: headers,
success: function() {
model.trigger( 'sync' );
success: function(response) {
model.trigger( 'sync', response.url);
},
error: function( error ) {
model.trigger( 'error', error );
......
......@@ -28,11 +28,13 @@
this.courseKey = obj.courseKey || null;
this.checkpointName = obj.checkpointName || null;
this.platformName = obj.platformName || null;
this.location = obj.location || null;
this.model = new edx.verify_student.ReverificationModel({
courseKey: this.courseKey,
checkpointName: this.checkpointName
checkpointName: this.checkpointName,
location: this.location
});
this.listenTo( this.model, 'sync', _.bind( this.handleSubmitPhotoSuccess, this ));
......@@ -75,10 +77,10 @@
this.model.save();
},
handleSubmitPhotoSuccess: function() {
handleSubmitPhotoSuccess: function(redirect_url) {
// Eventually this will be a redirect back into the courseware,
// but for now we can return to the student dashboard.
window.location.href = '/dashboard';
window.location.href = redirect_url;
},
handleSubmissionError: function(xhr) {
......
......@@ -46,6 +46,7 @@ checkpoint_name=checkpoint_name)}
data-course-key='${course_key}'
data-checkpoint-name='${checkpoint_name}'
data-platform-name='${platform_name}'
data-location='${location}'
></div>
</section>
</div>
......
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