From b0f9fd0df51160011ff886eed24bbd36ecda74cf Mon Sep 17 00:00:00 2001 From: Jason Bau Date: Sat, 31 Aug 2013 01:07:34 -0700 Subject: [PATCH 1/3] Add link in lms legacy instructor dashboard to cms course_index A one-click way of getting to editing the course --- lms/djangoapps/courseware/courses.py | 18 +++++++++++++++++- .../courseware/tests/test_courses.py | 10 +++++++++- lms/djangoapps/instructor/views/legacy.py | 15 +++++++++++---- lms/envs/aws.py | 2 ++ lms/envs/common.py | 3 +++ .../courseware/instructor_dashboard.html | 9 +++++++-- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index 092a0be8c6..b998d7eb11 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -2,10 +2,11 @@ from collections import defaultdict from fs.errors import ResourceNotFoundError import logging import inspect +import re from path import path from django.http import Http404 - +from django.conf import settings from .module_render import get_module from xmodule.course_module import CourseDescriptor from xmodule.modulestore import Location, XML_MODULESTORE_TYPE @@ -294,3 +295,18 @@ def sort_by_announcement(courses): courses = sorted(courses, key=key) return courses + +def get_cms_course_link_by_id(course_id): + """ + Returns a proto-relative link to course_index for editing the course in cms, assuming that the course is actually + cms-backed. If course_id is improperly formatted, just return the root of the cms + """ + format_str = r'^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$' + host = "//{}/".format(settings.CMS_BASE) # protocol-relative + m = re.match(format_str, course_id) + if m: + return "{host}{org}/{course}/course/{name}".format(host=host, + org=m.group('org'), + course=m.group('course'), + name=m.group('name')) + return host diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 60594602a4..6bba730100 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from django.test import TestCase from django.http import Http404 -from courseware.courses import get_course_by_id +from courseware.courses import get_course_by_id, get_cms_course_link_by_id class CoursesTest(TestCase): def test_get_course_by_id_invalid_chars(self): @@ -14,3 +14,11 @@ class CoursesTest(TestCase): get_course_by_id('MITx/foobar/statistics=introduction') get_course_by_id('MITx/foobar/business and management') get_course_by_id('MITx/foobar/NiñøJoséMaríáßç') + + def test_get_cms_course_link_by_id(self): + """ + Tests that get_cms_course_link_by_id returns the right thing + """ + self.assertEqual("//localhost:8001/", get_cms_course_link_by_id("blah_bad_course_id")) + self.assertEqual("//localhost:8001/", get_cms_course_link_by_id("too/too/many/slashes")) + self.assertEqual("//localhost:8001/org/num/course/name", get_cms_course_link_by_id('org/num/name')) \ No newline at end of file diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py index b9295557d7..3dfa0e85f9 100644 --- a/lms/djangoapps/instructor/views/legacy.py +++ b/lms/djangoapps/instructor/views/legacy.py @@ -33,7 +33,7 @@ from xmodule.html_module import HtmlDescriptor from courseware import grades from courseware.access import (has_access, get_access_group_name, course_beta_test_group_name) -from courseware.courses import get_course_with_access +from courseware.courses import get_course_with_access, get_cms_course_link_by_id from courseware.models import StudentModule from django_comment_common.models import (Role, FORUM_ROLE_ADMINISTRATOR, @@ -799,16 +799,23 @@ def instructor_dashboard(request, course_id): else: email_editor = None + # determine if this is a studio-backed course so we can 1) provide a link to edit this course in studio + # 2) enable course email + studio_url = None + is_studio_course = modulestore().get_modulestore_type(course_id) == MONGO_MODULESTORE_TYPE + if is_studio_course: + studio_url = get_cms_course_link_by_id(course_id) + # Flag for whether or not we display the email tab (depending upon # what backing store this course using (Mongo vs. XML)) - if settings.MITX_FEATURES['ENABLE_INSTRUCTOR_EMAIL'] and \ - modulestore().get_modulestore_type(course_id) == MONGO_MODULESTORE_TYPE: + if settings.MITX_FEATURES['ENABLE_INSTRUCTOR_EMAIL'] and is_studio_course: show_email_tab = True # display course stats only if there is no other table to display: course_stats = None if not datatable: course_stats = get_course_stats_table() + #---------------------------------------- # context for rendering @@ -821,6 +828,7 @@ def instructor_dashboard(request, course_id): 'course_stats': course_stats, 'msg': msg, 'modeflag': {idash_mode: 'selectedmode'}, + 'studio_url': studio_url, 'to_option': email_to_option, # email 'subject': email_subject, # email @@ -843,7 +851,6 @@ def instructor_dashboard(request, course_id): return render_to_response('courseware/instructor_dashboard.html', context) - def _do_remote_gradebook(user, course, action, args=None, files=None): ''' Perform remote gradebook action. Returns msg, datatable. diff --git a/lms/envs/aws.py b/lms/envs/aws.py index a22fbc5bb6..35275036e5 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -111,6 +111,8 @@ SITE_NAME = ENV_TOKENS['SITE_NAME'] SESSION_ENGINE = ENV_TOKENS.get('SESSION_ENGINE', SESSION_ENGINE) SESSION_COOKIE_DOMAIN = ENV_TOKENS.get('SESSION_COOKIE_DOMAIN') +CMS_BASE = ENV_TOKENS.get('CMS_BASE', 'studio.edx.org') + # allow for environments to specify what cookie name our login subsystem should use # this is to fix a bug regarding simultaneous logins between edx.org and edge.edx.org which can # happen with some browsers (e.g. Firefox) diff --git a/lms/envs/common.py b/lms/envs/common.py index 9d886f8dc1..5bd9cdc5d5 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -353,6 +353,9 @@ DEBUG = False TEMPLATE_DEBUG = False USE_TZ = True +# CMS base +CMS_BASE = 'localhost:8001' + # Site info SITE_ID = 1 SITE_NAME = "edx.org" diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html index fae76cca93..35b37dc291 100644 --- a/lms/templates/courseware/instructor_dashboard.html +++ b/lms/templates/courseware/instructor_dashboard.html @@ -109,7 +109,7 @@ function goto( mode)
%if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'): - + %endif
@@ -125,11 +125,16 @@ function goto( mode) ${_("DataDump")} | ${_("Manage Groups")} %if show_email_tab: - | Email + | ${_("Email")} %endif %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_ANALYTICS'): | ${_("Analytics")} %endif + %if studio_url: + ## not checking access because if user can see this, they are at least course staff (with studio edit access) + | ${_('Edit Course')} + %endif + ] From 577aeed35a92de1906e920e96afe102623a8743c Mon Sep 17 00:00:00 2001 From: Sarina Canelake Date: Wed, 4 Sep 2013 11:31:52 -0400 Subject: [PATCH 2/3] Don't fetch the editor for XML courses --- lms/djangoapps/instructor/views/legacy.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py index 3dfa0e85f9..bcf2910582 100644 --- a/lms/djangoapps/instructor/views/legacy.py +++ b/lms/djangoapps/instructor/views/legacy.py @@ -792,17 +792,17 @@ def instructor_dashboard(request, course_id): else: instructor_tasks = None - # HTML editor for email - if idash_mode == 'Email': - html_module = HtmlDescriptor(course.system, {'data': html_message}) - email_editor = wrap_xmodule(html_module.get_html, html_module, 'xmodule_edit.html')() - else: - email_editor = None - # determine if this is a studio-backed course so we can 1) provide a link to edit this course in studio # 2) enable course email - studio_url = None is_studio_course = modulestore().get_modulestore_type(course_id) == MONGO_MODULESTORE_TYPE + + email_editor = None + # HTML editor for email + if idash_mode == 'Email' and is_studio_course: + html_module = HtmlDescriptor(course.system, {'data': html_message}) + email_editor = wrap_xmodule(html_module.get_html, html_module, 'xmodule_edit.html')() + + studio_url = None if is_studio_course: studio_url = get_cms_course_link_by_id(course_id) From ec989e499962b32d6c46ae56384e777d3171d892 Mon Sep 17 00:00:00 2001 From: Jason Bau Date: Wed, 4 Sep 2013 11:29:22 -0700 Subject: [PATCH 3/3] Address review comments for lms_link_to_cms * Uses override_settings to provide test variable * Move location of cms link to upper right * PEP8 / Pylink --- lms/djangoapps/courseware/courses.py | 13 +++++++------ lms/djangoapps/courseware/tests/test_courses.py | 10 +++++++--- lms/static/sass/course/instructor/_instructor.scss | 6 ++++++ lms/templates/courseware/instructor_dashboard.html | 10 +++++----- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index b998d7eb11..b39e2d6315 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -296,17 +296,18 @@ def sort_by_announcement(courses): return courses + def get_cms_course_link_by_id(course_id): """ Returns a proto-relative link to course_index for editing the course in cms, assuming that the course is actually cms-backed. If course_id is improperly formatted, just return the root of the cms """ format_str = r'^(?P[^/]+)/(?P[^/]+)/(?P[^/]+)$' - host = "//{}/".format(settings.CMS_BASE) # protocol-relative - m = re.match(format_str, course_id) - if m: + host = "//{}/".format(settings.CMS_BASE) # protocol-relative + m_obj = re.match(format_str, course_id) + if m_obj: return "{host}{org}/{course}/course/{name}".format(host=host, - org=m.group('org'), - course=m.group('course'), - name=m.group('name')) + org=m_obj.group('org'), + course=m_obj.group('course'), + name=m_obj.group('name')) return host diff --git a/lms/djangoapps/courseware/tests/test_courses.py b/lms/djangoapps/courseware/tests/test_courses.py index 6bba730100..20cb83a411 100644 --- a/lms/djangoapps/courseware/tests/test_courses.py +++ b/lms/djangoapps/courseware/tests/test_courses.py @@ -1,8 +1,11 @@ # -*- coding: utf-8 -*- from django.test import TestCase from django.http import Http404 +from django.test.utils import override_settings from courseware.courses import get_course_by_id, get_cms_course_link_by_id +CMS_BASE_TEST = 'testcms' + class CoursesTest(TestCase): def test_get_course_by_id_invalid_chars(self): """ @@ -15,10 +18,11 @@ class CoursesTest(TestCase): get_course_by_id('MITx/foobar/business and management') get_course_by_id('MITx/foobar/NiñøJoséMaríáßç') + @override_settings(CMS_BASE=CMS_BASE_TEST) def test_get_cms_course_link_by_id(self): """ Tests that get_cms_course_link_by_id returns the right thing """ - self.assertEqual("//localhost:8001/", get_cms_course_link_by_id("blah_bad_course_id")) - self.assertEqual("//localhost:8001/", get_cms_course_link_by_id("too/too/many/slashes")) - self.assertEqual("//localhost:8001/org/num/course/name", get_cms_course_link_by_id('org/num/name')) \ No newline at end of file + self.assertEqual("//{}/".format(CMS_BASE_TEST), get_cms_course_link_by_id("blah_bad_course_id")) + self.assertEqual("//{}/".format(CMS_BASE_TEST), get_cms_course_link_by_id("too/too/many/slashes")) + self.assertEqual("//{}/org/num/course/name".format(CMS_BASE_TEST), get_cms_course_link_by_id('org/num/name')) diff --git a/lms/static/sass/course/instructor/_instructor.scss b/lms/static/sass/course/instructor/_instructor.scss index eee4afffc6..6ec7f617ab 100644 --- a/lms/static/sass/course/instructor/_instructor.scss +++ b/lms/static/sass/course/instructor/_instructor.scss @@ -8,6 +8,12 @@ right: 2em; } + .studio-edit-link{ + position: absolute; + top: 3.5em; + right: 2em; + } + section.instructor-dashboard-content { @extend .content; padding: 40px; diff --git a/lms/templates/courseware/instructor_dashboard.html b/lms/templates/courseware/instructor_dashboard.html index 35b37dc291..effa5852d8 100644 --- a/lms/templates/courseware/instructor_dashboard.html +++ b/lms/templates/courseware/instructor_dashboard.html @@ -111,6 +111,11 @@ function goto( mode) %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_BETA_DASHBOARD'): %endif + %if studio_url: + ## not checking access because if user can see this, they are at least course staff (with studio edit access) + + %endif +

${_("Instructor Dashboard")}

@@ -130,11 +135,6 @@ function goto( mode) %if settings.MITX_FEATURES.get('ENABLE_INSTRUCTOR_ANALYTICS'): | ${_("Analytics")} %endif - %if studio_url: - ## not checking access because if user can see this, they are at least course staff (with studio edit access) - | ${_('Edit Course')} - %endif - ]