From bb09fdb7bec87ff7a1d1640ddb03ecd423719fbc Mon Sep 17 00:00:00 2001 From: Dmitry Viskov Date: Fri, 1 Jul 2016 14:28:06 +0300 Subject: [PATCH] Ability to hide Pages from students --- cms/djangoapps/contentstore/views/item.py | 13 +++++++-- common/lib/xmodule/xmodule/html_module.py | 7 +++++ common/lib/xmodule/xmodule/modulestore/xml.py | 1 + common/lib/xmodule/xmodule/tabs.py | 10 ++++++- .../lib/xmodule/xmodule/tests/test_import.py | 15 ++++++++++ common/test/data/toy/policies/2012_Fall.json | 2 +- lms/djangoapps/courseware/tabs.py | 6 +++- lms/djangoapps/courseware/tests/test_tabs.py | 29 +++++++++++++++++++ 8 files changed, 77 insertions(+), 6 deletions(-) diff --git a/cms/djangoapps/contentstore/views/item.py b/cms/djangoapps/contentstore/views/item.py index 0004a13111..3a76963d55 100644 --- a/cms/djangoapps/contentstore/views/item.py +++ b/cms/djangoapps/contentstore/views/item.py @@ -546,9 +546,16 @@ def _save_xblock(user, xblock, data=None, children_strings=None, metadata=None, # find the course's reference to this tab and update the name. static_tab = CourseTabList.get_tab_by_slug(course.tabs, xblock.location.name) # only update if changed - if static_tab and static_tab['name'] != xblock.display_name: - static_tab['name'] = xblock.display_name - store.update_item(course, user.id) + if static_tab: + update_tab = False + if static_tab['name'] != xblock.display_name: + static_tab['name'] = xblock.display_name + update_tab = True + if static_tab['course_staff_only'] != xblock.course_staff_only: + static_tab['course_staff_only'] = xblock.course_staff_only + update_tab = True + if update_tab: + store.update_item(course, user.id) result = { 'id': unicode(xblock.location), diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py index c93351dbaa..70a09357e4 100644 --- a/common/lib/xmodule/xmodule/html_module.py +++ b/common/lib/xmodule/xmodule/html_module.py @@ -368,6 +368,13 @@ class StaticTabFields(object): scope=Scope.settings, default="Empty", ) + course_staff_only = Boolean( + display_name=_("Hide Page From Learners"), + help=_("If you select this option, only course team members with" + " the Staff or Admin role see this page."), + default=False, + scope=Scope.settings + ) data = String( default=textwrap.dedent(u"""\

Add the content you want students to see on this page.

diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py index e839206250..1421beb118 100644 --- a/common/lib/xmodule/xmodule/modulestore/xml.py +++ b/common/lib/xmodule/xmodule/modulestore/xml.py @@ -730,6 +730,7 @@ class XMLModuleStore(ModuleStoreReadBase): tab = CourseTabList.get_tab_by_slug(tab_list=course_descriptor.tabs, url_slug=slug) if tab: module.display_name = tab.name + module.course_staff_only = tab.course_staff_only module.data_dir = course_dir module.save() diff --git a/common/lib/xmodule/xmodule/tabs.py b/common/lib/xmodule/xmodule/tabs.py index 480c850d2b..3b34597f6f 100644 --- a/common/lib/xmodule/xmodule/tabs.py +++ b/common/lib/xmodule/xmodule/tabs.py @@ -58,6 +58,9 @@ class CourseTab(object): # If there is a single view associated with this tab, this is the name of it view_name = None + # True if this tab should be displayed only for instructors + course_staff_only = False + def __init__(self, tab_dict): """ Initializes class members with values passed in by subclasses. @@ -69,6 +72,7 @@ class CourseTab(object): self.name = tab_dict.get('name', self.title) self.tab_id = tab_dict.get('tab_id', getattr(self, 'tab_id', self.type)) self.link_func = tab_dict.get('link_func', link_reverse_func(self.view_name)) + self.course_staff_only = tab_dict.get('course_staff_only', False) self.is_hidden = tab_dict.get('is_hidden', False) @@ -105,6 +109,8 @@ class CourseTab(object): return self.tab_id elif key == 'is_hidden': return self.is_hidden + elif key == 'course_staff_only': + return self.course_staff_only else: raise KeyError('Key {0} not present in tab {1}'.format(key, self.to_json())) @@ -121,6 +127,8 @@ class CourseTab(object): self.tab_id = value elif key == 'is_hidden': self.is_hidden = value + elif key == 'course_staff_only': + self.course_staff_only = value else: raise KeyError('Key {0} cannot be set in tab {1}'.format(key, self.to_json())) @@ -179,7 +187,7 @@ class CourseTab(object): Returns: a dictionary with keys for the properties of the CourseTab object. """ - to_json_val = {'type': self.type, 'name': self.name} + to_json_val = {'type': self.type, 'name': self.name, 'course_staff_only': self.course_staff_only} if self.is_hidden: to_json_val.update({'is_hidden': True}) return to_json_val diff --git a/common/lib/xmodule/xmodule/tests/test_import.py b/common/lib/xmodule/xmodule/tests/test_import.py index 54a7a662c1..f557d7959a 100644 --- a/common/lib/xmodule/xmodule/tests/test_import.py +++ b/common/lib/xmodule/xmodule/tests/test_import.py @@ -476,6 +476,21 @@ class ImportTestCase(BaseCourseTestCase): # appropriate attribute maps -- 'graded' should be True, not 'true' self.assertEqual(toy.graded, True) + def test_static_tabs_import(self): + """Make sure that the static tabs are imported correctly""" + + modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy']) + + location_tab_syllabus = Location("edX", "toy", "2012_Fall", "static_tab", "syllabus", None) + toy_tab_syllabus = modulestore.get_item(location_tab_syllabus) + self.assertEqual(toy_tab_syllabus.display_name, 'Syllabus') + self.assertEqual(toy_tab_syllabus.course_staff_only, False) + + location_tab_resources = Location("edX", "toy", "2012_Fall", "static_tab", "resources", None) + toy_tab_resources = modulestore.get_item(location_tab_resources) + self.assertEqual(toy_tab_resources.display_name, 'Resources') + self.assertEqual(toy_tab_resources.course_staff_only, True) + def test_definition_loading(self): """When two courses share the same org and course name and both have a module with the same url_name, the definitions shouldn't clash. diff --git a/common/test/data/toy/policies/2012_Fall.json b/common/test/data/toy/policies/2012_Fall.json index cfa5014a9b..d251cee109 100644 --- a/common/test/data/toy/policies/2012_Fall.json +++ b/common/test/data/toy/policies/2012_Fall.json @@ -8,7 +8,7 @@ {"type": "courseware"}, {"type": "course_info", "name": "Course Info"}, {"type": "static_tab", "url_slug": "syllabus", "name": "Syllabus"}, - {"type": "static_tab", "url_slug": "resources", "name": "Resources"}, + {"type": "static_tab", "url_slug": "resources", "name": "Resources", "course_staff_only": true}, {"type": "discussion", "name": "Discussion"}, {"type": "wiki", "name": "Wiki"}, {"type": "progress", "name": "Progress"} diff --git a/lms/djangoapps/courseware/tabs.py b/lms/djangoapps/courseware/tabs.py index 721c967be0..c83ae1978b 100644 --- a/lms/djangoapps/courseware/tabs.py +++ b/lms/djangoapps/courseware/tabs.py @@ -9,6 +9,7 @@ from courseware.access import has_access from courseware.entrance_exams import user_must_complete_entrance_exam from openedx.core.lib.course_tabs import CourseTabPluginManager from student.models import CourseEnrollment +from student.roles import CourseStaffRole from xmodule.tabs import CourseTab, CourseTabList, key_checker @@ -299,9 +300,12 @@ def get_course_tab_list(request, course): if must_complete_ee: # Hide all of the tabs except for 'Courseware' # Rename 'Courseware' tab to 'Entrance Exam' - if tab.type is not 'courseware': + if tab.type != 'courseware': continue tab.name = _("Entrance Exam") + if tab.type == 'static_tab' and tab.course_staff_only and \ + not bool(user and CourseStaffRole(course.id).has_user(user)): + continue course_tab_list.append(tab) # Add in any dynamic tabs, i.e. those that are not persisted diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 2f814bb746..e3039f08e7 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -686,6 +686,35 @@ class CourseTabListTestCase(TabListTestCase): # get tab by id self.assertEquals(xmodule_tabs.CourseTabList.get_tab_by_id(self.course.tabs, tab.tab_id), tab) + def test_course_tabs_staff_only(self): + """ + Tests the static tabs that available only for instructor + """ + self.course.tabs.append(xmodule_tabs.CourseTab.load('static_tab', name='Static Tab Free', + url_slug='extra_tab_1', + course_staff_only=False)) + self.course.tabs.append(xmodule_tabs.CourseTab.load('static_tab', name='Static Tab Instructors Only', + url_slug='extra_tab_2', + course_staff_only=True)) + self.course.save() + + user = self.create_mock_user(is_authenticated=True, is_staff=False, is_enrolled=True) + request = get_request_for_user(user) + course_tab_list = get_course_tab_list(request, self.course) + name_list = [x.name for x in course_tab_list] + self.assertIn('Static Tab Free', name_list) + self.assertNotIn('Static Tab Instructors Only', name_list) + + # Login as member of staff + self.client.logout() + staff_user = StaffFactory(course_key=self.course.id) + self.client.login(username=staff_user.username, password='test') + request = get_request_for_user(staff_user) + course_tab_list_staff = get_course_tab_list(request, self.course) + name_list_staff = [x.name for x in course_tab_list_staff] + self.assertIn('Static Tab Free', name_list_staff) + self.assertIn('Static Tab Instructors Only', name_list_staff) + @attr(shard=1) class ProgressTestCase(TabTestCase):