diff --git a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py index 9aa9a7cc72aa..65d45bf0b206 100644 --- a/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py +++ b/cms/djangoapps/contentstore/management/commands/edit_course_tabs.py @@ -12,7 +12,7 @@ from courseware.courses import get_course_by_id -from xmodule.tabs import primitive_insert, primitive_delete +from contentstore.views import tabs from opaque_keys import InvalidKeyError from opaque_keys.edx.locations import SlashSeparatedCourseKey from opaque_keys.edx.keys import CourseKey @@ -25,6 +25,7 @@ def print_course(course): for index, item in enumerate(course.tabs): print index + 1, '"' + item.get('type') + '"', '"' + item.get('name', '') + '"' + # course.tabs looks like this # [{u'type': u'courseware'}, {u'type': u'course_info', u'name': u'Course Info'}, {u'type': u'textbooks'}, # {u'type': u'discussion', u'name': u'Discussion'}, {u'type': u'wiki', u'name': u'Wiki'}, @@ -83,7 +84,7 @@ def handle(self, *args, **options): raise CommandError(Command.delete_option.help) num = int(args[0]) if query_yes_no('Deleting tab {0} Confirm?'.format(num), default='no'): - primitive_delete(course, num - 1) # -1 for 0-based indexing + tabs.primitive_delete(course, num - 1) # -1 for 0-based indexing elif options['insert']: if len(args) != 3: raise CommandError(Command.insert_option.help) @@ -91,7 +92,7 @@ def handle(self, *args, **options): tab_type = args[1] name = args[2] if query_yes_no('Inserting tab {0} "{1}" "{2}" Confirm?'.format(num, tab_type, name), default='no'): - primitive_insert(course, num - 1, tab_type, name) # -1 as above + tabs.primitive_insert(course, num - 1, tab_type, name) # -1 as above except ValueError as e: # Cute: translate to CommandError so the CLI error prints nicely. raise CommandError(e) diff --git a/cms/djangoapps/contentstore/views/tabs.py b/cms/djangoapps/contentstore/views/tabs.py index 1bc54381d648..f79d4d07211b 100644 --- a/cms/djangoapps/contentstore/views/tabs.py +++ b/cms/djangoapps/contentstore/views/tabs.py @@ -12,6 +12,7 @@ from edxmako.shortcuts import render_to_response from xmodule.modulestore.django import modulestore +from xmodule.modulestore import ModuleStoreEnum from xmodule.tabs import CourseTabList, CourseTab, InvalidTabsException, StaticTab from opaque_keys.edx.keys import CourseKey, UsageKey @@ -167,3 +168,36 @@ def get_tab_by_locator(tab_list, usage_key_string): url_slug=item.location.name, ) return CourseTabList.get_tab_by_id(tab_list, static_tab.tab_id) + + +# "primitive" tab edit functions driven by the command line. +# These should be replaced/deleted by a more capable GUI someday. +# Note that the command line UI identifies the tabs with 1-based +# indexing, but this implementation code is standard 0-based. + +def validate_args(num, tab_type): + "Throws for the disallowed cases." + if num <= 1: + raise ValueError('Tabs 1 and 2 cannot be edited') + if tab_type == 'static_tab': + raise ValueError('Tabs of type static_tab cannot be edited here (use Studio)') + + +def primitive_delete(course, num): + "Deletes the given tab number (0 based)." + tabs = course.tabs + validate_args(num, tabs[num].get('type', '')) + del tabs[num] + # Note for future implementations: if you delete a static_tab, then Chris Dodge + # points out that there's other stuff to delete beyond this element. + # This code happens to not delete static_tab so it doesn't come up. + modulestore().update_item(course, ModuleStoreEnum.UserID.primitive_command) + + +def primitive_insert(course, num, tab_type, name): + "Inserts a new tab at the given number (0 based)." + validate_args(num, tab_type) + new_tab = CourseTab.from_json({u'type': unicode(tab_type), u'name': unicode(name)}) + tabs = course.tabs + tabs.insert(num, new_tab) + modulestore().update_item(course, ModuleStoreEnum.UserID.primitive_command) diff --git a/cms/djangoapps/contentstore/views/tests/test_tabs.py b/cms/djangoapps/contentstore/views/tests/test_tabs.py index 8fa631f8c44a..2ef15a481d41 100644 --- a/cms/djangoapps/contentstore/views/tests/test_tabs.py +++ b/cms/djangoapps/contentstore/views/tests/test_tabs.py @@ -1,7 +1,7 @@ """ Tests for tab functions (just primitive). """ import json -from xmodule.tabs import primitive_insert, primitive_delete +from contentstore.views import tabs from contentstore.tests.utils import CourseTestCase from contentstore.utils import reverse_course_url from xmodule.x_module import STUDENT_VIEW @@ -198,12 +198,12 @@ def test_delete(self): """Test primitive tab deletion.""" course = CourseFactory.create() with self.assertRaises(ValueError): - primitive_delete(course, 0) + tabs.primitive_delete(course, 0) with self.assertRaises(ValueError): - primitive_delete(course, 1) + tabs.primitive_delete(course, 1) with self.assertRaises(IndexError): - primitive_delete(course, 6) - primitive_delete(course, 2) + tabs.primitive_delete(course, 6) + tabs.primitive_delete(course, 2) self.assertFalse({u'type': u'textbooks'} in course.tabs) # Check that discussion has shifted up self.assertEquals(course.tabs[2], {'type': 'discussion', 'name': 'Discussion'}) @@ -211,16 +211,16 @@ def test_delete(self): def test_insert(self): """Test primitive tab insertion.""" course = CourseFactory.create() - primitive_insert(course, 2, 'notes', 'aname') + tabs.primitive_insert(course, 2, 'notes', 'aname') self.assertEquals(course.tabs[2], {'type': 'notes', 'name': 'aname'}) with self.assertRaises(ValueError): - primitive_insert(course, 0, 'notes', 'aname') + tabs.primitive_insert(course, 0, 'notes', 'aname') with self.assertRaises(ValueError): - primitive_insert(course, 3, 'static_tab', 'aname') + tabs.primitive_insert(course, 3, 'static_tab', 'aname') def test_save(self): """Test course saving.""" course = CourseFactory.create() - primitive_insert(course, 3, 'notes', 'aname') + tabs.primitive_insert(course, 3, 'notes', 'aname') course2 = modulestore().get_course(course.id) self.assertEquals(course2.tabs[3], {'type': 'notes', 'name': 'aname'}) diff --git a/common/lib/xmodule/xmodule/tabs.py b/common/lib/xmodule/xmodule/tabs.py index 6cc792b249af..08548d281721 100644 --- a/common/lib/xmodule/xmodule/tabs.py +++ b/common/lib/xmodule/xmodule/tabs.py @@ -6,8 +6,6 @@ import logging from xblock.fields import List -from xmodule.modulestore.django import modulestore -from xmodule.modulestore import ModuleStoreEnum from openedx.core.lib.api.plugins import PluginError # We should only scrape strings for i18n in this file, since the target language is known only when @@ -531,32 +529,3 @@ class UnequalTabsException(Exception): A complaint about tab lists being unequal """ pass - - -# Tab functions -def validate_args(num, tab_type): - "Throws for the disallowed cases." - if num <= 1: - raise ValueError('Tabs 1 and 2 cannot be edited') - if tab_type == 'static_tab': - raise ValueError('Tabs of type static_tab cannot be edited here (use Studio)') - - -def primitive_delete(course, num): - "Deletes the given tab number (0 based)." - tabs = course.tabs - validate_args(num, tabs[num].get('type', '')) - del tabs[num] - # Note for future implementations: if you delete a static_tab, then Chris Dodge - # points out that there's other stuff to delete beyond this element. - # This code happens to not delete static_tab so it doesn't come up. - modulestore().update_item(course, ModuleStoreEnum.UserID.primitive_command) - - -def primitive_insert(course, num, tab_type, name): - "Inserts a new tab at the given number (0 based)." - validate_args(num, tab_type) - new_tab = CourseTab.from_json({u'type': unicode(tab_type), u'name': unicode(name)}) - tabs = course.tabs - tabs.insert(num, new_tab) - modulestore().update_item(course, ModuleStoreEnum.UserID.primitive_command) diff --git a/lms/djangoapps/dashboard/sysadmin.py b/lms/djangoapps/dashboard/sysadmin.py index 855b13c60509..090c9584e350 100644 --- a/lms/djangoapps/dashboard/sysadmin.py +++ b/lms/djangoapps/dashboard/sysadmin.py @@ -38,7 +38,6 @@ import dashboard.git_import as git_import from django_comment_client.management_utils import rename_user as rename_user_util from dashboard.git_import import GitImportError -from dashboard.sysadmin_extensions import sysadmin_course_tabs from dashboard.models import CourseImportLog from external_auth.models import ExternalAuthMap from external_auth.views import generate_password @@ -382,48 +381,6 @@ def post(self, request): return render_to_response(self.template_name, context) -class CourseTabs(SysadminDashboardView): - """ - Handles rendering the view and processing requests for Edit Course Tabs - """ - - def get(self, request): - """ - Displays the form for Edit Course Tabs - """ - - if not request.user.is_superuser: - raise Http404 - - context = { - 'msg': self.msg, - 'djangopid': os.getpid(), - 'modeflag': {'course_tabs': 'active-section'}, - 'edx_platform_version': getattr(settings, 'EDX_PLATFORM_VERSION_STRING', ''), - } - return render_to_response(self.template_name, context) - - def post(self, request): - """Handle requests to Edit Course Tabs""" - - if not request.user.is_superuser: - raise Http404 - - action = request.POST.get('action', '') - track.views.server_track(request, action, {}, page='course_tabs_sysdashboard') - - if action in ['get_current_tabs', 'delete_tab', 'insert_tab']: - self.msg = sysadmin_course_tabs.process_request(action, request) - - context = { - 'msg': self.msg, - 'djangopid': os.getpid(), - 'modeflag': {'course_tabs': 'active-section'}, - 'edx_platform_version': getattr(settings, 'EDX_PLATFORM_VERSION_STRING', ''), - } - return render_to_response(self.template_name, context) - - class Courses(SysadminDashboardView): """ This manages adding/updating courses from git, deleting courses, and @@ -637,7 +594,6 @@ def post(self, request): page='courses_sysdashboard') courses = {course.id: course for course in self.get_courses()} - if action == 'add_course': gitloc = request.POST.get('repo_location', '').strip().replace(' ', '').replace(';', '') branch = request.POST.get('repo_branch', '').strip().replace(' ', '').replace(';', '') diff --git a/lms/djangoapps/dashboard/sysadmin_extensions/__init__.py b/lms/djangoapps/dashboard/sysadmin_extensions/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/lms/djangoapps/dashboard/sysadmin_extensions/sysadmin_course_tabs.py b/lms/djangoapps/dashboard/sysadmin_extensions/sysadmin_course_tabs.py deleted file mode 100644 index 7ccb11ed11df..000000000000 --- a/lms/djangoapps/dashboard/sysadmin_extensions/sysadmin_course_tabs.py +++ /dev/null @@ -1,110 +0,0 @@ -"""Helper module that processes edit_course_tabs requests""" -from django.utils.translation import ugettext as _ - -from courseware.courses import get_course_by_id -from opaque_keys.edx import locator -from opaque_keys import InvalidKeyError -from xmodule.tabs import primitive_insert, primitive_delete -from xmodule.tabs import InvalidTabsException - - -def process_request(action, request): - """Routes requests to the appropriate helper function""" - - course_id = request.POST.get('course_id', '').strip() - if action == 'get_current_tabs': - title = _('Current Tabs:') - message = get_current_tabs(course_id) - elif action == 'delete_tab': - title = _('Delete Tab Status:') - delete_tab_args = request.POST.get('tab_delete', '').strip() - message = delete_tab(course_id, delete_tab_args) - elif action == 'insert_tab': - title = _('Insert Tab Status:') - insert_tab_args = request.POST.get('tab_insert', '').strip() - message = insert_tab(course_id, insert_tab_args) - return u"
{message}
".format( - title=title, - message=message, - ) - - -def get_current_tabs(course_id): - """Displays a list of tabs for the given course""" - - try: - course_key = locator.CourseLocator.from_string(course_id) - course = get_course_by_id(course_key) - except InvalidKeyError: - message = _('Error - Invalid Course ID') - else: - # Translators: number, type, and name refer to tab number, tab type, and tab name - message = _('number, type, name') - for index, item in enumerate(course.tabs): - message += "