feat: Add discussion_enabled for Unit (#28864)

For each unit discussion_enabled flag is added
so that each unit can be made discussable when needed.

Signed-off-by: Farhaan Bukhsh <farhaan@opencraft.com>
This commit is contained in:
Farhaan Bukhsh
2021-11-08 16:47:07 +05:30
committed by GitHub
parent 1668d74abb
commit cfe75e95b9
3 changed files with 150 additions and 4 deletions

View File

@@ -1309,7 +1309,9 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
# Update with gating info
xblock_info.update(_get_gating_info(course, xblock))
if is_xblock_unit:
# if xblock is a Unit we add the discussion_enabled option
xblock_info['discussion_enabled'] = xblock.discussion_enabled
if xblock.category == 'sequential':
# Entrance exam subsection should be hidden. in_entrance_exam is
# inherited metadata, all children will have it.

View File

@@ -0,0 +1,117 @@
"""
Test module to test the discussion enabled flag.
"""
import json
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from cms.djangoapps.contentstore.tests.utils import CourseTestCase
from cms.djangoapps.contentstore.utils import reverse_usage_url
class TestDiscussionEnabled(CourseTestCase):
"""
Test discussion enabled flags functionality in a Unit.
"""
def setUp(self):
super().setUp()
self.course = self.get_test_course()
self.course_usage_key = self.course.id.make_usage_key("course", self.course.id.run)
self.non_staff_authed_user_client, _ = self.create_non_staff_authed_user_client()
def get_test_course(self):
"""
Create and return a test course
"""
self.course = CourseFactory(
org="SHIELD",
number="SH101",
name="Introduction to Avengers",
run="2020_T2",
modulestore=self.store
)
self.chapter = ItemFactory(
parent_location=self.course.location,
category="chapter",
display_name="What is SHIELD?",
modulestore=self.store
)
self.sequential = ItemFactory(
parent_location=self.chapter.location,
category="sequential",
display_name="HQ",
modulestore=self.store
)
self.vertical = ItemFactory(
parent_location=self.sequential.location,
category="vertical",
display_name="Triskelion",
modulestore=self.store
)
self.vertical_1 = ItemFactory(
parent_location=self.sequential.location,
category="vertical",
display_name="Helicarrier",
modulestore=self.store
)
self.course.save()
return self.course
def _get_discussion_enabled_status(self, usage_key, client=None):
"""
Issue a GET request to fetch value of discussion_enabled flag of xblock represented by param:usage_key
"""
client = client if client is not None else self.client
url = reverse_usage_url("xblock_handler", usage_key)
resp = client.get(url, HTTP_ACCEPT="application/json")
return resp
def get_discussion_enabled_status(self, xblock, client=None):
"""
Issue a GET request to fetch value of discussion_enabled flag of param:xblock's
"""
resp = self._get_discussion_enabled_status(xblock.location, client=client)
content = json.loads(resp.content.decode("utf-8"))
return content.get("discussion_enabled", None)
def set_discussion_enabled_status(self, xblock, value, client=None):
"""
Issue a POST request to update value of discussion_enabled flag of param:xblock's
"""
client = client if client is not None else self.client
xblock_location = xblock.location
url = reverse_usage_url("xblock_handler", xblock_location)
resp = client.post(
url,
HTTP_ACCEPT="application/json",
data=json.dumps({"metadata": {"discussion_enabled": value}}),
content_type="application/json",
)
return resp
def test_discussion_enabled_false_initially(self):
"""
Tests discussion_enabled flag is False initially for vertical
"""
self.assertFalse(self.get_discussion_enabled_status(self.vertical))
self.assertFalse(self.get_discussion_enabled_status(self.vertical_1))
def test_discussion_enabled_toggle(self):
"""
Tests discussion_enabled can be toggled.
"""
self.set_discussion_enabled_status(self.vertical, True)
self.assertTrue(self.get_discussion_enabled_status(self.vertical))
self.assertFalse(self.get_discussion_enabled_status(self.vertical_1))
def test_non_course_author_cannot_get_or_set_discussion_enabled_flag(self):
"""
Test non course author cannot get/set discussion_enabled flag
"""
resp = self._get_discussion_enabled_status(self.course_usage_key, self.non_staff_authed_user_client)
self.assertEqual(resp.status_code, 403)
# Set call to the API with non authorised user should raise a 403
resp = self.set_discussion_enabled_status(self.vertical, True, self.non_staff_authed_user_client)
self.assertEqual(resp.status_code, 403)

View File

@@ -11,28 +11,55 @@ from functools import reduce
import pytz
from lxml import etree
from web_fragments.fragment import Fragment
from xmodule.util.misc import is_xblock_an_assignment
from xblock.core import XBlock # lint-amnesty, pylint: disable=wrong-import-order
from xblock.fields import Boolean, Scope
from xmodule.mako_module import MakoTemplateBlockBase
from xmodule.progress import Progress
from xmodule.seq_module import SequenceFields
from xmodule.studio_editable import StudioEditableBlock
from xmodule.util.misc import is_xblock_an_assignment
from xmodule.util.xmodule_django import add_webpack_to_fragment
from xmodule.x_module import PUBLIC_VIEW, STUDENT_VIEW, XModuleFields
from xmodule.xml_module import XmlParserMixin
log = logging.getLogger(__name__)
# Make '_' a no-op so we can scrape strings. Using lambda instead of
# `django.utils.translation.ugettext_noop` because Django cannot be imported in this file
_ = lambda text: text
# HACK: This shouldn't be hard-coded to two types
# OBSOLETE: This obsoletes 'type'
CLASS_PRIORITY = ['video', 'problem']
class VerticalFields:
"""
A mixin to introduce fields in the Vertical Block.
"""
discussion_enabled = Boolean(
display_name=_("Enable in-context discussions for the Unit"),
help=_(
"Add discussion for the Unit."
),
default=False,
scope=Scope.settings,
)
@XBlock.needs('user', 'bookmarks')
@XBlock.wants('completion')
@XBlock.wants('call_to_action')
class VerticalBlock(SequenceFields, XModuleFields, StudioEditableBlock, XmlParserMixin, MakoTemplateBlockBase, XBlock):
class VerticalBlock(
SequenceFields,
VerticalFields,
XModuleFields,
StudioEditableBlock,
XmlParserMixin,
MakoTemplateBlockBase,
XBlock
):
"""
Layout XBlock for rendering subblocks vertically.
"""