From cc56e41d0ccc4904e572543b3f0af658e472460a Mon Sep 17 00:00:00 2001 From: Jillian Date: Fri, 7 Mar 2025 02:58:26 +1030 Subject: [PATCH] fix: allow LTI blocks to be loaded in a Library v2 context [FC-0076] (#36265) Fixes errors thrown when previewing/editing (built-in) LTI blocks in a Libraries v2 context. These fixes allow Library Authors to store LTI blocks in their content libraries. --- xmodule/editing_block.py | 19 ++++++++++++++++++- xmodule/lti_block.py | 10 ++++++++-- xmodule/word_cloud_block.py | 20 -------------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/xmodule/editing_block.py b/xmodule/editing_block.py index c35dc57bf6..13f42f5fdd 100644 --- a/xmodule/editing_block.py +++ b/xmodule/editing_block.py @@ -3,7 +3,8 @@ import logging -from xblock.fields import Scope, String +from xblock.core import XBlock +from xblock.fields import Boolean, Scope, String from xmodule.mako_block import MakoTemplateBlockBase @@ -43,3 +44,19 @@ class EditingMixin(EditingFields, MakoTemplateBlockBase): # Add our specific template information (the raw data body) _context.update({'data': self.data}) return _context + + @XBlock.json_handler + def studio_submit(self, submissions, suffix=''): # pylint: disable=unused-argument + """ + Change the settings for this XBlock given by the Studio user + """ + for field_name in self.editable_metadata_fields: + if field_name in submissions and field_name in self.fields: + field = self.fields[field_name] + if isinstance(field, Boolean): + setattr(self, field_name, submissions[field_name] == 'True') + else: + setattr(self, field_name, submissions[field_name]) + return { + 'result': 'success', + } diff --git a/xmodule/lti_block.py b/xmodule/lti_block.py index 944a7ec88d..f4503dcf23 100644 --- a/xmodule/lti_block.py +++ b/xmodule/lti_block.py @@ -68,6 +68,7 @@ import oauthlib.oauth1 from django.conf import settings from lxml import etree from oauthlib.oauth1.rfc5849 import signature +from opaque_keys.edx.keys import CourseKey from pytz import UTC from web_fragments.fragment import Fragment from webob import Response @@ -609,8 +610,12 @@ class _BuiltInLTIBlock( def get_course(self): """ Return course by course id. + + Returns None if the current block is not part of a course (i.e part of a library). """ - return self.runtime.modulestore.get_course(self.course_id) + if isinstance(self.course_id, CourseKey): + return self.runtime.modulestore.get_course(self.course_id) + return None @property def context_id(self): @@ -960,7 +965,8 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'} Obtains client_key and client_secret credentials from current course. """ course = self.get_course() - for lti_passport in course.lti_passports: + lti_passports = course.lti_passports if course else [] + for lti_passport in lti_passports: try: lti_id, key, secret = [i.strip() for i in lti_passport.split(':')] except ValueError: diff --git a/xmodule/word_cloud_block.py b/xmodule/word_cloud_block.py index f83cda8c0c..37e82400df 100644 --- a/xmodule/word_cloud_block.py +++ b/xmodule/word_cloud_block.py @@ -315,26 +315,6 @@ class _BuiltInWordCloudBlock( # pylint: disable=abstract-method return xblock_body - @XBlock.json_handler - def studio_submit(self, submissions, suffix=''): # pylint: disable=unused-argument - """ - Change the settings for this XBlock given by the Studio user - """ - if 'display_name' in submissions: - self.display_name = submissions['display_name'] - if 'instructions' in submissions: - self.instructions = submissions['instructions'] - if 'num_inputs' in submissions: - self.num_inputs = submissions['num_inputs'] - if 'num_top_words' in submissions: - self.num_top_words = submissions['num_top_words'] - if 'display_student_percents' in submissions: - self.display_student_percents = submissions['display_student_percents'] == 'True' - - return { - 'result': 'success', - } - WordCloudBlock = ( _ExtractedWordCloudBlock if settings.USE_EXTRACTED_WORD_CLOUD_BLOCK