Skip to content

Commit

Permalink
feat: [AXM-349] refactor offline content generation
Browse files Browse the repository at this point in the history
  • Loading branch information
NiedielnitsevIvan committed Jun 5, 2024
1 parent 5f34c2d commit 412acc9
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 14 deletions.
17 changes: 13 additions & 4 deletions openedx/features/offline_mode/assets_management.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import shutil
import os
import logging
import os
import requests

from django.conf import settings
from django.core.files.base import ContentFile
Expand All @@ -11,7 +12,7 @@
from xmodule.exceptions import NotFoundError
from xmodule.modulestore.exceptions import ItemNotFoundError

# from .file_management import get_static_file_path, read_static_file
from .constants import MATHJAX_CDN_URL, MATHJAX_STATIC_PATH


log = logging.getLogger(__name__)
Expand Down Expand Up @@ -43,6 +44,8 @@ def save_asset_file(xblock, path, filename):
path (str): The path where the asset is located.
filename (str): The name of the file to be saved.
"""
if filename.endswith('djangojs.js'):
return
try:
if '/' in filename:
static_path = get_static_file_path(filename)
Expand Down Expand Up @@ -140,11 +143,17 @@ def is_modified(xblock):
:return:
"""
file_path = os.path.join(base_storage_path(xblock), 'content_html.zip')
# file_path = f'{base_storage_path(xblock)}content_html.zip' # FIXME: change filename, and change to os.path.join
#

try:
last_modified = default_storage.get_created_time(file_path)
except OSError:
return True

return xblock.published_on > last_modified


def save_mathjax_to_local_static():
if not default_storage.exists(MATHJAX_STATIC_PATH):
response = requests.get(MATHJAX_CDN_URL)
default_storage.save(MATHJAX_STATIC_PATH, ContentFile(response.content))
log.info(f"Successfully saved MathJax to {MATHJAX_STATIC_PATH}")
5 changes: 5 additions & 0 deletions openedx/features/offline_mode/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import os

MATHJAX_VERSION = '2.7.5'
MATHJAX_CDN_URL = f'https://cdn.jsdelivr.net/npm/mathjax@{MATHJAX_VERSION}/MathJax.js'
MATHJAX_STATIC_PATH = os.path.join('offline_mode_shared_static', 'js', f'MathJax-{MATHJAX_VERSION}.js')
56 changes: 46 additions & 10 deletions openedx/features/offline_mode/html_manipulator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import os
import re

from bs4 import BeautifulSoup

from .assets_management import save_asset_file
from django.conf import settings

from .assets_management import save_asset_file, save_mathjax_to_local_static
from .constants import MATHJAX_CDN_URL, MATHJAX_STATIC_PATH

RELATIVE_PATH_DIFF = '../../../../'


class HtmlManipulator:
Expand All @@ -16,21 +23,37 @@ def __init__(self, xblock, html_data):
self.xblock = xblock

def _replace_mathjax_link(self):
# FIXME: version shouldn't be hardcoded
mathjax_pattern = re.compile(r'src="https://cdn.jsdelivr.net/npm/[email protected]/MathJax.js[^"]*"')
return mathjax_pattern.sub('src="/static/mathjax/MathJax.js"', self.html_data)
"""
Replace MathJax CDN link with local path to MathJax.js file.
"""
mathjax_pattern = re.compile(fr'src="{MATHJAX_CDN_URL}[^"]*"')
self.html_data = mathjax_pattern.sub(
f'src="{RELATIVE_PATH_DIFF}{MATHJAX_STATIC_PATH}"',
self.html_data
)

def _replace_static_links(self):
pattern = re.compile(r'/static/[\w./-]+')
return pattern.sub(self._replace_link, self.html_data)
"""
Replace static links with local links.
"""
static_links_pattern = os.path.join(settings.STATIC_URL, '[\w./-]+')
pattern = re.compile(fr'{static_links_pattern}')
self.html_data = pattern.sub(self._replace_link, self.html_data)

def _replace_link(self, match):
"""
Returns the local path of the asset file.
"""
link = match.group()
filename = link.split('/static/')[-1]
filename = link.split(settings.STATIC_URL)[-1]
save_asset_file(self.xblock, link, filename)
return f'assets/{filename}'

def _replace_iframe(self, soup):
@staticmethod
def _replace_iframe(soup):
"""
Replace iframe tags with anchor tags.
"""
for node in soup.find_all('iframe'):
replacement = soup.new_tag('p')
tag_a = soup.new_tag('a')
Expand All @@ -39,7 +62,13 @@ def _replace_iframe(self, soup):
replacement.append(tag_a)
node.replace_with(replacement)

def _add_js_bridge(self, soup):
@staticmethod
def _add_js_bridge(soup):
"""
Add JS bridge script to the HTML content.
:param soup:
:return:
"""
script_tag = soup.new_tag('script')
# FIXME: this script should be loaded from a file
script_tag.string = """
Expand Down Expand Up @@ -83,8 +112,15 @@ def _add_js_bridge(self, soup):
return soup

def process_html(self):
self._replace_mathjax_link()
"""
Prepares HTML content for local use.
Changes links to static files to paths to pre-generated static files for offline use.
"""
save_mathjax_to_local_static()
self._replace_static_links()
self._replace_mathjax_link()

soup = BeautifulSoup(self.html_data, 'html.parser')
self._replace_iframe(soup)
self._add_js_bridge(soup)
Expand Down

0 comments on commit 412acc9

Please sign in to comment.