diff --git a/cms/djangoapps/xblock_config/apps.py b/cms/djangoapps/xblock_config/apps.py index d378ee011d..2961140f91 100644 --- a/cms/djangoapps/xblock_config/apps.py +++ b/cms/djangoapps/xblock_config/apps.py @@ -7,7 +7,6 @@ from django.apps import AppConfig import cms.lib.xblock.runtime import xmodule.x_module -from openedx.core.lib.xblock_utils import xblock_local_resource_url class XBlockConfig(AppConfig): @@ -18,6 +17,8 @@ class XBlockConfig(AppConfig): verbose_name = u'XBlock Configuration' def ready(self): + from openedx.core.lib.xblock_utils import xblock_local_resource_url + # In order to allow descriptors to use a handler url, we need to # monkey-patch the x_module library. # TODO: Remove this code when Runtimes are no longer created by modulestores diff --git a/cms/urls.py b/cms/urls.py index 02774e9128..9683b9e67e 100644 --- a/cms/urls.py +++ b/cms/urls.py @@ -5,7 +5,6 @@ from django.contrib.admin import autodiscover as django_autodiscover from django.utils.translation import ugettext_lazy as _ import contentstore.views -import django_cas.views import openedx.core.djangoapps.common_views.xblock import openedx.core.djangoapps.debug.views import openedx.core.djangoapps.external_auth.views @@ -180,6 +179,8 @@ if settings.FEATURES.get('ENABLE_SERVICE_STATUS'): urlpatterns.append(url(r'^status/', include('openedx.core.djangoapps.service_status.urls'))) if settings.FEATURES.get('AUTH_USE_CAS'): + import django_cas.views + urlpatterns += [ url(r'^cas-auth/login/$', openedx.core.djangoapps.external_auth.views.cas_login, name="cas-login"), url(r'^cas-auth/logout/$', django_cas.views.logout, {'next_page': '/'}, name="cas-logout"), diff --git a/lms/djangoapps/certificates/management/commands/create_fake_cert.py b/lms/djangoapps/certificates/management/commands/create_fake_cert.py index b4c9514fef..c501a8e777 100644 --- a/lms/djangoapps/certificates/management/commands/create_fake_cert.py +++ b/lms/djangoapps/certificates/management/commands/create_fake_cert.py @@ -10,11 +10,11 @@ Example usage: """ import logging -from optparse import make_option from django.contrib.auth.models import User -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey +from six import text_type from certificates.models import CertificateStatuses, GeneratedCertificate @@ -24,33 +24,41 @@ LOGGER = logging.getLogger(__name__) class Command(BaseCommand): """Create a fake certificate for a user in a course. """ - USAGE = u'Usage: create_fake_cert --mode --status --grade ' + def add_arguments(self, parser): + parser.add_argument( + 'username', + metavar='USERNAME', + help='Username of the user to create the fake cert for' + ) + parser.add_argument( + 'course_key', + metavar='COURSE_KEY', + help='Course key of the course to grant the cert for' + ) - option_list = BaseCommand.option_list + ( - make_option( + parser.add_argument( '-m', '--mode', metavar='CERT_MODE', dest='cert_mode', default='honor', help='The course mode of the certificate (e.g. "honor", "verified", or "professional")' - ), + ) - make_option( + parser.add_argument( '-s', '--status', metavar='CERT_STATUS', dest='status', default=CertificateStatuses.downloadable, help='The status of the certificate' - ), + ) - make_option( + parser.add_argument( '-g', '--grade', metavar='CERT_GRADE', dest='grade', default='', - help='The grade for the course, as a decimal (e.g. "0.89" for 89%)' - ), - ) + help='The grade for the course, as a decimal (e.g. "0.89" for 89 percent)' + ) def handle(self, *args, **options): """Create a fake certificate for a user. @@ -68,11 +76,8 @@ class Command(BaseCommand): CommandError """ - if len(args) < 2: - raise CommandError(self.USAGE) - - user = User.objects.get(username=args[0]) - course_key = CourseKey.from_string(args[1]) + user = User.objects.get(username=options['username']) + course_key = CourseKey.from_string(options['course_key']) cert_mode = options.get('cert_mode', 'honor') status = options.get('status', CertificateStatuses.downloadable) grade = options.get('grade', '') @@ -97,7 +102,7 @@ class Command(BaseCommand): u"Created certificate for user %s in course %s " u"with mode %s, status %s, " u"and grade %s", - user.id, unicode(course_key), + user.id, text_type(course_key), cert_mode, status, grade ) @@ -106,6 +111,6 @@ class Command(BaseCommand): u"Updated certificate for user %s in course %s " u"with mode %s, status %s, " u"and grade %s", - user.id, unicode(course_key), + user.id, text_type(course_key), cert_mode, status, grade ) diff --git a/lms/djangoapps/certificates/management/commands/regenerate_user.py b/lms/djangoapps/certificates/management/commands/regenerate_user.py index 4d668f1b60..15e500ac59 100644 --- a/lms/djangoapps/certificates/management/commands/regenerate_user.py +++ b/lms/djangoapps/certificates/management/commands/regenerate_user.py @@ -1,12 +1,11 @@ """Django management command to force certificate regeneration for one user""" - import copy import logging -from optparse import make_option from django.contrib.auth.models import User -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey +from six import text_type from badges.events.course_complete import get_completion_badge from badges.utils import badges_enabled @@ -24,39 +23,36 @@ class Command(BaseCommand): help = """Put a request on the queue to recreate the certificate for a particular user in a particular course.""" - option_list = BaseCommand.option_list + ( - make_option('-n', '--noop', - action='store_true', - dest='noop', - default=False, - help="Don't grade or add certificate requests to the queue"), - make_option('--insecure', - action='store_true', - dest='insecure', - default=False, - help="Don't use https for the callback url to the LMS, useful in http test environments"), - make_option('-c', '--course', - metavar='COURSE_ID', - dest='course', - default=False, - help='The course id (e.g., mit/6-002x/circuits-and-electronics) for which the student named in' - ' should be graded'), - make_option('-u', '--user', - metavar='USERNAME', - dest='username', - default=False, - help='The username or email address for whom grading and certification should be requested'), - make_option('-G', '--grade', - metavar='GRADE', - dest='grade_value', - default=None, - help='The grade string, such as "Distinction", which should be passed to the certificate agent'), - make_option('-T', '--template', - metavar='TEMPLATE', - dest='template_file', - default=None, - help='The template file used to render this certificate, like "QMSE01-distinction.pdf"'), - ) + def add_arguments(self, parser): + parser.add_argument('-n', '--noop', + action='store_true', + dest='noop', + help="Don't grade or add certificate requests to the queue") + parser.add_argument('--insecure', + action='store_true', + dest='insecure', + help="Don't use https for the callback url to the LMS, useful in http test environments") + parser.add_argument('-c', '--course', + metavar='COURSE_ID', + dest='course', + required=True, + help='The course id (e.g., mit/6-002x/circuits-and-electronics) for which the student ' + 'named in should be graded') + parser.add_argument('-u', '--user', + metavar='USERNAME', + dest='username', + required=True, + help='The username or email address for whom grading and certification should be requested') + parser.add_argument('-G', '--grade', + metavar='GRADE', + dest='grade_value', + default=None, + help='The grade string, such as "Distinction", which is passed to the certificate agent') + parser.add_argument('-T', '--template', + metavar='TEMPLATE', + dest='template_file', + default=None, + help='The template file used to render this certificate, like "QMSE01-distinction.pdf"') def handle(self, *args, **options): @@ -69,21 +65,14 @@ class Command(BaseCommand): u"Starting to create tasks to regenerate certificates " u"with arguments %s and options %s" ), - unicode(args), - unicode(cleaned_options) + text_type(args), + text_type(cleaned_options) ) - if options['course']: - # try to parse out the course from the serialized form - course_id = CourseKey.from_string(options['course']) - else: - raise CommandError("You must specify a course") - + # try to parse out the course from the serialized form + course_id = CourseKey.from_string(options['course']) user = options['username'] - if not (course_id and user): - raise CommandError('both course id and student username are required') - student = None if '@' in user: student = User.objects.get(email=user, courseenrollment__course_id=course_id) else: @@ -124,7 +113,7 @@ class Command(BaseCommand): u"The new certificate status is '%s'." ), student.id, - unicode(course_id), + text_type(course_id), ret ) @@ -136,7 +125,7 @@ class Command(BaseCommand): u"because the noop flag is set." ), student.id, - unicode(course_id) + text_type(course_id) ) LOGGER.info( @@ -145,5 +134,5 @@ class Command(BaseCommand): u"user %s and course '%s'." ), student.id, - unicode(course_id) + text_type(course_id) ) diff --git a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py index efdbd146ea..421a4b0959 100644 --- a/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py +++ b/lms/djangoapps/certificates/management/commands/resubmit_error_certificates.py @@ -17,11 +17,11 @@ Example usage: """ import logging -from optparse import make_option from django.core.management.base import BaseCommand, CommandError from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey +from six import text_type from certificates import api as certs_api from certificates.models import CertificateStatuses, GeneratedCertificate @@ -33,16 +33,15 @@ LOGGER = logging.getLogger(__name__) class Command(BaseCommand): """Resubmit certificates with error status. """ - option_list = BaseCommand.option_list + ( - make_option( + def add_arguments(self, parser): + parser.add_argument( '-c', '--course', metavar='COURSE_KEY', dest='course_key_list', action='append', default=[], help='Only re-submit certificates for these courses.' - ), - ) + ) def handle(self, *args, **options): """Resubmit certificates with status 'error'. @@ -58,7 +57,7 @@ class Command(BaseCommand): """ only_course_keys = [] - for course_key_str in options.get('course_key_list', []): + for course_key_str in options['course_key_list']: try: only_course_keys.append(CourseKey.from_string(course_key_str)) except InvalidKeyError: @@ -73,7 +72,7 @@ class Command(BaseCommand): ( u'Starting to re-submit certificates with status "error" ' u'in these courses: %s' - ), ", ".join([unicode(key) for key in only_course_keys]) + ), ", ".join([text_type(key) for key in only_course_keys]) ) else: LOGGER.info(u'Starting to re-submit certificates with status "error".') diff --git a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py index ac4ef411c4..64749f19c0 100644 --- a/lms/djangoapps/certificates/management/commands/ungenerated_certs.py +++ b/lms/djangoapps/certificates/management/commands/ungenerated_certs.py @@ -2,14 +2,15 @@ Management command to find all students that need certificates for courses that have finished, and put their cert requests on the queue. """ +from __future__ import print_function import datetime import logging -from optparse import make_option from django.contrib.auth.models import User -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from opaque_keys.edx.keys import CourseKey from pytz import UTC +from six import text_type from certificates.api import generate_user_certificates from certificates.models import CertificateStatuses, certificate_status_for_student @@ -34,42 +35,43 @@ class Command(BaseCommand): queue to be generated. """ - option_list = BaseCommand.option_list + ( - make_option('-n', '--noop', - action='store_true', - dest='noop', - default=False, - help="Don't add certificate requests to the queue"), - make_option('--insecure', - action='store_true', - dest='insecure', - default=False, - help="Don't use https for the callback url to the LMS, useful in http test environments"), - make_option('-c', '--course', - metavar='COURSE_ID', - dest='course', - default=False, - help='Grade and generate certificates ' - 'for a specific course'), - make_option('-f', '--force-gen', - metavar='STATUS', - dest='force', - default=False, - help='Will generate new certificates for only those users ' - 'whose entry in the certificate table matches STATUS. ' - 'STATUS can be generating, unavailable, deleted, error ' - 'or notpassing.'), - ) + def add_arguments(self, parser): + parser.add_argument( + '-n', '--noop', + action='store_true', + dest='noop', + help="Don't add certificate requests to the queue" + ) + parser.add_argument( + '--insecure', + action='store_true', + dest='insecure', + help="Don't use https for the callback url to the LMS, useful in http test environments" + ) + parser.add_argument( + '-c', '--course', + metavar='COURSE_ID', + dest='course', + required=True, + help='Grade and generate certificates for a specific course' + ) + parser.add_argument( + '-f', '--force-gen', + metavar='STATUS', + dest='force', + default=False, + help='Will generate new certificates for only those users whose entry in the certificate table matches ' + 'STATUS. STATUS can be generating, unavailable, deleted, error or notpassing.' + ) def handle(self, *args, **options): - LOGGER.info( ( u"Starting to create tasks for ungenerated certificates " u"with arguments %s and options %s" ), - unicode(args), - unicode(options) + text_type(args), + text_type(options) ) # Will only generate a certificate if the current @@ -82,14 +84,10 @@ class Command(BaseCommand): valid_statuses = [CertificateStatuses.unavailable] # Print update after this many students + status_interval = 500 - STATUS_INTERVAL = 500 - - if options['course']: - course = CourseKey.from_string(options['course']) - ended_courses = [course] - else: - raise CommandError("You must specify a course") + course = CourseKey.from_string(options['course']) + ended_courses = [course] for course_key in ended_courses: # prefetch all chapters/sequentials by saying depth=2 @@ -105,16 +103,15 @@ class Command(BaseCommand): for student in enrolled_students: count += 1 - if count % STATUS_INTERVAL == 0: + if count % status_interval == 0: # Print a status update with an approximation of # how much time is left based on how long the last # interval took diff = datetime.datetime.now(UTC) - start - timeleft = diff * (total - count) / STATUS_INTERVAL + timeleft = diff * (total - count) / status_interval hours, remainder = divmod(timeleft.seconds, 3600) minutes, _seconds = divmod(remainder, 60) - print "{0}/{1} completed ~{2:02}:{3:02}m remaining".format( - count, total, hours, minutes) + print("{0}/{1} completed ~{2:02}:{3:02}m remaining".format(count, total, hours, minutes)) start = datetime.datetime.now(UTC) cert_status = certificate_status_for_student(student, course_key)['status'] @@ -125,7 +122,7 @@ class Command(BaseCommand): ), student.id, cert_status, - unicode(course_key) + text_type(course_key) ) if cert_status in valid_statuses: @@ -147,7 +144,7 @@ class Command(BaseCommand): u"The new certificate status is '%s'." ), student.id, - unicode(course_key), + text_type(course_key), ret ) @@ -159,7 +156,7 @@ class Command(BaseCommand): u"because the noop flag is set." ), student.id, - unicode(course_key) + text_type(course_key) ) else: @@ -170,7 +167,7 @@ class Command(BaseCommand): ), student.id, cert_status, - unicode(valid_statuses) + text_type(valid_statuses) ) LOGGER.info( @@ -178,5 +175,5 @@ class Command(BaseCommand): u"Completed ungenerated certificates command " u"for course '%s'" ), - unicode(course_key) + text_type(course_key) ) diff --git a/lms/djangoapps/certificates/tests/test_cert_management.py b/lms/djangoapps/certificates/tests/test_cert_management.py index c203d2038d..32434ceffd 100644 --- a/lms/djangoapps/certificates/tests/test_cert_management.py +++ b/lms/djangoapps/certificates/tests/test_cert_management.py @@ -1,15 +1,16 @@ """Tests for the resubmit_error_certificates management command. """ import ddt +from django.core.management import call_command from django.core.management.base import CommandError from django.test.utils import override_settings from mock import patch from nose.plugins.attrib import attr from opaque_keys.edx.locator import CourseLocator +from six import text_type from badges.events.course_complete import get_completion_badge from badges.models import BadgeAssertion from badges.tests.factories import BadgeAssertionFactory, CourseCompleteImageConfigurationFactory -from certificates.management.commands import regenerate_user, resubmit_error_certificates, ungenerated_certs from certificates.models import CertificateStatuses, GeneratedCertificate from course_modes.models import CourseMode from lms.djangoapps.grades.tests.utils import mock_passing_grade @@ -23,7 +24,7 @@ class CertificateManagementTest(ModuleStoreTestCase): Base test class for Certificate Management command tests. """ # Override with the command module you wish to test. - command = resubmit_error_certificates + command = 'resubmit_error_certificates' def setUp(self): super(CertificateManagementTest, self).setUp() @@ -53,11 +54,6 @@ class CertificateManagementTest(ModuleStoreTestCase): status=status ) - def _run_command(self, *args, **kwargs): - """Run the management command to generate a fake cert. """ - command = self.command.Command() - return command.handle(*args, **kwargs) - def _assert_cert_status(self, course_key, user, expected_status): """Check the status of a certificate. """ cert = GeneratedCertificate.eligible_certificates.get(user=user, course_id=course_key) @@ -77,7 +73,7 @@ class ResubmitErrorCertificatesTest(CertificateManagementTest): # Re-submit all certificates with status 'error' with check_mongo_calls(1): - self._run_command() + call_command(self.command) # Expect that the certificate was re-submitted self._assert_cert_status(self.courses[0].id, self.user, CertificateStatuses.notpassing) @@ -89,9 +85,9 @@ class ResubmitErrorCertificatesTest(CertificateManagementTest): self._create_cert(self.courses[idx].id, self.user, CertificateStatuses.error) # Re-submit certificates for two of the courses - self._run_command(course_key_list=[ - unicode(self.courses[0].id), - unicode(self.courses[1].id) + call_command(self.command, course_key_list=[ + text_type(self.courses[0].id), + text_type(self.courses[1].id) ]) # Expect that the first two courses have been re-submitted, @@ -115,7 +111,7 @@ class ResubmitErrorCertificatesTest(CertificateManagementTest): self._create_cert(self.courses[1].id, self.user, other_status) # Re-submit certificates for all courses - self._run_command() + call_command(self.command) # Only the certificate with status "error" should have been re-submitted self._assert_cert_status(self.courses[0].id, self.user, CertificateStatuses.notpassing) @@ -123,7 +119,7 @@ class ResubmitErrorCertificatesTest(CertificateManagementTest): def test_resubmit_error_certificate_none_found(self): self._create_cert(self.courses[0].id, self.user, CertificateStatuses.downloadable) - self._run_command() + call_command(self.command) self._assert_cert_status(self.courses[0].id, self.user, CertificateStatuses.downloadable) def test_course_caching(self): @@ -135,17 +131,17 @@ class ResubmitErrorCertificatesTest(CertificateManagementTest): # Verify that we make only one Mongo query # because the course is cached. with check_mongo_calls(1): - self._run_command() + call_command(self.command) def test_invalid_course_key(self): invalid_key = u"invalid/" with self.assertRaisesRegexp(CommandError, invalid_key): - self._run_command(course_key_list=[invalid_key]) + call_command(self.command, course_key_list=[invalid_key]) def test_course_does_not_exist(self): phantom_course = CourseLocator(org='phantom', course='phantom', run='phantom') self._create_cert(phantom_course, self.user, 'error') - self._run_command() + call_command(self.command) # Expect that the certificate was NOT resubmitted # since the course doesn't actually exist. @@ -158,7 +154,7 @@ class RegenerateCertificatesTest(CertificateManagementTest): """ Tests for regenerating certificates. """ - command = regenerate_user + command = 'regenerate_user' def setUp(self): """ @@ -185,10 +181,10 @@ class RegenerateCertificatesTest(CertificateManagementTest): self.assertTrue(BadgeAssertion.objects.filter(user=self.user, badge_class=badge_class)) self.course.issue_badges = issue_badges self.store.update_item(self.course, None) - self._run_command( - username=self.user.email, course=unicode(key), noop=False, insecure=False, template_file=None, - grade_value=None - ) + + args = '-u {} -c {}'.format(self.user.email, text_type(key)) + call_command(self.command, *args.split(' ')) + xqueue.return_value.regen_cert.assert_called_with( self.user, key, @@ -211,10 +207,10 @@ class RegenerateCertificatesTest(CertificateManagementTest): """ key = self.course.location.course_key self._create_cert(key, self.user, CertificateStatuses.downloadable) - self._run_command( - username=self.user.email, course=unicode(key), noop=False, insecure=True, template_file=None, - grade_value=None - ) + + args = '-u {} -c {} --insecure'.format(self.user.email, text_type(key)) + call_command(self.command, *args.split(' ')) + certificate = GeneratedCertificate.eligible_certificates.get( user=self.user, course_id=key @@ -228,7 +224,7 @@ class UngenerateCertificatesTest(CertificateManagementTest): """ Tests for generating certificates. """ - command = ungenerated_certs + command = 'ungenerated_certs' def setUp(self): """ @@ -248,10 +244,11 @@ class UngenerateCertificatesTest(CertificateManagementTest): mock_send_to_queue.return_value = (0, "Successfully queued") key = self.course.location.course_key self._create_cert(key, self.user, CertificateStatuses.unavailable) + with mock_passing_grade(): - self._run_command( - course=unicode(key), noop=False, insecure=True, force=False - ) + args = '-c {} --insecure'.format(text_type(key)) + call_command(self.command, *args.split(' ')) + self.assertTrue(mock_send_to_queue.called) certificate = GeneratedCertificate.eligible_certificates.get( user=self.user, diff --git a/lms/djangoapps/certificates/tests/test_create_fake_cert.py b/lms/djangoapps/certificates/tests/test_create_fake_cert.py index 71b5da394b..502789ac81 100644 --- a/lms/djangoapps/certificates/tests/test_create_fake_cert.py +++ b/lms/djangoapps/certificates/tests/test_create_fake_cert.py @@ -1,10 +1,12 @@ """Tests for the create_fake_certs management command. """ + +from django.core.management import call_command from django.core.management.base import CommandError from django.test import TestCase from nose.plugins.attrib import attr from opaque_keys.edx.locator import CourseLocator +from six import text_type -from certificates.management.commands import create_fake_cert from certificates.models import GeneratedCertificate from student.tests.factories import UserFactory @@ -24,7 +26,7 @@ class CreateFakeCertTest(TestCase): # No existing cert, so create it self._run_command( self.USERNAME, - unicode(self.COURSE_KEY), + text_type(self.COURSE_KEY), cert_mode='verified', grade='0.89' ) @@ -38,17 +40,16 @@ class CreateFakeCertTest(TestCase): # Cert already exists; modify it self._run_command( self.USERNAME, - unicode(self.COURSE_KEY), + text_type(self.COURSE_KEY), cert_mode='honor' ) cert = GeneratedCertificate.eligible_certificates.get(user=self.user, course_id=self.COURSE_KEY) self.assertEqual(cert.mode, 'honor') def test_too_few_args(self): - with self.assertRaisesRegexp(CommandError, 'Usage'): + with self.assertRaisesRegexp(CommandError, 'Error: too few arguments'): self._run_command(self.USERNAME) def _run_command(self, *args, **kwargs): """Run the management command to generate a fake cert. """ - command = create_fake_cert.Command() - return command.handle(*args, **kwargs) + return call_command('create_fake_cert', *args, **kwargs) diff --git a/lms/djangoapps/commerce/api/v0/tests/test_views.py b/lms/djangoapps/commerce/api/v0/tests/test_views.py index 558db9b500..35e9d18ba1 100644 --- a/lms/djangoapps/commerce/api/v0/tests/test_views.py +++ b/lms/djangoapps/commerce/api/v0/tests/test_views.py @@ -8,7 +8,7 @@ import ddt import mock import pytz from django.conf import settings -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.test import TestCase from django.test.utils import override_settings from edx_rest_api_client import exceptions @@ -285,7 +285,7 @@ class BasketOrderViewTests(UserMixin, TestCase): """ Tests for the basket order view. """ view_name = 'commerce_api:v0:baskets:retrieve_order' MOCK_ORDER = {'number': 1} - path = reverse(view_name, kwargs={'basket_id': 1}) + path = reverse_lazy(view_name, kwargs={'basket_id': 1}) def setUp(self): super(BasketOrderViewTests, self).setUp() diff --git a/lms/djangoapps/commerce/api/v1/tests/test_views.py b/lms/djangoapps/commerce/api/v1/tests/test_views.py index f8a32ce962..027a890421 100644 --- a/lms/djangoapps/commerce/api/v1/tests/test_views.py +++ b/lms/djangoapps/commerce/api/v1/tests/test_views.py @@ -7,7 +7,7 @@ import ddt import pytz from django.conf import settings from django.contrib.auth.models import Permission -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.test import TestCase from django.test.utils import override_settings from edx_rest_api_client import exceptions @@ -83,7 +83,7 @@ class CourseApiViewTestMixin(object): class CourseListViewTests(CourseApiViewTestMixin, ModuleStoreTestCase): """ Tests for CourseListView. """ - path = reverse('commerce_api:v1:courses:list') + path = reverse_lazy('commerce_api:v1:courses:list') def test_authentication_required(self): """ Verify only authenticated users can access the view. """ @@ -400,7 +400,7 @@ class OrderViewTests(UserMixin, TestCase): view_name = 'commerce_api:v1:orders:detail' ORDER_NUMBER = 'EDX-100001' MOCK_ORDER = {'number': ORDER_NUMBER} - path = reverse(view_name, kwargs={'number': ORDER_NUMBER}) + path = reverse_lazy(view_name, kwargs={'number': ORDER_NUMBER}) def setUp(self): super(OrderViewTests, self).setUp() diff --git a/lms/djangoapps/courseware/tests/test_i18n.py b/lms/djangoapps/courseware/tests/test_i18n.py index 4281456f65..71e1c8f779 100644 --- a/lms/djangoapps/courseware/tests/test_i18n.py +++ b/lms/djangoapps/courseware/tests/test_i18n.py @@ -7,7 +7,7 @@ import re from django.conf import settings from django.contrib.auth.models import User -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.test import TestCase from django.test.client import Client from django.utils import translation @@ -23,9 +23,9 @@ class BaseI18nTestCase(TestCase): Base utilities for i18n test classes to derive from """ preview_language_url = '/update_lang/' - url = reverse('dashboard') site_lang = settings.LANGUAGE_CODE pwd = 'test_password' + url = reverse_lazy('dashboard') def setUp(self): super(BaseI18nTestCase, self).setUp() @@ -171,7 +171,9 @@ class I18nLangPrefTests(BaseI18nTestCase): self.user_login() def set_lang_preference(self, language): - """Sets the user's language preference, allowing the LangPref middleware to operate to set the preference cookie.""" + """ + Sets the user's language preference, allowing the LangPref middleware to operate to set the preference cookie. + """ response = self.client.patch( reverse('preferences_api', args=[self.user.username]), json.dumps({LANGUAGE_KEY: language}), diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index eca079f730..3cba9f6094 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -13,7 +13,7 @@ from uuid import uuid4 import ddt from django.conf import settings from django.contrib.auth.models import AnonymousUser -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.http import Http404, HttpResponseBadRequest from django.test import TestCase from django.test.client import Client, RequestFactory @@ -983,7 +983,7 @@ class ViewsTestCase(ModuleStoreTestCase): class TestProgramMarketingView(SharedModuleStoreTestCase): """Unit tests for the program marketing page.""" program_uuid = str(uuid4()) - url = reverse('program_marketing_view', kwargs={'program_uuid': program_uuid}) + url = reverse_lazy('program_marketing_view', kwargs={'program_uuid': program_uuid}) @classmethod def setUpClass(cls): diff --git a/lms/djangoapps/learner_dashboard/tests/test_programs.py b/lms/djangoapps/learner_dashboard/tests/test_programs.py index 43c9625cc7..4075dd88c2 100644 --- a/lms/djangoapps/learner_dashboard/tests/test_programs.py +++ b/lms/djangoapps/learner_dashboard/tests/test_programs.py @@ -10,7 +10,7 @@ from uuid import uuid4 import mock from bs4 import BeautifulSoup from django.conf import settings -from django.core.urlresolvers import reverse +from django.core.urlresolvers import reverse, reverse_lazy from django.test import override_settings from openedx.core.djangoapps.catalog.tests.factories import CourseFactory, CourseRunFactory, ProgramFactory @@ -31,7 +31,7 @@ class TestProgramListing(ProgramsApiConfigMixin, SharedModuleStoreTestCase): """Unit tests for the program listing page.""" maxDiff = None password = 'test' - url = reverse('program_listing_view') + url = reverse_lazy('program_listing_view') @classmethod def setUpClass(cls): @@ -176,7 +176,7 @@ class TestProgramDetails(ProgramsApiConfigMixin, CatalogIntegrationMixin, Shared """Unit tests for the program details page.""" program_uuid = str(uuid4()) password = 'test' - url = reverse('program_details_view', kwargs={'program_uuid': program_uuid}) + url = reverse_lazy('program_details_view', kwargs={'program_uuid': program_uuid}) @classmethod def setUpClass(cls): diff --git a/lms/djangoapps/lms_xblock/apps.py b/lms/djangoapps/lms_xblock/apps.py index 2925e86bfc..5d0a392bcb 100644 --- a/lms/djangoapps/lms_xblock/apps.py +++ b/lms/djangoapps/lms_xblock/apps.py @@ -6,7 +6,6 @@ from __future__ import absolute_import from django.apps import AppConfig import xmodule.x_module -from .runtime import handler_url, local_resource_url class LMSXBlockConfig(AppConfig): @@ -17,6 +16,8 @@ class LMSXBlockConfig(AppConfig): verbose_name = u'LMS XBlock' def ready(self): + from .runtime import handler_url, local_resource_url + # In order to allow modules to use a handler url, we need to # monkey-patch the x_module library. # TODO: Remove this code when Runtimes are no longer created by modulestores diff --git a/lms/urls.py b/lms/urls.py index 55c262eb77..ef364b76a0 100644 --- a/lms/urls.py +++ b/lms/urls.py @@ -18,7 +18,6 @@ from courseware.views import views as courseware_views from courseware.views.index import CoursewareIndex from courseware.views.views import CourseTabView, EnrollStaffView, StaticCourseTabView from debug import views as debug_views -from django_cas import views as django_cas_views from django_comment_common.models import ForumsConfig from django_openid_auth import views as django_openid_auth_views from lms.djangoapps.discussion import views as discussion_views @@ -40,6 +39,7 @@ from openedx.core.djangoapps.programs.models import ProgramsApiConfig from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.verified_track_content import views as verified_track_content_views +from openedx.core.djangoapps.common_views.xblock import xblock_resource from openedx.features.enterprise_support.api import enterprise_enabled from ratelimitbackend import admin from static_template_view import views as static_template_view_views @@ -290,7 +290,7 @@ urlpatterns += [ # xblock Resource URL url( r'xblock/resource/(?P[^/]+)/(?P.*)$', - 'openedx.core.djangoapps.common_views.xblock.xblock_resource', + xblock_resource, name='xblock_resource_url', ), @@ -825,6 +825,8 @@ if settings.FEATURES.get('AUTH_USE_SHIB'): ] if settings.FEATURES.get('AUTH_USE_CAS'): + from django_cas import views as django_cas_views + urlpatterns += [ url(r'^cas-auth/login/$', external_auth_views.cas_login, name='cas-login'), url(r'^cas-auth/logout/$', django_cas_views.logout, {'next_page': '/'}, name='cas-logout'), diff --git a/openedx/core/djangoapps/coursegraph/tasks.py b/openedx/core/djangoapps/coursegraph/tasks.py index 137b75646a..d010eee1a9 100644 --- a/openedx/core/djangoapps/coursegraph/tasks.py +++ b/openedx/core/djangoapps/coursegraph/tasks.py @@ -13,7 +13,6 @@ from opaque_keys.edx.keys import CourseKey from py2neo import Graph, Node, Relationship, authenticate, NodeSelector from py2neo.compat import integer, string, unicode as neo4j_unicode from request_cache.middleware import RequestCache -from xmodule.modulestore.store_utilities import DETACHED_XBLOCK_TYPES log = logging.getLogger(__name__) @@ -37,6 +36,8 @@ def serialize_item(item): block_type: the name of the XBlock's type (i.e. 'course' or 'problem') """ + from xmodule.modulestore.store_utilities import DETACHED_XBLOCK_TYPES + # convert all fields to a dict and filter out parent and children field fields = dict( (field, field_value.read_from(item)) diff --git a/openedx/features/learner_profile/urls.py b/openedx/features/learner_profile/urls.py index 775d6ded1f..31bc859b87 100644 --- a/openedx/features/learner_profile/urls.py +++ b/openedx/features/learner_profile/urls.py @@ -6,13 +6,14 @@ from django.conf import settings from django.conf.urls import url from views.learner_achievements import LearnerAchievementsFragmentView +from openedx.features.learner_profile.views.learner_profile import learner_profile urlpatterns = [ url( r'^{username_pattern}$'.format( username_pattern=settings.USERNAME_PATTERN, ), - 'openedx.features.learner_profile.views.learner_profile.learner_profile', + learner_profile, name='learner_profile', ), url( diff --git a/requirements/edx/base.txt b/requirements/edx/base.txt index 70443048cd..2ff772bca2 100644 --- a/requirements/edx/base.txt +++ b/requirements/edx/base.txt @@ -11,7 +11,7 @@ bleach==1.4 html5lib==0.999 boto==2.39.0 celery==3.1.18 -cryptography==1.5.3 +cryptography==1.9 cssselect==0.9.1 dealer==2.0.4 defusedxml==0.4.1