feat: add support for enabling/disabling the wiki app (#28889)
Currently the wiki app can't be enabled or configured. This change allows enabling/disabling the wiki app which effectively hides/shows the wiki tab.
This commit is contained in:
@@ -184,8 +184,8 @@ class TabsAPITests(CourseTestCase):
|
||||
"""
|
||||
Test that toggling the visibility via the API works.
|
||||
"""
|
||||
self.check_toggle_tab_visibility("wiki", True)
|
||||
self.check_toggle_tab_visibility("wiki", False)
|
||||
self.check_toggle_tab_visibility("wiki", True)
|
||||
|
||||
def test_toggle_tab_visibility_fail(self):
|
||||
"""
|
||||
|
||||
@@ -159,8 +159,8 @@ class TabsPageTests(CourseTestCase):
|
||||
|
||||
def test_toggle_tab_visibility(self):
|
||||
"""Test toggling of tab visibility"""
|
||||
self.check_toggle_tab_visiblity('wiki', True)
|
||||
self.check_toggle_tab_visiblity('wiki', False)
|
||||
self.check_toggle_tab_visiblity('wiki', True)
|
||||
|
||||
def test_toggle_invalid_tab_visibility(self):
|
||||
"""Test toggling visibility of an invalid tab"""
|
||||
|
||||
@@ -41,8 +41,8 @@ class CourseHomeMetadataTests(BaseCourseHomeTests):
|
||||
response = self.client.get(self.url)
|
||||
assert response.status_code == 200
|
||||
assert not response.data.get('is_staff')
|
||||
# 'Course', 'Wiki', 'Progress' tabs
|
||||
assert len(response.data.get('tabs', [])) == 4
|
||||
# 'Course', and 'Progress' tabs
|
||||
assert len(response.data.get('tabs', [])) == 3
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_get_authenticated_not_enrolled(self, has_previously_enrolled):
|
||||
@@ -61,8 +61,8 @@ class CourseHomeMetadataTests(BaseCourseHomeTests):
|
||||
assert response.status_code == 200
|
||||
assert response.data['is_staff']
|
||||
# This differs for a staff user because they also receive the Instructor tab
|
||||
# 'Course', 'Wiki', 'Progress', and 'Instructor' tabs
|
||||
assert len(response.data.get('tabs', [])) == 5
|
||||
# 'Course', 'Progress', and 'Instructor' tabs
|
||||
assert len(response.data.get('tabs', [])) == 4
|
||||
|
||||
def test_get_masqueraded_user(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
"""Module with the course app configuration for the Wiki."""
|
||||
from typing import Dict, Optional, TYPE_CHECKING
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.course_apps.plugins import CourseApp
|
||||
|
||||
# Import the User model only for type checking since importing it at runtime
|
||||
# will prevent the app from starting since the model is imported before
|
||||
# Django's machinery is ready.
|
||||
if TYPE_CHECKING:
|
||||
from django.contrib.auth import get_user_model
|
||||
User = get_user_model()
|
||||
|
||||
WIKI_ENABLED = settings.WIKI_ENABLED
|
||||
|
||||
|
||||
class WikiCourseApp(CourseApp):
|
||||
"""
|
||||
Course app for the Wiki.
|
||||
"""
|
||||
|
||||
app_id = "wiki"
|
||||
name = _("Wiki")
|
||||
description = _("Enable learners to access, and collaborate on course-related information.")
|
||||
documentation_links = {
|
||||
"learn_more_configuration": settings.WIKI_HELP_URL,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def is_available(cls, course_key: CourseKey) -> bool: # pylint: disable=unused-argument
|
||||
"""
|
||||
Returns if the app is available for the course.
|
||||
|
||||
The wiki is available for all courses or none of them depending on the a Django setting.
|
||||
"""
|
||||
return WIKI_ENABLED
|
||||
|
||||
@classmethod
|
||||
def is_enabled(cls, course_key: CourseKey) -> bool: # pylint: disable=unused-argument
|
||||
"""
|
||||
Returns if the wiki is available for the course.
|
||||
|
||||
The wiki currently cannot be enabled or disabled on a per-course basis.
|
||||
"""
|
||||
return WIKI_ENABLED
|
||||
|
||||
@classmethod
|
||||
def set_enabled(cls, course_key: CourseKey, enabled: bool, user: 'User') -> bool:
|
||||
"""
|
||||
The wiki cannot be enabled or disabled.
|
||||
"""
|
||||
# Currently, you cannot enable/disable wiki via the API
|
||||
raise ValueError("Wiki cannot be enabled/disabled vis this API.")
|
||||
|
||||
@classmethod
|
||||
def get_allowed_operations(cls, course_key: CourseKey, user: Optional['User'] = None) -> Dict[str, bool]:
|
||||
"""
|
||||
Returns the operations you can perform on the wiki.
|
||||
"""
|
||||
return {
|
||||
# The wiki cannot be enabled/disabled via the API yet.
|
||||
"enable": False,
|
||||
"configure": True,
|
||||
}
|
||||
|
||||
82
lms/djangoapps/course_wiki/plugins/course_app.py
Normal file
82
lms/djangoapps/course_wiki/plugins/course_app.py
Normal file
@@ -0,0 +1,82 @@
|
||||
"""Module with the course app configuration for the Wiki."""
|
||||
from typing import Dict, Optional, TYPE_CHECKING
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_noop as _
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview, CourseOverviewTab
|
||||
from openedx.core.djangoapps.course_apps.plugins import CourseApp
|
||||
from openedx.core.lib.courses import get_course_by_id
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from xmodule.tabs import CourseTab, CourseTabList
|
||||
|
||||
# Import the User model only for type checking since importing it at runtime
|
||||
# will prevent the app from starting since the model is imported before
|
||||
# Django's machinery is ready.
|
||||
if TYPE_CHECKING:
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
WIKI_ENABLED = settings.WIKI_ENABLED
|
||||
|
||||
|
||||
class WikiCourseApp(CourseApp):
|
||||
"""
|
||||
Course app for the Wiki.
|
||||
"""
|
||||
|
||||
app_id = "wiki"
|
||||
name = _("Wiki")
|
||||
description = _("Enable learners to access, and collaborate on course-related information.")
|
||||
documentation_links = {
|
||||
"learn_more_configuration": settings.WIKI_HELP_URL,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def is_available(cls, course_key: CourseKey) -> bool: # pylint: disable=unused-argument
|
||||
"""
|
||||
Returns if the app is available for the course.
|
||||
|
||||
The wiki is available for all courses or none of them depending on the Django setting.
|
||||
"""
|
||||
return WIKI_ENABLED
|
||||
|
||||
@classmethod
|
||||
def is_enabled(cls, course_key: CourseKey) -> bool: # pylint: disable=unused-argument
|
||||
"""
|
||||
Returns if the wiki is enabled for the course.
|
||||
"""
|
||||
try:
|
||||
wiki_tab = CourseOverview.get_from_id(course_key).tab_set.get(tab_id='wiki')
|
||||
return not wiki_tab.is_hidden
|
||||
except CourseOverviewTab.DoesNotExist:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def set_enabled(cls, course_key: CourseKey, enabled: bool, user: 'User') -> bool:
|
||||
"""
|
||||
Enabled/disables the wiki tab in the course.
|
||||
"""
|
||||
course = get_course_by_id(course_key)
|
||||
wiki_tab = CourseTabList.get_tab_by_id(course.tabs, 'wiki')
|
||||
if wiki_tab is None:
|
||||
if not enabled:
|
||||
return False
|
||||
# If the course doesn't already have the wiki tab, add it.
|
||||
wiki_tab = CourseTab.load("wiki")
|
||||
course.tabs.append(wiki_tab)
|
||||
wiki_tab.is_hidden = not enabled
|
||||
modulestore().update_item(course, user.id)
|
||||
return enabled
|
||||
|
||||
@classmethod
|
||||
def get_allowed_operations(cls, course_key: CourseKey, user: Optional['User'] = None) -> Dict[str, bool]:
|
||||
"""
|
||||
Returns the operations you can perform on the wiki.
|
||||
"""
|
||||
return {
|
||||
"enable": True,
|
||||
"configure": True,
|
||||
}
|
||||
@@ -21,6 +21,17 @@ class WikiTab(EnrolledTab):
|
||||
is_hideable = True
|
||||
is_default = False
|
||||
|
||||
def __init__(self, tab_dict):
|
||||
# Default to hidden
|
||||
super().__init__({"is_hidden": True, **tab_dict})
|
||||
|
||||
def to_json(self):
|
||||
json_val = super().to_json()
|
||||
# Persist that the tab is *not* hidden
|
||||
if not self.is_hidden:
|
||||
json_val.update({"is_hidden": False})
|
||||
return json_val
|
||||
|
||||
@classmethod
|
||||
def is_enabled(cls, course, user=None):
|
||||
"""
|
||||
|
||||
@@ -4,10 +4,9 @@ Tests for wiki views.
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
from django.test.client import RequestFactory
|
||||
|
||||
from lms.djangoapps.courseware.tabs import get_course_tab_list
|
||||
from common.djangoapps.student.tests.factories import AdminFactory, UserFactory
|
||||
from lms.djangoapps.courseware.tabs import get_course_tab_list
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
@@ -21,19 +20,28 @@ class WikiTabTestCase(ModuleStoreTestCase):
|
||||
self.instructor = AdminFactory.create()
|
||||
self.user = UserFactory()
|
||||
|
||||
def _enable_wiki_tab(self):
|
||||
"""
|
||||
Enables the wiki tab globally and unhides it for the course.
|
||||
"""
|
||||
settings.WIKI_ENABLED = True
|
||||
# Enable the wiki tab for these tests
|
||||
for tab in self.course.tabs:
|
||||
if tab.type == 'wiki':
|
||||
tab.is_hidden = False
|
||||
self.course.save()
|
||||
|
||||
def get_wiki_tab(self, user, course):
|
||||
"""Returns true if the "Wiki" tab is shown."""
|
||||
request = RequestFactory().request()
|
||||
"""Returns wiki tab if it is shown."""
|
||||
all_tabs = get_course_tab_list(user, course)
|
||||
wiki_tabs = [tab for tab in all_tabs if tab.name == 'Wiki']
|
||||
return wiki_tabs[0] if len(wiki_tabs) == 1 else None
|
||||
return next((tab for tab in all_tabs if tab.type == 'wiki'), None)
|
||||
|
||||
def test_wiki_enabled_and_public(self):
|
||||
"""
|
||||
Test wiki tab when Enabled setting is True and the wiki is open to
|
||||
the public.
|
||||
"""
|
||||
settings.WIKI_ENABLED = True
|
||||
self._enable_wiki_tab()
|
||||
self.course.allow_public_wiki_access = True
|
||||
assert self.get_wiki_tab(self.user, self.course) is not None
|
||||
|
||||
@@ -41,20 +49,19 @@ class WikiTabTestCase(ModuleStoreTestCase):
|
||||
"""
|
||||
Test wiki when it is enabled but not open to the public
|
||||
"""
|
||||
settings.WIKI_ENABLED = True
|
||||
self._enable_wiki_tab()
|
||||
self.course.allow_public_wiki_access = False
|
||||
assert self.get_wiki_tab(self.user, self.course) is None
|
||||
assert self.get_wiki_tab(self.instructor, self.course) is not None
|
||||
|
||||
def test_wiki_enabled_false(self):
|
||||
"""Test wiki tab when Enabled setting is False"""
|
||||
settings.WIKI_ENABLED = False
|
||||
assert self.get_wiki_tab(self.user, self.course) is None
|
||||
assert self.get_wiki_tab(self.instructor, self.course) is None
|
||||
|
||||
def test_wiki_visibility(self):
|
||||
"""Test toggling of visibility of wiki tab"""
|
||||
settings.WIKI_ENABLED = True
|
||||
self._enable_wiki_tab()
|
||||
self.course.allow_public_wiki_access = True
|
||||
wiki_tab = self.get_wiki_tab(self.user, self.course)
|
||||
assert wiki_tab is not None
|
||||
@@ -63,3 +70,9 @@ class WikiTabTestCase(ModuleStoreTestCase):
|
||||
assert wiki_tab['is_hidden']
|
||||
wiki_tab['is_hidden'] = False
|
||||
assert not wiki_tab.is_hidden
|
||||
|
||||
def test_wiki_hidden_by_default(self):
|
||||
"""
|
||||
Test that the wiki tab is hidden by default
|
||||
"""
|
||||
assert self.get_wiki_tab(self.user, self.course) is None
|
||||
|
||||
@@ -426,7 +426,7 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, Mi
|
||||
self.client.logout()
|
||||
self.login(self.email, self.password)
|
||||
course_tab_list = get_course_tab_list(self.user, self.course)
|
||||
assert len(course_tab_list) == 5
|
||||
assert len(course_tab_list) == 4
|
||||
|
||||
def test_course_tabs_list_for_staff_members(self):
|
||||
"""
|
||||
@@ -438,7 +438,7 @@ class EntranceExamsTabsTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase, Mi
|
||||
staff_user = StaffFactory(course_key=self.course.id)
|
||||
self.client.login(username=staff_user.username, password='test')
|
||||
course_tab_list = get_course_tab_list(staff_user, self.course)
|
||||
assert len(course_tab_list) == 5
|
||||
assert len(course_tab_list) == 4
|
||||
|
||||
|
||||
class TextBookCourseViewsTestCase(LoginEnrollmentTestCase, SharedModuleStoreTestCase):
|
||||
|
||||
55
openedx/core/djangoapps/course_apps/tests/test_wiki_app.py
Normal file
55
openedx/core/djangoapps/course_apps/tests/test_wiki_app.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
Tests for wiki course app.
|
||||
"""
|
||||
|
||||
from common.djangoapps.student.tests.factories import AdminFactory, UserFactory
|
||||
from lms.djangoapps.course_wiki.plugins.course_app import WikiCourseApp
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_cms
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
@skip_unless_cms
|
||||
class WikiCourseAppTestCase(ModuleStoreTestCase):
|
||||
"""Test cases for Wiki CourseApp."""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.course = CourseFactory.create()
|
||||
self.instructor = AdminFactory.create()
|
||||
self.user = UserFactory()
|
||||
|
||||
def get_wiki_tab(self, course_key):
|
||||
"""
|
||||
Reload the course and fetch the wiki tab if present.
|
||||
"""
|
||||
course = self.store.get_course(course_key)
|
||||
return next((tab for tab in course.tabs if tab.type == 'wiki'), None)
|
||||
|
||||
def test_app_disabled_by_default(self):
|
||||
"""
|
||||
Test that the wiki tab is disabled by default.
|
||||
"""
|
||||
assert not WikiCourseApp.is_enabled(self.course.id)
|
||||
|
||||
def test_app_enabling(self):
|
||||
"""
|
||||
Test that enabling and disable the app enabled/disables the tab.
|
||||
"""
|
||||
WikiCourseApp.set_enabled(self.course.id, True, self.instructor)
|
||||
wiki_tab = self.get_wiki_tab(self.course.id)
|
||||
assert not wiki_tab.is_hidden
|
||||
WikiCourseApp.set_enabled(self.course.id, False, self.instructor)
|
||||
wiki_tab = self.get_wiki_tab(self.course.id)
|
||||
assert wiki_tab.is_hidden
|
||||
|
||||
def test_app_adds_wiki(self):
|
||||
"""
|
||||
Test that enabling the app for a course that doesn't have the wiki tab
|
||||
adds the wiki tab.
|
||||
"""
|
||||
self.course.tabs = [tab for tab in self.course.tabs if tab.type != 'wiki']
|
||||
self.store.update_item(self.course, self.instructor.id)
|
||||
assert self.get_wiki_tab(self.course.id) is None
|
||||
WikiCourseApp.set_enabled(self.course.id, True, self.instructor)
|
||||
assert self.get_wiki_tab(self.course.id) is not None
|
||||
@@ -155,7 +155,7 @@ class CourseApiTestViews(BaseCoursewareTests, MasqueradeMixin):
|
||||
enrollment = response.data['enrollment']
|
||||
assert enrollment_mode == enrollment['mode']
|
||||
assert enrollment['is_active']
|
||||
assert len(response.data['tabs']) == 6
|
||||
assert len(response.data['tabs']) == 5
|
||||
found = False
|
||||
for tab in response.data['tabs']:
|
||||
if tab['type'] == 'external_link':
|
||||
|
||||
2
setup.py
2
setup.py
@@ -46,7 +46,7 @@ setup(
|
||||
"progress = lms.djangoapps.courseware.plugins:ProgressCourseApp",
|
||||
"teams = lms.djangoapps.teams.plugins:TeamsCourseApp",
|
||||
"textbooks = lms.djangoapps.courseware.plugins:TextbooksCourseApp",
|
||||
"wiki = lms.djangoapps.course_wiki.plugins:WikiCourseApp",
|
||||
"wiki = lms.djangoapps.course_wiki.plugins.course_app:WikiCourseApp",
|
||||
"custom_pages = lms.djangoapps.courseware.plugins:CustomPagesCourseApp",
|
||||
],
|
||||
"openedx.course_tool": [
|
||||
|
||||
Reference in New Issue
Block a user