Ran pyupgrade on lms/djangoapps
Ran pyupgrade on lms/djangoapps/lms_xblock Ran pyupgrade on lms/djangoapps/lti_provider
This commit is contained in:
@@ -12,8 +12,8 @@ class LMSXBlockConfig(AppConfig):
|
||||
"""
|
||||
Default configuration for the "lms.djangoapps.lms_xblock" Django application.
|
||||
"""
|
||||
name = u'lms.djangoapps.lms_xblock'
|
||||
verbose_name = u'LMS XBlock'
|
||||
name = 'lms.djangoapps.lms_xblock'
|
||||
verbose_name = 'LMS XBlock'
|
||||
|
||||
def ready(self):
|
||||
from .runtime import handler_url, local_resource_url
|
||||
|
||||
@@ -24,7 +24,7 @@ class LmsFieldData(SplitFieldData):
|
||||
self._authored_data = authored_data
|
||||
self._student_data = student_data
|
||||
|
||||
super(LmsFieldData, self).__init__({ # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__({
|
||||
Scope.content: authored_data,
|
||||
Scope.settings: authored_data,
|
||||
Scope.parent: authored_data,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
@@ -19,7 +16,7 @@ class Migration(migrations.Migration):
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('change_date', models.DateTimeField(auto_now_add=True, verbose_name='Change date')),
|
||||
('enabled', models.BooleanField(default=False, verbose_name='Enabled')),
|
||||
('disabled_blocks', models.TextField(default=u'about course_info static_tab', help_text=u'Space-separated list of XBlocks on which XBlockAsides should never render.')),
|
||||
('disabled_blocks', models.TextField(default='about course_info static_tab', help_text='Space-separated list of XBlocks on which XBlockAsides should never render.')),
|
||||
('changed_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, editable=False, to=settings.AUTH_USER_MODEL, null=True, verbose_name='Changed by')),
|
||||
],
|
||||
options={
|
||||
|
||||
@@ -5,7 +5,6 @@ Namespace that defines fields common to all blocks used in the LMS
|
||||
#from django.utils.translation import ugettext_noop as _
|
||||
|
||||
|
||||
import six
|
||||
from lazy import lazy
|
||||
from xblock.core import XBlock, XBlockMixin
|
||||
from xblock.exceptions import JsonHandlerError
|
||||
@@ -21,16 +20,16 @@ from xmodule.partitions.partitions import NoSuchUserPartitionError, NoSuchUserPa
|
||||
_ = lambda text: text
|
||||
|
||||
INVALID_USER_PARTITION_VALIDATION_COMPONENT = _(
|
||||
u"This component's access settings refer to deleted or invalid group configurations."
|
||||
"This component's access settings refer to deleted or invalid group configurations."
|
||||
)
|
||||
INVALID_USER_PARTITION_VALIDATION_UNIT = _(
|
||||
u"This unit's access settings refer to deleted or invalid group configurations."
|
||||
"This unit's access settings refer to deleted or invalid group configurations."
|
||||
)
|
||||
INVALID_USER_PARTITION_GROUP_VALIDATION_COMPONENT = _(
|
||||
u"This component's access settings refer to deleted or invalid groups."
|
||||
"This component's access settings refer to deleted or invalid groups."
|
||||
)
|
||||
INVALID_USER_PARTITION_GROUP_VALIDATION_UNIT = _(u"This unit's access settings refer to deleted or invalid groups.")
|
||||
NONSENSICAL_ACCESS_RESTRICTION = _(u"This component's access settings contradict its parent's access settings.")
|
||||
INVALID_USER_PARTITION_GROUP_VALIDATION_UNIT = _("This unit's access settings refer to deleted or invalid groups.")
|
||||
NONSENSICAL_ACCESS_RESTRICTION = _("This component's access settings contradict its parent's access settings.")
|
||||
|
||||
|
||||
class GroupAccessDict(Dict):
|
||||
@@ -43,7 +42,7 @@ class GroupAccessDict(Dict):
|
||||
|
||||
def to_json(self, value):
|
||||
if value is not None:
|
||||
return {six.text_type(k): value[k] for k in value}
|
||||
return {str(k): value[k] for k in value}
|
||||
|
||||
|
||||
@XBlock.needs('partitions')
|
||||
@@ -158,7 +157,7 @@ class LmsBlockMixin(XBlockMixin):
|
||||
if user_partition.id == user_partition_id:
|
||||
return user_partition
|
||||
|
||||
raise NoSuchUserPartitionError(u"could not find a UserPartition with ID [{}]".format(user_partition_id))
|
||||
raise NoSuchUserPartitionError(f"could not find a UserPartition with ID [{user_partition_id}]")
|
||||
|
||||
def _has_nonsensical_access_settings(self):
|
||||
"""
|
||||
@@ -185,7 +184,7 @@ class LmsBlockMixin(XBlockMixin):
|
||||
parent_group_access = parent.group_access
|
||||
component_group_access = self.group_access
|
||||
|
||||
for user_partition_id, parent_group_ids in six.iteritems(parent_group_access):
|
||||
for user_partition_id, parent_group_ids in parent_group_access.items():
|
||||
component_group_ids = component_group_access.get(user_partition_id) # pylint: disable=no-member
|
||||
if component_group_ids:
|
||||
return parent_group_ids and not set(component_group_ids).issubset(set(parent_group_ids))
|
||||
@@ -198,12 +197,12 @@ class LmsBlockMixin(XBlockMixin):
|
||||
Validates the state of this xblock instance.
|
||||
"""
|
||||
_ = self.runtime.service(self, "i18n").ugettext
|
||||
validation = super(LmsBlockMixin, self).validate() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
validation = super().validate()
|
||||
has_invalid_user_partitions = False
|
||||
has_invalid_groups = False
|
||||
block_is_unit = is_unit(self)
|
||||
|
||||
for user_partition_id, group_ids in six.iteritems(self.group_access):
|
||||
for user_partition_id, group_ids in self.group_access.items(): # lint-amnesty, pylint:disable=no-member
|
||||
try:
|
||||
user_partition = self._get_user_partition(user_partition_id)
|
||||
except NoSuchUserPartitionError:
|
||||
@@ -254,10 +253,10 @@ class LmsBlockMixin(XBlockMixin):
|
||||
"""
|
||||
completion_service = self.runtime.service(self, 'completion')
|
||||
if completion_service is None: # lint-amnesty, pylint: disable=no-else-raise
|
||||
raise JsonHandlerError(500, u"No completion service found")
|
||||
raise JsonHandlerError(500, "No completion service found")
|
||||
elif not completion_service.completion_tracking_enabled():
|
||||
raise JsonHandlerError(404, u"Completion tracking is not enabled and API calls are unexpected")
|
||||
raise JsonHandlerError(404, "Completion tracking is not enabled and API calls are unexpected")
|
||||
if not completion_service.can_mark_block_complete_on_view(self):
|
||||
raise JsonHandlerError(400, u"Block not configured for completion on view.")
|
||||
raise JsonHandlerError(400, "Block not configured for completion on view.")
|
||||
self.runtime.publish(self, "completion", data)
|
||||
return {'result': 'ok'}
|
||||
|
||||
@@ -23,8 +23,8 @@ class XBlockAsidesConfig(ConfigurationModel):
|
||||
app_label = "lms_xblock"
|
||||
|
||||
disabled_blocks = TextField(
|
||||
default=u"about course_info static_tab",
|
||||
help_text=u"Space-separated list of XBlocks on which XBlockAsides should never render."
|
||||
default="about course_info static_tab",
|
||||
help_text="Space-separated list of XBlocks on which XBlockAsides should never render."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -3,7 +3,6 @@ Module implementing `xblock.runtime.Runtime` functionality for the LMS
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
import xblock.reference.plugins
|
||||
from completion.services import CompletionService
|
||||
from django.conf import settings
|
||||
@@ -46,7 +45,7 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
|
||||
# to ask for handler URLs without a student context.
|
||||
func = getattr(block.__class__, handler_name, None)
|
||||
if not func:
|
||||
raise ValueError(u"{!r} is not a function name".format(handler_name))
|
||||
raise ValueError(f"{handler_name!r} is not a function name")
|
||||
|
||||
# Is the following necessary? ProxyAttribute causes an UndefinedContext error
|
||||
# if trying this without the module system.
|
||||
@@ -58,8 +57,8 @@ def handler_url(block, handler_name, suffix='', query='', thirdparty=False):
|
||||
view_name = 'xblock_handler_noauth'
|
||||
|
||||
url = reverse(view_name, kwargs={
|
||||
'course_id': six.text_type(block.location.course_key),
|
||||
'usage_id': quote_slashes(six.text_type(block.scope_ids.usage_id)),
|
||||
'course_id': str(block.location.course_key),
|
||||
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'handler': handler_name,
|
||||
'suffix': suffix,
|
||||
})
|
||||
@@ -91,7 +90,7 @@ def local_resource_url(block, uri):
|
||||
return xblock_local_resource_url(block, uri)
|
||||
|
||||
|
||||
class UserTagsService(object):
|
||||
class UserTagsService:
|
||||
"""
|
||||
A runtime class that provides an interface to the user service. It handles filling in
|
||||
the current course id and current user.
|
||||
@@ -115,7 +114,7 @@ class UserTagsService(object):
|
||||
key: the key for the value we want
|
||||
"""
|
||||
if scope != user_course_tag_api.COURSE_SCOPE:
|
||||
raise ValueError(u"unexpected scope {0}".format(scope))
|
||||
raise ValueError(f"unexpected scope {scope}")
|
||||
|
||||
return user_course_tag_api.get_course_tag(
|
||||
self._get_current_user(),
|
||||
@@ -131,7 +130,7 @@ class UserTagsService(object):
|
||||
value: the value to set
|
||||
"""
|
||||
if scope != user_course_tag_api.COURSE_SCOPE:
|
||||
raise ValueError(u"unexpected scope {0}".format(scope))
|
||||
raise ValueError(f"unexpected scope {scope}")
|
||||
|
||||
return user_course_tag_api.set_course_tag(
|
||||
self._get_current_user(),
|
||||
@@ -166,7 +165,7 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
|
||||
services['teams'] = TeamsService()
|
||||
services['teams_configuration'] = TeamsConfigurationService()
|
||||
services['call_to_action'] = CallToActionService()
|
||||
super(LmsModuleSystem, self).__init__(**kwargs) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def handler_url(self, *args, **kwargs): # lint-amnesty, pylint: disable=signature-differs
|
||||
"""
|
||||
@@ -205,8 +204,8 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
|
||||
|
||||
runtime_class = 'LmsRuntime'
|
||||
extra_data = {
|
||||
'block-id': quote_slashes(six.text_type(block.scope_ids.usage_id)),
|
||||
'course-id': quote_slashes(six.text_type(block.course_id)),
|
||||
'block-id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'course-id': quote_slashes(str(block.course_id)),
|
||||
'url-selector': 'asideBaseUrl',
|
||||
'runtime-class': runtime_class,
|
||||
}
|
||||
@@ -219,7 +218,7 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
|
||||
view,
|
||||
frag,
|
||||
context,
|
||||
usage_id_serializer=six.text_type,
|
||||
usage_id_serializer=str,
|
||||
request_token=self.request_token,
|
||||
extra_data=extra_data,
|
||||
)
|
||||
@@ -244,6 +243,6 @@ class LmsModuleSystem(ModuleSystem): # pylint: disable=abstract-method
|
||||
# (see https://openedx.atlassian.net/browse/TE-811)
|
||||
return [
|
||||
aside_type
|
||||
for aside_type in super(LmsModuleSystem, self).applicable_aside_types(block) # lint-amnesty, pylint: disable=super-with-arguments
|
||||
for aside_type in super().applicable_aside_types(block)
|
||||
if aside_type != 'acid_aside'
|
||||
]
|
||||
|
||||
@@ -2,21 +2,23 @@
|
||||
Tests of the LMS XBlock Runtime and associated utilities
|
||||
"""
|
||||
|
||||
|
||||
from unittest.mock import Mock, patch
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import pytest
|
||||
from ddt import data, ddt
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from mock import Mock, patch
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from opaque_keys.edx.locations import BlockUsageLocator, CourseLocator
|
||||
from six.moves.urllib.parse import urlparse
|
||||
from xblock.exceptions import NoSuchServiceError
|
||||
from xblock.fields import ScopeIds
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.badges.tests.factories import BadgeClassFactory
|
||||
from lms.djangoapps.badges.tests.test_models import get_image
|
||||
from lms.djangoapps.lms_xblock.runtime import LmsModuleSystem
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.django import ModuleI18nService
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
@@ -54,7 +56,7 @@ class TestHandlerUrl(TestCase):
|
||||
"""Test the LMS handler_url"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestHandlerUrl, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.block = BlockMock(name='block', scope_ids=ScopeIds(None, None, None, 'dummy'))
|
||||
self.course_key = CourseLocator("org", "course", "run")
|
||||
self.runtime = LmsModuleSystem(
|
||||
@@ -119,7 +121,7 @@ class TestUserServiceAPI(TestCase):
|
||||
"""Test the user service interface"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestUserServiceAPI, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course_id = CourseLocator("org", "course", "run")
|
||||
self.user = UserFactory.create()
|
||||
|
||||
@@ -169,7 +171,7 @@ class TestBadgingService(ModuleStoreTestCase):
|
||||
"""Test the badging service interface"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestBadgingService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course_id = CourseKey.from_string('course-v1:org+course+run')
|
||||
|
||||
self.mock_block = Mock()
|
||||
@@ -235,7 +237,7 @@ class TestI18nService(ModuleStoreTestCase):
|
||||
|
||||
def setUp(self):
|
||||
""" Setting up tests """
|
||||
super(TestI18nService, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.test_language = 'dummy language'
|
||||
self.runtime = LmsModuleSystem(
|
||||
|
||||
@@ -5,7 +5,6 @@ Management command to resend all lti scores for the requested course.
|
||||
|
||||
import textwrap
|
||||
|
||||
import six
|
||||
from django.core.management import BaseCommand
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
@@ -29,11 +28,11 @@ class Command(BaseCommand):
|
||||
help = textwrap.dedent(__doc__)
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(u'course_keys', type=CourseKey.from_string, nargs='*')
|
||||
parser.add_argument('course_keys', type=CourseKey.from_string, nargs='*')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options[u'course_keys']:
|
||||
for course_key in options[u'course_keys']:
|
||||
if options['course_keys']:
|
||||
for course_key in options['course_keys']:
|
||||
for assignment in self._iter_course_assignments(course_key):
|
||||
self._send_score(assignment)
|
||||
else:
|
||||
@@ -46,7 +45,7 @@ class Command(BaseCommand):
|
||||
"""
|
||||
tasks.send_composite_outcome.delay(
|
||||
assignment.user_id,
|
||||
six.text_type(assignment.course_key),
|
||||
str(assignment.course_key),
|
||||
assignment.id,
|
||||
assignment.version_number,
|
||||
)
|
||||
|
||||
@@ -3,14 +3,14 @@ Test lti_provider management commands.
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import TestCase
|
||||
from mock import patch
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.lti_provider.management.commands import resend_lti_scores
|
||||
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.utils import TEST_DATA_DIR
|
||||
from xmodule.modulestore.xml_importer import import_course_from_xml
|
||||
@@ -34,7 +34,7 @@ class CommandArgsTestCase(TestCase):
|
||||
assert len(args.course_keys) == 2
|
||||
key = args.course_keys[0]
|
||||
assert isinstance(key, CourseKey)
|
||||
assert six.text_type(key) == 'course-v1:edX+test_course+2525_fall'
|
||||
assert str(key) == 'course-v1:edX+test_course+2525_fall'
|
||||
|
||||
def test_no_course_keys(self):
|
||||
parser = self._get_arg_parser()
|
||||
@@ -49,25 +49,25 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(CommandExecutionTestCase, cls).setUpClass()
|
||||
cls.course_key = cls.store.make_course_key(u'edX', u'lti_provider', u'3000')
|
||||
super().setUpClass()
|
||||
cls.course_key = cls.store.make_course_key('edX', 'lti_provider', '3000')
|
||||
import_course_from_xml(
|
||||
cls.store,
|
||||
u'test_user',
|
||||
'test_user',
|
||||
TEST_DATA_DIR,
|
||||
source_dirs=[u'simple'],
|
||||
source_dirs=['simple'],
|
||||
static_content_store=None,
|
||||
target_id=cls.course_key,
|
||||
raise_on_failure=True,
|
||||
create_if_not_present=True,
|
||||
)
|
||||
cls.lti_block = u'block-v1:edX+lti_provider+3000+type@chapter+block@chapter_2'
|
||||
cls.lti_block = 'block-v1:edX+lti_provider+3000+type@chapter+block@chapter_2'
|
||||
|
||||
def setUp(self):
|
||||
super(CommandExecutionTestCase, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.user = UserFactory()
|
||||
self.user2 = UserFactory(username=u'anotheruser')
|
||||
self.client.login(username=self.user.username, password=u'test')
|
||||
self.user2 = UserFactory(username='anotheruser')
|
||||
self.client.login(username=self.user.username, password='test')
|
||||
|
||||
def _configure_lti(self, usage_key):
|
||||
"""
|
||||
@@ -76,21 +76,21 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
|
||||
consumer = LtiConsumer.objects.create()
|
||||
outcome_service = OutcomeService.objects.create(
|
||||
lti_consumer=consumer,
|
||||
lis_outcome_service_url=u'https://lol.tools'
|
||||
lis_outcome_service_url='https://lol.tools'
|
||||
)
|
||||
GradedAssignment.objects.create(
|
||||
user=self.user,
|
||||
course_key=self.course_key,
|
||||
usage_key=usage_key,
|
||||
outcome_service=outcome_service,
|
||||
lis_result_sourcedid=u'abc',
|
||||
lis_result_sourcedid='abc',
|
||||
)
|
||||
GradedAssignment.objects.create(
|
||||
user=self.user2,
|
||||
course_key=self.course_key,
|
||||
usage_key=usage_key,
|
||||
outcome_service=outcome_service,
|
||||
lis_result_sourcedid=u'xyz',
|
||||
lis_result_sourcedid='xyz',
|
||||
)
|
||||
|
||||
def _scores_sent_with_args(self, *args, **kwargs):
|
||||
@@ -111,5 +111,5 @@ class CommandExecutionTestCase(SharedModuleStoreTestCase):
|
||||
assert self._scores_sent_with_args(course_keys=[self.course_key])
|
||||
|
||||
def test_command_with_wrong_course_key(self):
|
||||
fake_course_key = self.store.make_course_key(u'not', u'the', u'course')
|
||||
fake_course_key = self.store.make_course_key('not', 'the', 'course')
|
||||
assert not self._scores_sent_with_args(course_keys=[fake_course_key])
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openedx.core.lib.hash_utils import create_hash256, short_token
|
||||
|
||||
from django.conf import settings
|
||||
@@ -63,10 +61,10 @@ class Migration(migrations.Migration):
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='ltiuser',
|
||||
unique_together=set([('lti_consumer', 'lti_user_id')]),
|
||||
unique_together={('lti_consumer', 'lti_user_id')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='gradedassignment',
|
||||
unique_together=set([('outcome_service', 'lis_result_sourcedid')]),
|
||||
unique_together={('outcome_service', 'lis_result_sourcedid')},
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from openedx.core.lib.hash_utils import short_token
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
import openedx.core.djangolib.fields
|
||||
|
||||
@@ -125,7 +125,7 @@ class GradedAssignment(models.Model):
|
||||
lis_result_sourcedid = models.CharField(max_length=255, db_index=True)
|
||||
version_number = models.IntegerField(default=0)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
unique_together = ('outcome_service', 'lis_result_sourcedid')
|
||||
|
||||
|
||||
@@ -142,5 +142,5 @@ class LtiUser(models.Model):
|
||||
lti_user_id = models.CharField(max_length=255)
|
||||
edx_user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
|
||||
class Meta(object):
|
||||
class Meta:
|
||||
unique_together = ('lti_consumer', 'lti_user_id')
|
||||
|
||||
@@ -38,9 +38,9 @@ def store_outcome_parameters(request_params, user, lti_consumer):
|
||||
# to figure out the result service URL. As it stands, though, this
|
||||
# is a badly-formed LTI request
|
||||
log.warning(
|
||||
u"Outcome Service: lis_outcome_service_url parameter missing "
|
||||
u"from scored assignment; we will be unable to return a score. "
|
||||
u"Request parameters: %s",
|
||||
"Outcome Service: lis_outcome_service_url parameter missing "
|
||||
"from scored assignment; we will be unable to return a score. "
|
||||
"Request parameters: %s",
|
||||
request_params
|
||||
)
|
||||
return
|
||||
@@ -141,8 +141,8 @@ def send_score_update(assignment, score):
|
||||
# necessary.
|
||||
if not (response and check_replace_result_response(response)):
|
||||
log.error(
|
||||
u"Outcome Service: Failed to update score on LTI consumer. "
|
||||
u"User: %s, course: %s, usage: %s, score: %s, status: %s, body: %s",
|
||||
"Outcome Service: Failed to update score on LTI consumer. "
|
||||
"User: %s, course: %s, usage: %s, score: %s, status: %s, body: %s",
|
||||
assignment.user,
|
||||
assignment.course_key,
|
||||
assignment.usage_key,
|
||||
@@ -192,7 +192,7 @@ def check_replace_result_response(response):
|
||||
# Pylint doesn't recognize members in the LXML module
|
||||
if response.status_code != 200:
|
||||
log.error(
|
||||
u"Outcome service response: Unexpected status code %s",
|
||||
"Outcome service response: Unexpected status code %s",
|
||||
response.status_code
|
||||
)
|
||||
return False
|
||||
@@ -201,7 +201,7 @@ def check_replace_result_response(response):
|
||||
xml = response.content
|
||||
root = etree.fromstring(xml)
|
||||
except etree.ParseError as ex:
|
||||
log.error(u"Outcome service response: Failed to parse XML: %s\n %s", ex, xml)
|
||||
log.error("Outcome service response: Failed to parse XML: %s\n %s", ex, xml)
|
||||
return False
|
||||
|
||||
major_codes = root.xpath(
|
||||
@@ -209,14 +209,14 @@ def check_replace_result_response(response):
|
||||
namespaces={'ns': 'http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0'})
|
||||
if len(major_codes) != 1:
|
||||
log.error(
|
||||
u"Outcome service response: Expected exactly one imsx_codeMajor field in response. Received %s",
|
||||
"Outcome service response: Expected exactly one imsx_codeMajor field in response. Received %s",
|
||||
major_codes
|
||||
)
|
||||
return False
|
||||
|
||||
if major_codes[0].text != 'success':
|
||||
log.error(
|
||||
u"Outcome service response: Unexpected major code: %s.",
|
||||
"Outcome service response: Unexpected major code: %s.",
|
||||
major_codes[0].text
|
||||
)
|
||||
return False
|
||||
|
||||
@@ -10,9 +10,9 @@ from opaque_keys.edx.keys import LearningContextKey
|
||||
|
||||
import lms.djangoapps.lti_provider.outcomes as outcomes
|
||||
from lms.djangoapps.grades.api import signals as grades_signals
|
||||
from lms.djangoapps.lti_provider.tasks import send_composite_outcome, send_leaf_outcome
|
||||
from lms.djangoapps.lti_provider.views import parse_course_and_usage_keys
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from lms.djangoapps.lti_provider.tasks import send_composite_outcome, send_leaf_outcome
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -70,8 +70,8 @@ def score_changed_handler(sender, **kwargs): # pylint: disable=unused-argument
|
||||
)
|
||||
else:
|
||||
log.error(
|
||||
u"Outcome Service: Required signal parameter is None. "
|
||||
u"points_possible: %s, points_earned: %s, user_id: %s, "
|
||||
u"course_id: %s, usage_id: %s",
|
||||
"Outcome Service: Required signal parameter is None. "
|
||||
"points_possible: %s, points_earned: %s, user_id: %s, "
|
||||
"course_id: %s, usage_id: %s",
|
||||
points_possible, points_earned, user_id, course_id, usage_id
|
||||
)
|
||||
|
||||
@@ -3,7 +3,6 @@ Subclass of oauthlib's RequestValidator that checks an OAuth signature.
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
from oauthlib.oauth1 import RequestValidator, SignatureOnlyEndpoint
|
||||
|
||||
|
||||
@@ -18,7 +17,7 @@ class SignatureValidator(RequestValidator):
|
||||
"""
|
||||
|
||||
def __init__(self, lti_consumer):
|
||||
super(SignatureValidator, self).__init__() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().__init__()
|
||||
self.endpoint = SignatureOnlyEndpoint(self)
|
||||
self.lti_consumer = lti_consumer
|
||||
|
||||
@@ -99,7 +98,7 @@ class SignatureValidator(RequestValidator):
|
||||
:return: True if the signature matches, False if it does not.
|
||||
"""
|
||||
|
||||
method = six.text_type(request.method)
|
||||
method = str(request.method)
|
||||
url = request.build_absolute_uri()
|
||||
body = request.body
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ def send_composite_outcome(user_id, course_id, assignment_id, version):
|
||||
assignment = GradedAssignment.objects.get(id=assignment_id)
|
||||
if version != assignment.version_number:
|
||||
log.info(
|
||||
u"Score passback for GradedAssignment %s skipped. More recent score available.",
|
||||
"Score passback for GradedAssignment %s skipped. More recent score available.",
|
||||
assignment.id
|
||||
)
|
||||
return
|
||||
|
||||
@@ -3,14 +3,15 @@ Tests for the LTI outcome service handlers, both in outcomes.py and in tasks.py
|
||||
"""
|
||||
|
||||
|
||||
from unittest.mock import ANY, MagicMock, patch
|
||||
|
||||
from django.test import TestCase
|
||||
from lxml import etree
|
||||
from mock import ANY, MagicMock, patch
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
|
||||
import lms.djangoapps.lti_provider.outcomes as outcomes
|
||||
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, check_mongo_calls
|
||||
|
||||
@@ -21,7 +22,7 @@ class StoreOutcomeParametersTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(StoreOutcomeParametersTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.user = UserFactory.create()
|
||||
self.course_key = CourseLocator(
|
||||
org='some_org',
|
||||
@@ -135,7 +136,7 @@ class SignAndSendReplaceResultTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(SignAndSendReplaceResultTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course_key = CourseLocator(
|
||||
org='some_org',
|
||||
course='some_course',
|
||||
@@ -185,7 +186,7 @@ class XmlHandlingTest(TestCase):
|
||||
methods in outcomes.py
|
||||
"""
|
||||
|
||||
response_xml = u"""
|
||||
response_xml = """
|
||||
<imsx_POXEnvelopeResponse xmlns = "http://www.imsglobal.org/services/ltiv1p1/xsd/imsoms_v1p0">
|
||||
<imsx_POXHeader>
|
||||
<imsx_POXResponseHeaderInfo>
|
||||
@@ -298,7 +299,7 @@ class TestAssignmentsForProblem(ModuleStoreTestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(TestAssignmentsForProblem, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.user = UserFactory.create()
|
||||
self.user_id = self.user.id
|
||||
self.outcome_service = self.create_outcome_service('outcomes')
|
||||
|
||||
@@ -3,10 +3,11 @@ Tests for the SignatureValidator class.
|
||||
"""
|
||||
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import ddt
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from mock import patch
|
||||
|
||||
from lms.djangoapps.lti_provider.models import LtiConsumer
|
||||
from lms.djangoapps.lti_provider.signature_validator import SignatureValidator
|
||||
@@ -30,7 +31,7 @@ class ClientKeyValidatorTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(ClientKeyValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.lti_consumer = get_lti_consumer()
|
||||
|
||||
def test_valid_client_key(self):
|
||||
@@ -60,7 +61,7 @@ class NonceValidatorTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(NonceValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.lti_consumer = get_lti_consumer()
|
||||
|
||||
def test_valid_nonce(self):
|
||||
@@ -91,7 +92,7 @@ class SignatureValidatorTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(SignatureValidatorTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.lti_consumer = get_lti_consumer()
|
||||
|
||||
def test_get_existing_client_secret(self):
|
||||
@@ -110,7 +111,7 @@ class SignatureValidatorTest(TestCase):
|
||||
Verify that the signature validaton library method is called using the
|
||||
correct parameters derived from the HttpRequest.
|
||||
"""
|
||||
body = u'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
|
||||
body = 'oauth_signature_method=HMAC-SHA1&oauth_version=1.0'
|
||||
content_type = 'application/x-www-form-urlencoded'
|
||||
request = RequestFactory().post('/url', body, content_type=content_type)
|
||||
headers = {'Content-Type': content_type}
|
||||
|
||||
@@ -3,15 +3,15 @@ Tests for the LTI outcome service handlers, both in outcomes.py and in tasks.py
|
||||
"""
|
||||
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import ddt
|
||||
import six
|
||||
from django.test import TestCase
|
||||
from mock import MagicMock, patch
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
|
||||
import lms.djangoapps.lti_provider.tasks as tasks
|
||||
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.lti_provider.models import GradedAssignment, LtiConsumer, OutcomeService
|
||||
|
||||
|
||||
class BaseOutcomeTest(TestCase):
|
||||
@@ -19,7 +19,7 @@ class BaseOutcomeTest(TestCase):
|
||||
Super type for tests of both the leaf and composite outcome celery tasks.
|
||||
"""
|
||||
def setUp(self):
|
||||
super(BaseOutcomeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.course_key = CourseLocator(
|
||||
org='some_org',
|
||||
course='some_course',
|
||||
@@ -96,7 +96,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(SendCompositeOutcomeTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.descriptor = MagicMock()
|
||||
self.descriptor.location = BlockUsageLocator(
|
||||
course_key=self.course_key,
|
||||
@@ -123,7 +123,7 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
|
||||
def test_outcome_with_score_score(self, earned, possible, expected):
|
||||
self.course_grade.score_for_module = MagicMock(return_value=(earned, possible))
|
||||
tasks.send_composite_outcome(
|
||||
self.user.id, six.text_type(self.course_key), self.assignment.id, 1
|
||||
self.user.id, str(self.course_key), self.assignment.id, 1
|
||||
)
|
||||
self.send_score_update_mock.assert_called_once_with(self.assignment, expected)
|
||||
|
||||
@@ -131,6 +131,6 @@ class SendCompositeOutcomeTest(BaseOutcomeTest):
|
||||
self.assignment.version_number = 2
|
||||
self.assignment.save()
|
||||
tasks.send_composite_outcome(
|
||||
self.user.id, six.text_type(self.course_key), self.assignment.id, 1
|
||||
self.user.id, str(self.course_key), self.assignment.id, 1
|
||||
)
|
||||
assert self.course_grade_mock.call_count == 0
|
||||
|
||||
@@ -4,17 +4,18 @@ Tests for the LTI user management functionality
|
||||
|
||||
|
||||
import string
|
||||
from unittest.mock import MagicMock, PropertyMock, patch
|
||||
|
||||
import pytest
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from mock import MagicMock, PropertyMock, patch
|
||||
from six.moves import range
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
|
||||
from .. import users
|
||||
from ..models import LtiConsumer, LtiUser
|
||||
from common.djangoapps.student.tests.factories import UserFactory # lint-amnesty, pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
class UserManagementHelperTest(TestCase):
|
||||
@@ -23,7 +24,7 @@ class UserManagementHelperTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(UserManagementHelperTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.request = RequestFactory().post('/')
|
||||
self.old_user = UserFactory.create()
|
||||
self.new_user = UserFactory.create()
|
||||
@@ -68,7 +69,7 @@ class UserManagementHelperTest(TestCase):
|
||||
# Check that the username contains only allowable characters
|
||||
for char in range(len(username)): # lint-amnesty, pylint: disable=consider-using-enumerate
|
||||
assert username[char] in (string.ascii_letters + string.digits), \
|
||||
u"Username has forbidden character '{}'".format(username[char])
|
||||
"Username has forbidden character '{}'".format(username[char])
|
||||
|
||||
|
||||
@patch('lms.djangoapps.lti_provider.users.switch_user', autospec=True)
|
||||
@@ -79,7 +80,7 @@ class AuthenticateLtiUserTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(AuthenticateLtiUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.lti_consumer = LtiConsumer(
|
||||
consumer_name='TestConsumer',
|
||||
consumer_key='TestKey',
|
||||
@@ -146,7 +147,7 @@ class CreateLtiUserTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CreateLtiUserTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.lti_consumer = LtiConsumer(
|
||||
consumer_name='TestConsumer',
|
||||
consumer_key='TestKey',
|
||||
@@ -183,7 +184,7 @@ class LtiBackendTest(TestCase):
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(LtiBackendTest, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
self.edx_user = UserFactory.create()
|
||||
self.edx_user.save()
|
||||
self.lti_consumer = LtiConsumer(
|
||||
|
||||
@@ -3,36 +3,36 @@ Tests for the LTI provider views
|
||||
"""
|
||||
|
||||
|
||||
import six
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
from django.test import TestCase
|
||||
from django.test.client import RequestFactory
|
||||
from django.urls import reverse
|
||||
from mock import MagicMock, patch
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from lms.djangoapps.courseware.testutils import RenderXBlockTestMixin
|
||||
from lms.djangoapps.lti_provider import models, views
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
LTI_DEFAULT_PARAMS = {
|
||||
'roles': u'Instructor,urn:lti:instrole:ims/lis/Administrator',
|
||||
'context_id': u'lti_launch_context_id',
|
||||
'oauth_version': u'1.0',
|
||||
'oauth_consumer_key': u'consumer_key',
|
||||
'oauth_signature': u'OAuth Signature',
|
||||
'oauth_signature_method': u'HMAC-SHA1',
|
||||
'oauth_timestamp': u'OAuth Timestamp',
|
||||
'oauth_nonce': u'OAuth Nonce',
|
||||
'user_id': u'LTI_User',
|
||||
'roles': 'Instructor,urn:lti:instrole:ims/lis/Administrator',
|
||||
'context_id': 'lti_launch_context_id',
|
||||
'oauth_version': '1.0',
|
||||
'oauth_consumer_key': 'consumer_key',
|
||||
'oauth_signature': 'OAuth Signature',
|
||||
'oauth_signature_method': 'HMAC-SHA1',
|
||||
'oauth_timestamp': 'OAuth Timestamp',
|
||||
'oauth_nonce': 'OAuth Nonce',
|
||||
'user_id': 'LTI_User',
|
||||
}
|
||||
|
||||
LTI_OPTIONAL_PARAMS = {
|
||||
'context_title': u'context title',
|
||||
'context_label': u'context label',
|
||||
'lis_result_sourcedid': u'result sourcedid',
|
||||
'lis_outcome_service_url': u'outcome service URL',
|
||||
'tool_consumer_instance_guid': u'consumer instance guid'
|
||||
'context_title': 'context title',
|
||||
'context_label': 'context label',
|
||||
'lis_result_sourcedid': 'result sourcedid',
|
||||
'lis_outcome_service_url': 'outcome service URL',
|
||||
'tool_consumer_instance_guid': 'consumer instance guid'
|
||||
}
|
||||
|
||||
COURSE_KEY = CourseLocator(org='some_org', course='some_course', run='some_run')
|
||||
@@ -62,13 +62,13 @@ def build_launch_request(extra_post_data=None, param_to_delete=None):
|
||||
return request
|
||||
|
||||
|
||||
class LtiTestMixin(object):
|
||||
class LtiTestMixin:
|
||||
"""
|
||||
Mixin for LTI tests
|
||||
"""
|
||||
@patch.dict('django.conf.settings.FEATURES', {'ENABLE_LTI_PROVIDER': True})
|
||||
def setUp(self):
|
||||
super(LtiTestMixin, self).setUp() # lint-amnesty, pylint: disable=super-with-arguments
|
||||
super().setUp()
|
||||
# Always accept the OAuth signature
|
||||
self.mock_verify = MagicMock(return_value=True)
|
||||
patcher = patch('lms.djangoapps.lti_provider.signature_validator.SignatureValidator.verify', self.mock_verify)
|
||||
@@ -94,7 +94,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
|
||||
Verifies that the LTI launch succeeds when passed a valid request.
|
||||
"""
|
||||
request = build_launch_request()
|
||||
views.lti_launch(request, six.text_type(COURSE_KEY), six.text_type(USAGE_KEY))
|
||||
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
|
||||
render.assert_called_with(request, USAGE_KEY)
|
||||
|
||||
@patch('lms.djangoapps.lti_provider.views.render_courseware')
|
||||
@@ -105,7 +105,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
|
||||
Verifies that the LTI launch succeeds when passed a valid request.
|
||||
"""
|
||||
request = build_launch_request(extra_post_data=LTI_OPTIONAL_PARAMS)
|
||||
views.lti_launch(request, six.text_type(COURSE_KEY), six.text_type(USAGE_KEY))
|
||||
views.lti_launch(request, str(COURSE_KEY), str(USAGE_KEY))
|
||||
store_params.assert_called_with(
|
||||
dict(list(ALL_PARAMS.items()) + list(LTI_OPTIONAL_PARAMS.items())),
|
||||
request.user,
|
||||
@@ -122,8 +122,8 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
|
||||
request = build_launch_request()
|
||||
views.lti_launch(
|
||||
request,
|
||||
six.text_type(COURSE_PARAMS['course_key']),
|
||||
six.text_type(COURSE_PARAMS['usage_key'])
|
||||
str(COURSE_PARAMS['course_key']),
|
||||
str(COURSE_PARAMS['usage_key'])
|
||||
)
|
||||
store_params.assert_called_with(ALL_PARAMS, request.user, self.consumer)
|
||||
|
||||
@@ -175,7 +175,7 @@ class LtiLaunchTest(LtiTestMixin, TestCase):
|
||||
consumer = models.LtiConsumer.objects.get(
|
||||
consumer_key=LTI_DEFAULT_PARAMS['oauth_consumer_key']
|
||||
)
|
||||
assert consumer.instance_guid == u'consumer instance guid'
|
||||
assert consumer.instance_guid == 'consumer instance guid'
|
||||
|
||||
|
||||
class LtiLaunchTestRender(LtiTestMixin, RenderXBlockTestMixin, ModuleStoreTestCase):
|
||||
@@ -192,8 +192,8 @@ class LtiLaunchTestRender(LtiTestMixin, RenderXBlockTestMixin, ModuleStoreTestCa
|
||||
lti_launch_url = reverse(
|
||||
'lti_provider_launch',
|
||||
kwargs={
|
||||
'course_id': six.text_type(self.course.id),
|
||||
'usage_id': six.text_type(usage_key)
|
||||
'course_id': str(self.course.id),
|
||||
'usage_id': str(usage_key)
|
||||
}
|
||||
)
|
||||
if url_encoded_params:
|
||||
|
||||
@@ -13,10 +13,9 @@ from django.contrib.auth import authenticate, login
|
||||
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import IntegrityError, transaction
|
||||
from six.moves import range
|
||||
|
||||
from lms.djangoapps.lti_provider.models import LtiUser
|
||||
from common.djangoapps.student.models import UserProfile
|
||||
from lms.djangoapps.lti_provider.models import LtiUser
|
||||
|
||||
|
||||
def authenticate_lti_user(request, lti_user_id, lti_consumer):
|
||||
@@ -55,7 +54,7 @@ def create_lti_user(lti_user_id, lti_consumer):
|
||||
while not created:
|
||||
try:
|
||||
edx_user_id = generate_random_edx_username()
|
||||
edx_email = "{}@{}".format(edx_user_id, settings.LTI_USER_EMAIL_DOMAIN)
|
||||
edx_email = f"{edx_user_id}@{settings.LTI_USER_EMAIL_DOMAIN}"
|
||||
with transaction.atomic():
|
||||
edx_user = User.objects.create_user(
|
||||
username=edx_user_id,
|
||||
@@ -112,7 +111,7 @@ def generate_random_edx_username():
|
||||
return username
|
||||
|
||||
|
||||
class LtiBackend(object):
|
||||
class LtiBackend:
|
||||
"""
|
||||
A Django authentication backend that authenticates users via LTI. This
|
||||
backend will only return a User object if it is associated with an LTI
|
||||
|
||||
@@ -5,19 +5,18 @@ LTI Provider view functions
|
||||
|
||||
import logging
|
||||
|
||||
import six
|
||||
from django.conf import settings
|
||||
from django.http import Http404, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
|
||||
from common.djangoapps.util.views import add_p3p_header
|
||||
from lms.djangoapps.lti_provider.models import LtiConsumer
|
||||
from lms.djangoapps.lti_provider.outcomes import store_outcome_parameters
|
||||
from lms.djangoapps.lti_provider.signature_validator import SignatureValidator
|
||||
from lms.djangoapps.lti_provider.users import authenticate_lti_user
|
||||
from openedx.core.lib.url_utils import unquote_slashes
|
||||
from common.djangoapps.util.views import add_p3p_header
|
||||
|
||||
log = logging.getLogger("edx.lti_provider")
|
||||
|
||||
@@ -78,7 +77,7 @@ def lti_launch(request, course_id, usage_id):
|
||||
course_key, usage_key = parse_course_and_usage_keys(course_id, usage_id)
|
||||
except InvalidKeyError:
|
||||
log.error(
|
||||
u'Invalid course key %s or usage key %s from request %s',
|
||||
'Invalid course key %s or usage key %s from request %s',
|
||||
course_id,
|
||||
usage_id,
|
||||
request
|
||||
@@ -146,7 +145,7 @@ def render_courseware(request, usage_key):
|
||||
"""
|
||||
# return an HttpResponse object that contains the template and necessary context to render the courseware.
|
||||
from lms.djangoapps.courseware.views.views import render_xblock
|
||||
return render_xblock(request, six.text_type(usage_key), check_if_enrolled=False)
|
||||
return render_xblock(request, str(usage_key), check_if_enrolled=False)
|
||||
|
||||
|
||||
def parse_course_and_usage_keys(course_id, usage_id):
|
||||
|
||||
Reference in New Issue
Block a user