From 2049fab9fc3f6ac4cfd9528765a9b1af16f25e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=86=D0=B2=D0=B0=D0=BD=20=D0=9D=D1=94=D0=B4=D1=94=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=96=D1=86=D0=B5=D0=B2?= Date: Thu, 20 Jun 2024 18:06:49 +0300 Subject: [PATCH] fix: [AXM-791] fix error 404 handling and optimize for not modified blocks --- cms/djangoapps/contentstore/utils.py | 2 +- .../offline_mode/storage_management.py | 26 ++++++++++++------- openedx/features/offline_mode/tasks.py | 13 +++++----- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index c86accc22fb6..8eaf31f927bd 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -2328,7 +2328,7 @@ def get_cms_api_client(): """ Returns an API client which can be used to make requests from the CMS service. """ - user = User.objects.get(username=settings.EDXAPP_CMS_SERVICE_USER_NAME) + user = User.objects.get(username=settings.CMS_SERVICE_USER_NAME) jwt = create_jwt_for_user(user) client = requests.Session() client.auth = SuppliedJwtAuth(jwt) diff --git a/openedx/features/offline_mode/storage_management.py b/openedx/features/offline_mode/storage_management.py index 2811485695b7..a77cf606c853 100644 --- a/openedx/features/offline_mode/storage_management.py +++ b/openedx/features/offline_mode/storage_management.py @@ -15,6 +15,7 @@ from .assets_management import block_storage_path, clean_outdated_xblock_files, is_modified from .html_manipulator import HtmlManipulator +from .renderer import XBlockRenderer User = get_user_model() log = logging.getLogger(__name__) @@ -25,13 +26,12 @@ class OfflineContentGenerator: Creates zip file with Offline Content in the media storage. """ - def __init__(self, xblock, html_data, storage_class=None, storage_kwargs=None): + def __init__(self, xblock, html_data=None, storage_class=None, storage_kwargs=None): """ Creates `SaveOfflineContentToStorage` object. Args: xblock (XBlock): The XBlock instance - html_data (str): The rendered HTML representation of the XBlock storage_class: Used media storage class. storage_kwargs (dict): Additional storage attributes. """ @@ -39,14 +39,27 @@ def __init__(self, xblock, html_data, storage_class=None, storage_kwargs=None): storage_kwargs = {} self.xblock = xblock - self.html_data = html_data + self.html_data = html_data or self.render_block_html_data() self.storage = get_storage(storage_class, **storage_kwargs) + def render_block_html_data(self): + """ + Renders the XBlock HTML content from the LMS. + """ + try: + return XBlockRenderer(str(self.xblock.location)).render_xblock_from_lms() + except Http404: + log.error( + f'Block {str(self.xblock.location)} cannot be fetched from course' + f' {self.xblock.location.course_key} during offline content generation.' + ) + return None + def generate_offline_content(self): """ Generates archive with XBlock content for offline mode. """ - if not is_modified(self.xblock): + if not self.html_data: return base_path = block_storage_path(self.xblock) @@ -56,11 +69,6 @@ def generate_offline_content(self): try: self.save_xblock_html(tmp_dir) self.create_zip_file(tmp_dir, base_path, f'{self.xblock.location.block_id}.zip') - except Http404: - log.error( - f'Block {self.xblock.location.block_id} cannot be fetched from course' - f' {self.xblock.location.course_key} during offline content generation.' - ) finally: shutil.rmtree(tmp_dir, ignore_errors=True) diff --git a/openedx/features/offline_mode/tasks.py b/openedx/features/offline_mode/tasks.py index 224840fc07d3..bbd9db524778 100644 --- a/openedx/features/offline_mode/tasks.py +++ b/openedx/features/offline_mode/tasks.py @@ -8,8 +8,8 @@ from xmodule.modulestore.django import modulestore +from .assets_management import is_modified from .constants import MAX_RETRY_ATTEMPTS, OFFLINE_SUPPORTED_XBLOCKS, RETRY_BACKOFF_INITIAL_TIMEOUT -from .renderer import XBlockRenderer from .storage_management import OfflineContentGenerator @@ -24,10 +24,9 @@ def generate_offline_content_for_course(course_id): course_key = CourseKey.from_string(course_id) for offline_supported_block_type in OFFLINE_SUPPORTED_XBLOCKS: for xblock in modulestore().get_items(course_key, qualifiers={'category': offline_supported_block_type}): - if not hasattr(xblock, 'closed') or not xblock.closed(): - block_id = str(xblock.location) - html_data = XBlockRenderer(block_id).render_xblock_from_lms() - generate_offline_content_for_block.apply_async([block_id, html_data]) + is_not_closed = not hasattr(xblock, 'closed') or not xblock.closed() + if is_not_closed and is_modified(xblock): + generate_offline_content_for_block.apply_async([str(xblock.location)]) @shared_task( @@ -36,10 +35,10 @@ def generate_offline_content_for_course(course_id): retry_kwargs={'max_retries': MAX_RETRY_ATTEMPTS} ) @set_code_owner_attribute -def generate_offline_content_for_block(block_id, html_data): +def generate_offline_content_for_block(block_id): """ Generates offline content for the specified block. """ block_usage_key = UsageKey.from_string(block_id) xblock = modulestore().get_item(block_usage_key) - OfflineContentGenerator(xblock, html_data).generate_offline_content() + OfflineContentGenerator(xblock).generate_offline_content()