Merge pull request #8467 from edx/release-2015-06-10-conflict
Release 2015 06 10 conflict
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
Tests for user enrollment.
|
||||
"""
|
||||
import json
|
||||
import itertools
|
||||
import unittest
|
||||
import datetime
|
||||
|
||||
@@ -91,11 +92,11 @@ class EnrollmentTestMixin(object):
|
||||
|
||||
return response
|
||||
|
||||
def assert_enrollment_activation(self, expected_activation, expected_mode=CourseMode.VERIFIED):
|
||||
def assert_enrollment_activation(self, expected_activation, expected_mode):
|
||||
"""Change an enrollment's activation and verify its activation and mode are as expected."""
|
||||
self.assert_enrollment_status(
|
||||
as_server=True,
|
||||
mode=None,
|
||||
mode=expected_mode,
|
||||
is_active=expected_activation,
|
||||
expected_status=status.HTTP_200_OK
|
||||
)
|
||||
@@ -637,6 +638,58 @@ class EnrollmentTest(EnrollmentTestMixin, ModuleStoreTestCase, APITestCase):
|
||||
self.assertTrue(is_active)
|
||||
self.assertEqual(course_mode, CourseMode.HONOR)
|
||||
|
||||
@ddt.data(*itertools.product(
|
||||
(CourseMode.HONOR, CourseMode.VERIFIED),
|
||||
(CourseMode.HONOR, CourseMode.VERIFIED),
|
||||
(True, False),
|
||||
(True, False),
|
||||
))
|
||||
@ddt.unpack
|
||||
def test_change_mode_from_server(self, old_mode, new_mode, old_is_active, new_is_active):
|
||||
"""
|
||||
Server-to-server calls should be allowed to change the mode of any
|
||||
enrollment, as long as the enrollment is not being deactivated during
|
||||
the same call (this is assumed to be an error on the client's side).
|
||||
"""
|
||||
for mode in [CourseMode.HONOR, CourseMode.VERIFIED]:
|
||||
CourseModeFactory.create(
|
||||
course_id=self.course.id,
|
||||
mode_slug=mode,
|
||||
mode_display_name=mode,
|
||||
)
|
||||
|
||||
# Set up the initial enrollment
|
||||
self.assert_enrollment_status(as_server=True, mode=old_mode, is_active=old_is_active)
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
self.assertEqual(is_active, old_is_active)
|
||||
self.assertEqual(course_mode, old_mode)
|
||||
|
||||
expected_status = status.HTTP_400_BAD_REQUEST if (
|
||||
old_mode != new_mode and
|
||||
old_is_active != new_is_active and
|
||||
not new_is_active
|
||||
) else status.HTTP_200_OK
|
||||
|
||||
# simulate the server-server api call under test
|
||||
response = self.assert_enrollment_status(
|
||||
as_server=True,
|
||||
mode=new_mode,
|
||||
is_active=new_is_active,
|
||||
expected_status=expected_status,
|
||||
)
|
||||
|
||||
course_mode, is_active = CourseEnrollment.enrollment_mode_for_user(self.user, self.course.id)
|
||||
if expected_status == status.HTTP_400_BAD_REQUEST:
|
||||
# nothing should have changed
|
||||
self.assertEqual(is_active, old_is_active)
|
||||
self.assertEqual(course_mode, old_mode)
|
||||
# error message should contain specific text. Otto checks for this text in the message.
|
||||
self.assertRegexpMatches(json.loads(response.content)['message'], 'Enrollment mode mismatch')
|
||||
else:
|
||||
# call should have succeeded
|
||||
self.assertEqual(is_active, new_is_active)
|
||||
self.assertEqual(course_mode, new_mode)
|
||||
|
||||
def test_change_mode_invalid_user(self):
|
||||
"""
|
||||
Attempts to change an enrollment for a non-existent user should result in an HTTP 404 for non-server users,
|
||||
|
||||
@@ -3,6 +3,8 @@ The Enrollment API Views should be simple, lean HTTP endpoints for API access. T
|
||||
consist primarily of authentication, request validation, and serialization.
|
||||
|
||||
"""
|
||||
import logging
|
||||
|
||||
from ipware.ip import get_ip
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.utils.decorators import method_decorator
|
||||
@@ -31,6 +33,9 @@ from enrollment.errors import (
|
||||
from student.models import User
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class EnrollmentCrossDomainSessionAuth(SessionAuthenticationAllowInactiveUser, SessionAuthenticationCrossDomainCsrf):
|
||||
"""Session authentication that allows inactive users and cross-domain requests. """
|
||||
pass
|
||||
@@ -429,7 +434,18 @@ class EnrollmentListView(APIView, ApiKeyPermissionMixIn):
|
||||
)
|
||||
|
||||
enrollment = api.get_enrollment(username, unicode(course_id))
|
||||
if has_api_key_permissions and enrollment and enrollment['mode'] != mode:
|
||||
mode_changed = enrollment and mode is not None and enrollment['mode'] != mode
|
||||
active_changed = enrollment and is_active is not None and enrollment['is_active'] != is_active
|
||||
if has_api_key_permissions and (mode_changed or active_changed):
|
||||
if mode_changed and active_changed and not is_active:
|
||||
# if the requester wanted to deactivate but specified the wrong mode, fail
|
||||
# the request (on the assumption that the requester had outdated information
|
||||
# about the currently active enrollment).
|
||||
msg = u"Enrollment mode mismatch: active mode={}, requested mode={}. Won't deactivate.".format(
|
||||
enrollment["mode"], mode
|
||||
)
|
||||
log.warning(msg)
|
||||
return Response(status=status.HTTP_400_BAD_REQUEST, data={"message": msg})
|
||||
response = api.update_enrollment(username, unicode(course_id), mode=mode, is_active=is_active)
|
||||
else:
|
||||
# Will reactivate inactive enrollments.
|
||||
|
||||
@@ -522,12 +522,9 @@ function (VideoPlayer, i18n) {
|
||||
|
||||
this.youtubeXhr
|
||||
.always(function (json, status) {
|
||||
var err = $.isPlainObject(json.error) ||
|
||||
(
|
||||
status !== 'success' &&
|
||||
status !== 'notmodified'
|
||||
);
|
||||
if (err) {
|
||||
// It will work for both if statusCode is 200 or 410.
|
||||
var didSucceed = (json.error && json.error.code === 410) || status === 'success' || status === 'notmodified';
|
||||
if (!didSucceed) {
|
||||
console.log(
|
||||
'[Video info]: YouTube returned an error for ' +
|
||||
'video with id "' + id + '".'
|
||||
|
||||
@@ -94,7 +94,32 @@ def save_subs_to_store(subs, subs_id, item, language='en'):
|
||||
return save_to_store(filedata, filename, 'application/json', item.location)
|
||||
|
||||
|
||||
def get_transcripts_from_youtube(youtube_id, settings, i18n):
|
||||
def youtube_video_transcript_name(youtube_text_api):
|
||||
"""
|
||||
Get the transcript name from available transcripts of video
|
||||
with respect to language from youtube server
|
||||
"""
|
||||
# pylint: disable=no-member
|
||||
utf8_parser = etree.XMLParser(encoding='utf-8')
|
||||
|
||||
transcripts_param = {'type': 'list', 'v': youtube_text_api['params']['v']}
|
||||
lang = youtube_text_api['params']['lang']
|
||||
# get list of transcripts of specific video
|
||||
# url-form
|
||||
# http://video.google.com/timedtext?type=list&v={VideoId}
|
||||
youtube_response = requests.get('http://' + youtube_text_api['url'], params=transcripts_param)
|
||||
if youtube_response.status_code == 200 and youtube_response.text:
|
||||
# pylint: disable=no-member
|
||||
youtube_data = etree.fromstring(youtube_response.content, parser=utf8_parser)
|
||||
# iterate all transcripts information from youtube server
|
||||
for element in youtube_data:
|
||||
# search specific language code such as 'en' in transcripts info list
|
||||
if element.tag == 'track' and element.get('lang_code', '') == lang:
|
||||
return element.get('name')
|
||||
return None
|
||||
|
||||
|
||||
def get_transcripts_from_youtube(youtube_id, settings, i18n, youtube_transcript_name=''):
|
||||
"""
|
||||
Gets transcripts from youtube for youtube_id.
|
||||
|
||||
@@ -109,6 +134,12 @@ def get_transcripts_from_youtube(youtube_id, settings, i18n):
|
||||
|
||||
youtube_text_api = copy.deepcopy(settings.YOUTUBE['TEXT_API'])
|
||||
youtube_text_api['params']['v'] = youtube_id
|
||||
# if the transcript name is not empty on youtube server we have to pass
|
||||
# name param in url in order to get transcript
|
||||
# example http://video.google.com/timedtext?lang=en&v={VideoId}&name={transcript_name}
|
||||
youtube_transcript_name = youtube_video_transcript_name(youtube_text_api)
|
||||
if youtube_transcript_name:
|
||||
youtube_text_api['params']['name'] = youtube_transcript_name
|
||||
data = requests.get('http://' + youtube_text_api['url'], params=youtube_text_api['params'])
|
||||
|
||||
if data.status_code != 200 or not data.text:
|
||||
|
||||
Reference in New Issue
Block a user