Changes necessary for Django 1.11 tests to start
- Certificates management commands updates - Moving reverse calls in tests into setUp from class definition - Import shuffling - Consolidating cryptograhpy version to 1.9
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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 <USERNAME> <COURSE_KEY> --mode <MODE> --status <STATUS> --grade <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
|
||||
)
|
||||
|
||||
@@ -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'
|
||||
'<username> 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 <username> 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)
|
||||
)
|
||||
|
||||
@@ -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".')
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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}),
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<block_type>[^/]+)/(?P<uri>.*)$',
|
||||
'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'),
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user