diff --git a/lms/djangoapps/courseware/tests/test_discussion_xblock.py b/lms/djangoapps/courseware/tests/test_discussion_xblock.py index 599f125a7e..16c40e8ff5 100644 --- a/lms/djangoapps/courseware/tests/test_discussion_xblock.py +++ b/lms/djangoapps/courseware/tests/test_discussion_xblock.py @@ -11,6 +11,7 @@ import json import uuid from unittest import mock +from unittest.mock import patch import ddt from django.conf import settings from django.test.utils import override_settings @@ -18,9 +19,10 @@ from django.urls import reverse from opaque_keys.edx.keys import CourseKey from web_fragments.fragment import Fragment from xblock.field_data import DictFieldData -from xmodule.discussion_block import DiscussionXBlock, loader +from xmodule.discussion_block import DiscussionXBlock from xmodule.modulestore.tests.django_utils import TEST_DATA_SPLIT_MODULESTORE, SharedModuleStoreTestCase from xmodule.modulestore.tests.factories import BlockFactory, ToyCourseFactory +from xmodule.tests.helpers import mock_render_template from lms.djangoapps.course_api.blocks.tests.helpers import deserialize_usage_key from lms.djangoapps.courseware.block_render import get_block_for_descriptor @@ -153,15 +155,15 @@ class TestViews(TestDiscussionXBlock): assert self.render_template.call_count == 1 return self.render_template.call_args_list[0][0][0] - def test_studio_view(self): + @patch('xblock.utils.resources.ResourceLoader.render_django_template', side_effect=mock_render_template) + def test_studio_view(self, mock_render_django_template): """ Test for the studio view. """ fragment = self.block.author_view() assert isinstance(fragment, Fragment) - assert fragment.content == self.template_canary - self.render_template.assert_called_once_with( - 'discussion/_discussion_inline_studio.html', + mock_render_django_template.assert_called_once_with( + 'templates/discussion/_discussion_inline_studio.html', { 'discussion_id': self.discussion_id, 'is_visible': True, @@ -192,10 +194,11 @@ class TestViews(TestDiscussionXBlock): } self.block.has_permission = lambda perm: permission_dict[perm] - with mock.patch.object(loader, 'render_template', mock.Mock): + with mock.patch('xmodule.discussion_block.render_to_string', return_value='') as mock_render: self.block.student_view() - - context = self.get_template_context() + # Get context from the mock call + assert mock_render.call_count == 1 + context = mock_render.call_args_list[0][0][1] for permission_name, expected_value in expected_permissions.items(): assert expected_value == context[permission_name] @@ -204,7 +207,7 @@ class TestViews(TestDiscussionXBlock): """ Test proper js init function is called. """ - with mock.patch.object(loader, 'render_template', mock.Mock): + with mock.patch('xmodule.discussion_block.render_to_string', return_value=''): fragment = self.block.student_view() assert fragment.js_init_fn == 'DiscussionInlineBlock' diff --git a/lms/djangoapps/discussion/templates/discussion/discussion_board_fragment.html b/lms/djangoapps/discussion/templates/discussion/discussion_board_fragment.html index be7bce1733..cf7c8969fb 100644 --- a/lms/djangoapps/discussion/templates/discussion/discussion_board_fragment.html +++ b/lms/djangoapps/discussion/templates/discussion/discussion_board_fragment.html @@ -1,78 +1,76 @@ -## mako +{% load static i18n %} -<%namespace name='static' file='../static_content.html'/> - -<%page expression_filter="h"/> - -<%! -import json -from django.utils.translation import gettext as _ -from django.template.defaultfilters import escapejs -from django.urls import reverse - -from lms.djangoapps.discussion.django_comment_client.permissions import has_permission -from openedx.core.djangolib.js_utils import dump_js_escaped_json, js_escaped_string -from openedx.core.djangolib.markup import HTML -%> - -
+ data-sort-preference="{{ sort_preference }}" + data-flag-moderator="{{ flag_moderator|yesno:'true,false' }}" + data-user-group-id="{{ user_group_id }}"> + - % if course_expiration_fragment: - ${HTML(course_expiration_fragment.content)} - % endif + + {% if course_expiration_fragment %} + {{ course_expiration_fragment.content|safe }} + {% endif %} +
- +
-
-<%include file="_underscore_templates.html" /> -<%include file="_thread_list_template.html" /> +{% include "discussion/_underscore_templates.html" %} +{% include "discussion/_thread_list_template.html" %} -<%static:require_module_async module_name="js/commerce/track_ecommerce_events" class_name="TrackECommerceEvents"> + diff --git a/lms/djangoapps/discussion/views.py b/lms/djangoapps/discussion/views.py index c01fb24b07..d6f61d2094 100644 --- a/lms/djangoapps/discussion/views.py +++ b/lms/djangoapps/discussion/views.py @@ -560,7 +560,8 @@ def _create_discussion_board_context(request, base_context, thread=None): 'is_commentable_divided': is_commentable_divided(course_key, discussion_id, course_discussion_settings), # If the default topic id is None the front-end code will look for a topic that contains "General" 'discussion_default_topic_id': _get_discussion_default_topic_id(course), - 'enable_daily_digest': is_forum_daily_digest_enabled() + 'enable_daily_digest': is_forum_daily_digest_enabled(), + 'PLATFORM_NAME': settings.PLATFORM_NAME }) context.update( get_experiment_user_metadata_context( diff --git a/lms/templates/discussion/_discussion_inline.html b/lms/templates/discussion/_discussion_inline.html index dea3156f37..3ab64ed93c 100644 --- a/lms/templates/discussion/_discussion_inline.html +++ b/lms/templates/discussion/_discussion_inline.html @@ -1,44 +1,45 @@ -<%page expression_filter="h"/> +{% load i18n %} -<%include file="_underscore_templates.html" /> -<%include file="_thread_list_template.html" /> +{% include "discussion/_underscore_templates.html" %} +{% include "discussion/_thread_list_template.html" %} -<%! -from django.utils.translation import gettext as _ -from json import dumps as json_dumps -from openedx.core.djangolib.js_utils import js_escaped_string -%> - -
- % if not user.is_authenticated: +
+ {% if not user.is_authenticated %}

- % endif + {% endif %} +
-

${_(display_name)}

-
${_("Topic:")} ${discussion_category} - % if discussion_target: - / ${discussion_target} - %endif -
+

+ {% filter force_escape %} + {% blocktrans with title=display_name %}{{ title }}{% endblocktrans %} + {% endfilter %} +

+
+ {% trans "Topic:" as tmsg %} {{tmsg|force_escape}} + {{ discussion_category }} + {% if discussion_target %} + / {{ discussion_target }} + {% endif %} +
-<%static:include path="common/templates/discussion/templates.underscore" /> + +{% include "common/templates/discussion/templates.underscore" %} diff --git a/xmodule/discussion_block.py b/xmodule/discussion_block.py index 79914b63d6..aaea2de7bb 100644 --- a/xmodule/discussion_block.py +++ b/xmodule/discussion_block.py @@ -6,6 +6,7 @@ import logging import urllib from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage +from django.template.loader import render_to_string from django.urls import reverse from django.utils.translation import get_language_bidi from web_fragments.fragment import Fragment @@ -23,7 +24,7 @@ from openedx.core.lib.xblock_utils import get_css_dependencies, get_js_dependenc from xmodule.xml_block import XmlMixin log = logging.getLogger(__name__) -loader = ResourceLoader(__name__) # pylint: disable=invalid-name +loader = ResourceLoader("lms") # pylint: disable=invalid-name def _(text): @@ -204,9 +205,11 @@ class _BuiltInDiscussionXBlock(XBlock, StudioEditableXBlockMixin, 'can_create_comment': self.has_permission("create_comment"), 'can_create_subcomment': self.has_permission("create_sub_comment"), 'login_msg': login_msg, + 'PLATFORM_NAME': settings.PLATFORM_NAME, + 'enable_discussion_home_panel': settings.FEATURES.get("ENABLE_DISCUSSION_HOME_PANEL", False), } fragment.add_content( - self.runtime.service(self, 'mako').render_lms_template('discussion/_discussion_inline.html', context) + render_to_string('discussion/_discussion_inline.html', context) ) fragment.initialize_js('DiscussionInlineBlock') @@ -219,13 +222,13 @@ class _BuiltInDiscussionXBlock(XBlock, StudioEditableXBlockMixin, """ fragment = Fragment() # For historic reasons, this template is in the LMS templates folder: - fragment.add_content(self.runtime.service(self, 'mako').render_lms_template( - 'discussion/_discussion_inline_studio.html', - { - 'discussion_id': self.discussion_id, - 'is_visible': self.is_visible, - } - )) + context = { + 'discussion_id': self.discussion_id, + 'is_visible': self.is_visible, + } + fragment.add_content( + loader.render_django_template('templates/discussion/_discussion_inline_studio.html', context) + ) return fragment def student_view_data(self):