From bcbd1464d4244b93a1306991036b0ba7108e9d6c Mon Sep 17 00:00:00 2001 From: Zia Fazal Date: Wed, 24 Jun 2015 14:40:52 +0500 Subject: [PATCH 001/104] New course cannot be started till web certificate is active fixed broken test changes based on feedback on 6/24 fixed broken unit test after feedback changes added more checks and updated tests fixed broken bok choy test Fixed pylint quality error trying to fix pylint quality error --- .../tests/test_course_settings.py | 36 +++++++++++++++++++ cms/djangoapps/contentstore/utils.py | 19 ++++++++++ .../models/settings/course_details.py | 6 ++-- .../js/models/settings/course_details.js | 15 +++++--- .../js/spec/views/settings/main_spec.js | 10 +++++- cms/static/js/utils/date_utils.js | 22 +++++++++++- .../student/tests/test_certificates.py | 8 ++++- common/djangoapps/student/views.py | 8 +++-- common/lib/xmodule/xmodule/course_module.py | 6 ++++ .../pages/studio/settings_advanced.py | 1 + .../tests/lms/test_certificate_web_view.py | 5 ++- lms/djangoapps/certificates/api.py | 9 +++-- lms/djangoapps/certificates/tests/test_api.py | 1 + .../certificates/tests/test_views.py | 5 +++ lms/djangoapps/certificates/views.py | 5 +-- lms/djangoapps/courseware/tests/test_views.py | 1 + lms/djangoapps/courseware/views.py | 2 +- 17 files changed, 142 insertions(+), 17 deletions(-) diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py index 31afe010d5..2f720a14c2 100644 --- a/cms/djangoapps/contentstore/tests/test_course_settings.py +++ b/cms/djangoapps/contentstore/tests/test_course_settings.py @@ -52,6 +52,7 @@ class CourseDetailsTestCase(CourseTestCase): self.assertIsNone(details.intro_video, "intro_video somehow initialized" + str(details.intro_video)) self.assertIsNone(details.effort, "effort somehow initialized" + str(details.effort)) self.assertIsNone(details.language, "language somehow initialized" + str(details.language)) + self.assertIsNone(details.has_cert_config) def test_encoder(self): details = CourseDetails.fetch(self.course.id) @@ -1008,6 +1009,41 @@ class CourseMetadataEditingTest(CourseTestCase): tab_list.append(self.notes_tab) self.assertEqual(tab_list, course.tabs) + @override_settings(FEATURES={'CERTIFICATES_HTML_VIEW': True}) + def test_web_view_certifcate_configuration_settings(self): + """ + Test that has_cert_config is updated based on cert_html_view_enabled setting. + """ + test_model = CourseMetadata.update_from_json( + self.course, + { + "cert_html_view_enabled": {"value": "true"} + }, + user=self.user + ) + self.assertIn('cert_html_view_enabled', test_model) + url = get_url(self.course.id) + response = self.client.get_json(url) + course_detail_json = json.loads(response.content) + self.assertFalse(course_detail_json['has_cert_config']) + + # Now add a certificate configuration + certificates = [ + { + 'id': 1, + 'name': 'Certificate Config Name', + 'course_title': 'Title override', + 'org_logo_path': '/c4x/test/CSS101/asset/org_logo.png', + 'signatories': [], + 'is_active': True + } + ] + self.course.certificates = {'certificates': certificates} + modulestore().update_item(self.course, self.user.id) + response = self.client.get_json(url) + course_detail_json = json.loads(response.content) + self.assertTrue(course_detail_json['has_cert_config']) + class CourseGraderUpdatesTest(CourseTestCase): """ diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 5828d4e761..1b3c1ec580 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -310,3 +310,22 @@ def reverse_usage_url(handler_name, usage_key, kwargs=None): Creates the URL for handlers that use usage_keys as URL parameters. """ return reverse_url(handler_name, 'usage_key_string', usage_key, kwargs) + + +def has_active_web_certificate(course): + """ + Returns True if given course has active web certificate configuration. + If given course has no active web certificate configuration returns False. + Returns None If `CERTIFICATES_HTML_VIEW` is not enabled of course has not enabled + `cert_html_view_enabled` settings. + """ + cert_config = None + if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False) and course.cert_html_view_enabled: + cert_config = False + certificates = getattr(course, 'certificates', {}) + configurations = certificates.get('certificates', []) + for config in configurations: + if config.get('is_active'): + cert_config = True + break + return cert_config diff --git a/cms/djangoapps/models/settings/course_details.py b/cms/djangoapps/models/settings/course_details.py index 0b81444ab5..4483b1145f 100644 --- a/cms/djangoapps/models/settings/course_details.py +++ b/cms/djangoapps/models/settings/course_details.py @@ -8,7 +8,7 @@ from django.conf import settings from opaque_keys.edx.locations import Location from xmodule.modulestore.exceptions import ItemNotFoundError -from contentstore.utils import course_image_url +from contentstore.utils import course_image_url, has_active_web_certificate from models.settings import course_grading from xmodule.fields import Date from xmodule.modulestore.django import modulestore @@ -52,7 +52,8 @@ class CourseDetails(object): self.entrance_exam_minimum_score_pct = settings.FEATURES.get( 'ENTRANCE_EXAM_MIN_SCORE_PCT', '50' - ) # minimum passing score for entrance exam content module/tree + ) # minimum passing score for entrance exam content module/tree, + self.has_cert_config = None # course has active certificate configuration @classmethod def _fetch_about_attribute(cls, course_key, attribute): @@ -84,6 +85,7 @@ class CourseDetails(object): course_details.language = descriptor.language # Default course license is "All Rights Reserved" course_details.license = getattr(descriptor, "license", "all-rights-reserved") + course_details.has_cert_config = has_active_web_certificate(descriptor) for attribute in ABOUT_ATTRIBUTES: value = cls._fetch_about_attribute(course_key, attribute) diff --git a/cms/static/js/models/settings/course_details.js b/cms/static/js/models/settings/course_details.js index a9f70eac7e..efb3e24dcd 100644 --- a/cms/static/js/models/settings/course_details.js +++ b/cms/static/js/models/settings/course_details.js @@ -1,5 +1,5 @@ -define(["backbone", "underscore", "gettext", "js/models/validation_helpers"], - function(Backbone, _, gettext, ValidationHelpers) { +define(["backbone", "underscore", "gettext", "js/models/validation_helpers", "js/utils/date_utils"], + function(Backbone, _, gettext, ValidationHelpers, DateUtils) { var CourseDetails = Backbone.Model.extend({ defaults: { @@ -28,14 +28,21 @@ var CourseDetails = Backbone.Model.extend({ // Returns either nothing (no return call) so that validate works or an object of {field: errorstring} pairs // A bit funny in that the video key validation is asynchronous; so, it won't stop the validation. var errors = {}; + newattrs = DateUtils.convertDateStringsToObjects( + newattrs, ["start_date", "end_date", "enrollment_start", "enrollment_end"] + ); + if (newattrs.start_date === null) { errors.start_date = gettext("The course must have an assigned start date."); } + if (this.hasChanged("start_date") && this.get("has_cert_config") === false){ + errors.start_date = gettext("The course must have at least one active certificate configuration before it can be started."); + } if (newattrs.start_date && newattrs.end_date && newattrs.start_date >= newattrs.end_date) { - errors.end_date = gettext("The course end date cannot be before the course start date."); + errors.end_date = gettext("The course end date must be later than the course start date."); } if (newattrs.start_date && newattrs.enrollment_start && newattrs.start_date < newattrs.enrollment_start) { - errors.enrollment_start = gettext("The course start date cannot be before the enrollment start date."); + errors.enrollment_start = gettext("The course start date must be later than the enrollment start date."); } if (newattrs.enrollment_start && newattrs.enrollment_end && newattrs.enrollment_start >= newattrs.enrollment_end) { errors.enrollment_end = gettext("The enrollment start date cannot be after the enrollment end date."); diff --git a/cms/static/js/spec/views/settings/main_spec.js b/cms/static/js/spec/views/settings/main_spec.js index f39d669c5d..636ed93c0a 100644 --- a/cms/static/js/spec/views/settings/main_spec.js +++ b/cms/static/js/spec/views/settings/main_spec.js @@ -31,7 +31,8 @@ define([ entrance_exam_enabled : '', entrance_exam_minimum_score_pct: '50', license: null, - language: '' + language: '', + has_cert_config: false }, mockSettingsPage = readFixtures('mock/mock-settings-page.underscore'); @@ -71,6 +72,13 @@ define([ ); }); + it('Changing course start date without active certificate configuration should result in error', function () { + this.view.$el.find('#course-start-date') + .val('10/06/2014') + .trigger('change'); + expect(this.view.$el.find('span.message-error').text()).toContain("course must have at least one active certificate configuration"); + }); + it('Selecting a course in pre-requisite drop down should save it as part of course details', function () { var pre_requisite_courses = ['test/CSS101/2012_T1']; var requests = AjaxHelpers.requests(this), diff --git a/cms/static/js/utils/date_utils.js b/cms/static/js/utils/date_utils.js index 8bb1c20884..c6ae76d00d 100644 --- a/cms/static/js/utils/date_utils.js +++ b/cms/static/js/utils/date_utils.js @@ -35,9 +35,29 @@ define(["jquery", "date", "jquery.ui", "jquery.timepicker"], function($, date) { ); }; + var parseDateFromString = function(stringDate){ + if (stringDate && typeof stringDate === "string"){ + return new Date(stringDate); + } + else { + return stringDate; + } + }; + + var convertDateStringsToObjects = function(obj, dateFields){ + for (var i = 0; i < dateFields.length; i++){ + if (obj[dateFields[i]]){ + obj[dateFields[i]] = parseDateFromString(obj[dateFields[i]]); + } + } + return obj; + }; + return { getDate: getDate, setDate: setDate, - renderDate: renderDate + renderDate: renderDate, + convertDateStringsToObjects: convertDateStringsToObjects, + parseDateFromString: parseDateFromString }; }); diff --git a/common/djangoapps/student/tests/test_certificates.py b/common/djangoapps/student/tests/test_certificates.py index 03d5b66e00..33d89458a1 100644 --- a/common/djangoapps/student/tests/test_certificates.py +++ b/common/djangoapps/student/tests/test_certificates.py @@ -47,9 +47,14 @@ class CertificateDisplayTest(ModuleStoreTestCase): @patch.dict('django.conf.settings.FEATURES', {'CERTIFICATES_HTML_VIEW': True}) def test_display_download_certificate_button(self, enrollment_mode): """ - Tests if CERTIFICATES_HTML_VIEW is True and there is no active certificate configuration available + Tests if CERTIFICATES_HTML_VIEW is True + and course has enabled web certificates via cert_html_view_enabled setting + and no active certificate configuration available then any of the Download certificate button should not be visible. """ + self.course.cert_html_view_enabled = True + self.course.save() + self.store.update_item(self.course, self.user.id) self._create_certificate(enrollment_mode) self._check_can_not_download_certificate() @@ -75,6 +80,7 @@ class CertificateDisplayTest(ModuleStoreTestCase): } ] self.course.certificates = {'certificates': certificates} + self.course.cert_html_view_enabled = True self.course.save() # pylint: disable=no-member self.store.update_item(self.course, self.user.id) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 1420aa5432..b46a973168 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -59,7 +59,11 @@ from student.forms import AccountCreationForm, PasswordResetFormNoActive from verify_student.models import SoftwareSecurePhotoVerification # pylint: disable=import-error from certificates.models import CertificateStatuses, certificate_status_for_student -from certificates.api import get_certificate_url, get_active_web_certificate # pylint: disable=import-error +from certificates.api import ( # pylint: disable=import-error + get_certificate_url, + get_active_web_certificate, + has_html_certificates_enabled, +) from dark_lang.models import DarkLangConfig from xmodule.modulestore.django import modulestore @@ -305,7 +309,7 @@ def _cert_info(user, course, cert_status, course_mode): if status == 'ready': # showing the certificate web view button if certificate is ready state and feature flags are enabled. - if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): + if has_html_certificates_enabled(course.id, course): if get_active_web_certificate(course) is not None: certificate_url = get_certificate_url( user_id=user.id, diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py index 5a5066c344..f3d18eb8be 100644 --- a/common/lib/xmodule/xmodule/course_module.py +++ b/common/lib/xmodule/xmodule/course_module.py @@ -712,6 +712,12 @@ class CourseFields(object): scope=Scope.settings, default="" ) + cert_html_view_enabled = Boolean( + display_name=_("Certificate Web/HTML View Enabled"), + help=_("If true, certificate Web/HTML views are enabled for the course."), + scope=Scope.settings, + default=False, + ) cert_html_view_overrides = Dict( # Translators: This field is the container for course-specific certifcate configuration values display_name=_("Certificate Web/HTML View Overrides"), diff --git a/common/test/acceptance/pages/studio/settings_advanced.py b/common/test/acceptance/pages/studio/settings_advanced.py index dc94a08920..d4a02d23d5 100644 --- a/common/test/acceptance/pages/studio/settings_advanced.py +++ b/common/test/acceptance/pages/studio/settings_advanced.py @@ -201,4 +201,5 @@ class AdvancedSettingsPage(CoursePage): 'social_sharing_url', 'teams_configuration', 'video_bumper', + 'cert_html_view_enabled', ] diff --git a/common/test/acceptance/tests/lms/test_certificate_web_view.py b/common/test/acceptance/tests/lms/test_certificate_web_view.py index b069ee654e..495457de7f 100644 --- a/common/test/acceptance/tests/lms/test_certificate_web_view.py +++ b/common/test/acceptance/tests/lms/test_certificate_web_view.py @@ -36,8 +36,11 @@ class CertificateWebViewTest(EventsTestMixin, UniqueCourseTest): self.course_info["display_name"], settings=course_settings ) + self.course_fixture.add_advanced_settings({ + "cert_html_view_enabled": {"value": "true"} + }) self.course_fixture.install() - self.user_id = "99" # we have createad a user with this id in fixture + self.user_id = "99" # we have created a user with this id in fixture self.cert_fixture = CertificateConfigFixture(self.course_id, test_certificate_config) # Load certificate web view page for use by the tests diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index 58b2b48a9f..aa9f4c005f 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -10,6 +10,7 @@ from django.conf import settings from django.core.urlresolvers import reverse from eventtracking import tracker +from opaque_keys.edx.keys import CourseKey from xmodule.modulestore.django import modulestore @@ -211,10 +212,14 @@ def has_html_certificates_enabled(course_key, course=None): It determines if course has html certificates enabled """ html_certificates_enabled = False - if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): + try: + if not isinstance(course_key, CourseKey): + course_key = CourseKey.from_string(course_key) course = course if course else modulestore().get_course(course_key, depth=0) - if get_active_web_certificate(course) is not None: + if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False) and course.cert_html_view_enabled: html_certificates_enabled = True + except: # pylint: disable=bare-except + pass return html_certificates_enabled diff --git a/lms/djangoapps/certificates/tests/test_api.py b/lms/djangoapps/certificates/tests/test_api.py index 043bdf6639..c6fa67aec6 100644 --- a/lms/djangoapps/certificates/tests/test_api.py +++ b/lms/djangoapps/certificates/tests/test_api.py @@ -214,6 +214,7 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase): } ] self.course.certificates = {'certificates': certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) diff --git a/lms/djangoapps/certificates/tests/test_views.py b/lms/djangoapps/certificates/tests/test_views.py index e4f3eb7b80..7bc80ffd0d 100644 --- a/lms/djangoapps/certificates/tests/test_views.py +++ b/lms/djangoapps/certificates/tests/test_views.py @@ -267,6 +267,7 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase): ] self.course.certificates = {'certificates': certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) @@ -422,6 +423,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): ] self.course.certificates = {'certificates': certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) @@ -483,6 +485,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): } ] self.course.certificates = {'certificates': test_certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) response = self.client.get(test_url) @@ -506,6 +509,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): } ] self.course.certificates = {'certificates': test_certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) response = self.client.get(test_url) @@ -646,6 +650,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): verify_uuid=self.cert.verify_uuid ) test_url = '{}?evidence_visit=1'.format(cert_url) + self._add_course_certificates(count=1, signatory_count=2) self.recreate_tracker() assertion = BadgeAssertion( user=self.user, course_id=self.course_id, mode='honor', diff --git a/lms/djangoapps/certificates/views.py b/lms/djangoapps/certificates/views.py index 7d0c7bf40a..282abc273b 100644 --- a/lms/djangoapps/certificates/views.py +++ b/lms/djangoapps/certificates/views.py @@ -21,7 +21,8 @@ from certificates.api import ( get_active_web_certificate, get_certificate_url, generate_user_certificates, - emit_certificate_event + emit_certificate_event, + has_html_certificates_enabled ) from certificates.models import ( certificate_status_for_student, @@ -504,7 +505,7 @@ def render_html_view(request, user_id, course_id): invalid_template_path = 'certificates/invalid.html' # Kick the user back to the "Invalid" screen if the feature is disabled - if not settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): + if not has_html_certificates_enabled(course_id): return render_to_response(invalid_template_path, context) # Load the core building blocks for the view context diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index 217da31f53..e85e06cfe3 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -853,6 +853,7 @@ class ProgressPageTests(ModuleStoreTestCase): ] self.course.certificates = {'certificates': certificates} + self.course.cert_html_view_enabled = True self.course.save() self.store.update_item(self.course, self.user.id) diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index de5252bbfe..4ccb838fbf 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -1081,7 +1081,7 @@ def _progress(request, course_key, student_id): if show_generate_cert_btn: context.update(certs_api.certificate_downloadable_status(student, course_key)) # showing the certificate web view button if feature flags are enabled. - if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): + if certs_api.has_html_certificates_enabled(course_key, course): if certs_api.get_active_web_certificate(course) is not None: context.update({ 'show_cert_web_view': True, From f4209803f2985c06e1b6cc5d815986360cd02d71 Mon Sep 17 00:00:00 2001 From: Alison Hodges Date: Mon, 29 Jun 2015 13:25:18 -0400 Subject: [PATCH 002/104] Remove "instructor" label or change to "Admin" Clarifies what the roles are, makes Studio and LMS naming parallel. --- cms/templates/manage_users.html | 7 ++- cms/templates/manage_users_lib.html | 6 +- .../instructor_dashboard/student_admin.html | 6 +- .../instructor_dashboard_2/course_info.html | 4 +- .../instructor_dashboard_2/data_download.html | 2 +- .../instructor_dashboard_2/e-commerce.html | 2 +- .../instructor_dashboard_2/membership.html | 56 +++++++++++-------- .../instructor_dashboard_2/send_email.html | 10 ++-- .../instructor_dashboard_2/student_admin.html | 6 +- lms/templates/peer_grading/peer_grading.html | 2 +- 10 files changed, 55 insertions(+), 46 deletions(-) diff --git a/cms/templates/manage_users.html b/cms/templates/manage_users.html index 2a898fc9b9..df48b9670a 100644 --- a/cms/templates/manage_users.html +++ b/cms/templates/manage_users.html @@ -53,7 +53,7 @@ from django.core.urlresolvers import reverse
  • - ${_("Please provide the email address of the course staff member you'd like to add")} + ${_("Provide an email address to add the user as Staff")}
  • @@ -94,14 +94,15 @@ from django.core.urlresolvers import reverse diff --git a/cms/templates/manage_users_lib.html b/cms/templates/manage_users_lib.html index 7c8ed187a1..e4dd12d3cf 100644 --- a/cms/templates/manage_users_lib.html +++ b/cms/templates/manage_users_lib.html @@ -95,9 +95,9 @@ from django.core.urlresolvers import reverse

    ${_("Library Access Roles")}

    ${_("There are three access roles for libraries: User, Staff, and Admin.")}

    -

    ${_("Users can view library content and can reference or use library components in their courses, but they cannot edit the contents of a library.")}

    -

    ${_("Staff are content co-authors. They have full editing privileges on the contents of a library.")}

    -

    ${_("Admins have full editing privileges and can also add and remove other team members. There must be at least one user with Admin privileges in a library.")}

    +

    ${_("Library Users can view library content and can reference or use library components in their courses, but they cannot edit the contents of a library.")}

    +

    ${_("Library Staff are content co-authors. They have full editing privileges on the contents of a library.")}

    +

    ${_("Library Admins have full editing privileges and can also add and remove other team members. There must be at least one user with the Admin role in a library.")}

    diff --git a/lms/static/js/fixtures/instructor_dashboard/student_admin.html b/lms/static/js/fixtures/instructor_dashboard/student_admin.html index cbf94bb0dc..c724191d2c 100644 --- a/lms/static/js/fixtures/instructor_dashboard/student_admin.html +++ b/lms/static/js/fixtures/instructor_dashboard/student_admin.html @@ -70,7 +70,7 @@

    - Rescoring runs in the background, and status for active tasks will appear in the 'Pending Instructor Tasks' table. To see status for all tasks submitted for this problem and student, click on this button: + Rescoring runs in the background, and status for active tasks will appear in the 'Pending Tasks' table. To see status for all tasks submitted for this problem and student, click on this button:

    @@ -103,7 +103,7 @@

    - Rescoring runs in the background, and status for active tasks will appear in the 'Pending Instructor Tasks' table. To see status for all tasks submitted for this problem and student, click on this button: + Rescoring runs in the background, and status for active tasks will appear in the 'Pending Tasks' table. To see status for all tasks submitted for this problem and student, click on this button:

    @@ -137,7 +137,7 @@

    -

    Pending Instructor Tasks

    +

    Pending Tasks

    The status for any active tasks appears in a table below.


    diff --git a/lms/templates/instructor/instructor_dashboard_2/course_info.html b/lms/templates/instructor/instructor_dashboard_2/course_info.html index 22cce25f6f..db19bc1d0e 100644 --- a/lms/templates/instructor/instructor_dashboard_2/course_info.html +++ b/lms/templates/instructor/instructor_dashboard_2/course_info.html @@ -7,7 +7,7 @@ %if settings.FEATURES.get('DISPLAY_ANALYTICS_ENROLLMENTS'): ## Translators: 'track' refers to the enrollment type ('honor', 'verified', or 'audit') - ${_("Number of enrollees (instructors, staff members, and students) by track")} + ${_("Number of enrollees (admins, staff, and students) by track")}instructors

    <% modes = section_data['enrollment_count'] %> @@ -94,7 +94,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

    -

    ${_("Pending Instructor Tasks")}

    +

    ${_("Pending Tasks")}

    ${_("The status for any active tasks appears in a table below.")}


    diff --git a/lms/templates/instructor/instructor_dashboard_2/data_download.html b/lms/templates/instructor/instructor_dashboard_2/data_download.html index a7110098fa..f3e1327e15 100644 --- a/lms/templates/instructor/instructor_dashboard_2/data_download.html +++ b/lms/templates/instructor/instructor_dashboard_2/data_download.html @@ -74,7 +74,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

    -

    ${_("Pending Instructor Tasks")}

    +

    ${_("Pending Tasks")}

    ${_("The status for any active tasks appears in a table below.")}


    diff --git a/lms/templates/instructor/instructor_dashboard_2/e-commerce.html b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html index e7cc2f2987..5a0daee732 100644 --- a/lms/templates/instructor/instructor_dashboard_2/e-commerce.html +++ b/lms/templates/instructor/instructor_dashboard_2/e-commerce.html @@ -126,7 +126,7 @@ import pytz %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

    -

    ${_("Pending Instructor Tasks")}

    +

    ${_("Pending Tasks")}

    ${_("The status for any active tasks appears in a table below.")}


    diff --git a/lms/templates/instructor/instructor_dashboard_2/membership.html b/lms/templates/instructor/instructor_dashboard_2/membership.html index 755cf70663..153bf4d137 100644 --- a/lms/templates/instructor/instructor_dashboard_2/membership.html +++ b/lms/templates/instructor/instructor_dashboard_2/membership.html @@ -114,7 +114,7 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_

    @@ -156,13 +156,13 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_

    ## Translators: an "Administration List" is a list, such as Course Staff, that users can be added to. -

    ${_("Administration List Management")}

    +

    ${_("Course Team Management")}

    ## Translators: an "Administrator Group" is a group, such as Course Staff, that users can be added to. - + @@ -172,21 +172,21 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_ %if not section_data['access']['instructor']:

    - ${_("Staff cannot modify staff or beta tester lists. To modify these lists, " - "contact your instructor and ask them to add you as an instructor for staff " - "and beta lists, or a discussion admin for discussion management.")} + ${_("Staff cannot modify these lists. To manage course team membership, " + "a course Admin must give you the Admin role to add Staff or Beta Testers, " + "or the Discussion Admin role to add discussion moderators and TAs.")}

    %endif %if section_data['access']['instructor']:
    %if to_option == "staff": - + %else: - + %endif %if to_option == "all": - + %else: - + %endif @@ -58,7 +58,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

    -

    ${_("Pending Instructor Tasks")}

    +

    ${_("Pending Tasks")}

    ${_("Email actions run in the background. The status for any active tasks - including email tasks - appears in a table below.")}


    diff --git a/lms/templates/instructor/instructor_dashboard_2/student_admin.html b/lms/templates/instructor/instructor_dashboard_2/student_admin.html index 4081aa359d..a7d3b92279 100644 --- a/lms/templates/instructor/instructor_dashboard_2/student_admin.html +++ b/lms/templates/instructor/instructor_dashboard_2/student_admin.html @@ -78,7 +78,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']:

    - ${_("Rescoring runs in the background, and status for active tasks will appear in the 'Pending Instructor Tasks' table. " + ${_("Rescoring runs in the background, and status for active tasks will appear in the 'Pending Tasks' table. " "To see status for all tasks submitted for this problem and student, click on this button:")}

    @@ -119,7 +119,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS') and section_data['access']['instructor']:

    - ${_("Rescoring runs in the background, and status for active tasks will appear in the 'Pending Instructor Tasks' table. " + ${_("Rescoring runs in the background, and status for active tasks will appear in the 'Pending Tasks' table. " "To see status for all tasks submitted for this problem and student, click on this button:")}

    @@ -161,7 +161,7 @@ %if settings.FEATURES.get('ENABLE_INSTRUCTOR_BACKGROUND_TASKS'):

    -

    ${_("Pending Instructor Tasks")}

    +

    ${_("Pending Tasks")}

    ${_("The status for any active tasks appears in a table below.")}


    diff --git a/lms/templates/peer_grading/peer_grading.html b/lms/templates/peer_grading/peer_grading.html index d868347445..c03b61aee9 100644 --- a/lms/templates/peer_grading/peer_grading.html +++ b/lms/templates/peer_grading/peer_grading.html @@ -5,7 +5,7 @@ nothing_to_grade_message = _( {p_tag}You currently do not have any peer grading to do. In order to have peer grading to do: {ul_tag} {li_tag}You need to have submitted a response to a peer grading problem.{end_li_tag} -{li_tag}The instructor needs to score the essays that are used to help you better understand the grading +{li_tag}The course team needs to score the essays that are used to help you better understand the grading criteria.{end_li_tag} {li_tag}There must be submissions that are waiting for grading.{end_li_tag} {end_ul_tag} From ad1f4951fceaafa4f7c405426ab0716645c46f17 Mon Sep 17 00:00:00 2001 From: Zia Fazal Date: Wed, 1 Jul 2015 16:14:37 +0500 Subject: [PATCH 003/104] get_certificate_url should return certificate download_url in case of non html certificates --- .../student/tests/test_certificates.py | 3 +- common/djangoapps/student/views.py | 3 +- lms/djangoapps/certificates/api.py | 34 ++++++++---- lms/djangoapps/certificates/tests/test_api.py | 10 +++- .../certificates/tests/test_views.py | 52 +++++++------------ lms/djangoapps/certificates/views.py | 3 +- lms/djangoapps/courseware/tests/test_views.py | 3 +- lms/djangoapps/courseware/views.py | 3 +- lms/envs/aws.py | 3 -- lms/envs/common.py | 3 -- 10 files changed, 58 insertions(+), 59 deletions(-) diff --git a/common/djangoapps/student/tests/test_certificates.py b/common/djangoapps/student/tests/test_certificates.py index 03d5b66e00..dea4192a90 100644 --- a/common/djangoapps/student/tests/test_certificates.py +++ b/common/djangoapps/student/tests/test_certificates.py @@ -59,8 +59,7 @@ class CertificateDisplayTest(ModuleStoreTestCase): def test_linked_student_to_web_view_credential(self, enrollment_mode): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid='abcdefg12345678' + course_id=unicode(self.course.id) ) self._create_certificate(enrollment_mode) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 1420aa5432..20c3e6d3ae 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -309,8 +309,7 @@ def _cert_info(user, course, cert_status, course_mode): if get_active_web_certificate(course) is not None: certificate_url = get_certificate_url( user_id=user.id, - course_id=unicode(course.id), - verify_uuid=None + course_id=unicode(course.id) ) status_dict.update({ 'show_cert_web_view': True, diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index 58b2b48a9f..b0e352588f 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -10,6 +10,7 @@ from django.conf import settings from django.core.urlresolvers import reverse from eventtracking import tracker +from opaque_keys.edx.keys import CourseKey from xmodule.modulestore.django import modulestore @@ -18,7 +19,8 @@ from certificates.models import ( certificate_status_for_student, CertificateGenerationCourseSetting, CertificateGenerationConfiguration, - ExampleCertificateSet + ExampleCertificateSet, + GeneratedCertificate ) from certificates.queue import XQueueCertInterface @@ -253,18 +255,32 @@ def example_certificates_status(course_key): # pylint: disable=no-member -def get_certificate_url(user_id, course_id, verify_uuid): +def get_certificate_url(user_id, course_id): """ :return certificate url """ + url = "" if settings.FEATURES.get('CERTIFICATES_HTML_VIEW', False): - return u'{url}'.format( - url=reverse( - 'cert_html_view', - kwargs=dict(user_id=str(user_id), course_id=unicode(course_id)) - ) + url = reverse( + 'cert_html_view', kwargs=dict(user_id=str(user_id), course_id=unicode(course_id)) ) - return '{url}{uuid}'.format(url=settings.CERTIFICATES_STATIC_VERIFY_URL, uuid=verify_uuid) + else: + try: + if isinstance(course_id, basestring): + course_id = CourseKey.from_string(course_id) + user_certificate = GeneratedCertificate.objects.get( + user=user_id, + course_id=course_id + ) + url = user_certificate.download_url + except GeneratedCertificate.DoesNotExist: + log.critical( + 'Unable to lookup certificate\n' + 'user id: %d\n' + 'course: %s', user_id, unicode(course_id) + ) + + return url def get_active_web_certificate(course, is_preview_mode=None): @@ -293,7 +309,7 @@ def emit_certificate_event(event_name, user, course_id, course=None, event_data= data = { 'user_id': user.id, 'course_id': unicode(course_id), - 'certificate_url': get_certificate_url(user.id, course_id, event_data['certificate_id']) + 'certificate_url': get_certificate_url(user.id, course_id) } event_data = event_data or {} event_data.update(data) diff --git a/lms/djangoapps/certificates/tests/test_api.py b/lms/djangoapps/certificates/tests/test_api.py index 043bdf6639..bc3f100665 100644 --- a/lms/djangoapps/certificates/tests/test_api.py +++ b/lms/djangoapps/certificates/tests/test_api.py @@ -148,7 +148,7 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase): 'edx.certificate.created', user_id=self.student.id, course_id=unicode(self.course.id), - certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id, cert.verify_uuid), + certificate_url=certs_api.get_certificate_url(self.student.id, self.course.id), certificate_id=cert.verify_uuid, enrollment_mode=cert.mode, generation_mode='batch' @@ -177,6 +177,14 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase): cert = GeneratedCertificate.objects.get(user=self.student, course_id=self.course.id) self.assertEqual(cert.status, CertificateStatuses.downloadable) + @patch.dict(settings.FEATURES, {'CERTIFICATES_HTML_VIEW': False}) + def test_cert_url_empty_with_invalid_certificate(self): + """ + Test certificate url is empty if html view is not enabled and certificate is not yet generated + """ + url = certs_api.get_certificate_url(self.student.id, self.course.id) + self.assertEqual(url, "") + @contextmanager def _mock_passing_grade(self): """Mock the grading function to always return a passing grade. """ diff --git a/lms/djangoapps/certificates/tests/test_views.py b/lms/djangoapps/certificates/tests/test_views.py index e4f3eb7b80..c8ebbaa4ee 100644 --- a/lms/djangoapps/certificates/tests/test_views.py +++ b/lms/djangoapps/certificates/tests/test_views.py @@ -308,8 +308,7 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase): self.assertEquals(config.configuration, test_configuration_string) test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) @@ -319,6 +318,7 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase): self.assertIn('Microsite title', response.content) @patch("microsite_configuration.microsite.get_value", fakemicrosite) + @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) def test_html_view_microsite_configuration_missing(self): test_configuration_string = """{ "default": { @@ -342,8 +342,7 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase): self.assertEquals(config.configuration, test_configuration_string) test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) @@ -379,6 +378,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): course_id=self.course_id, verify_uuid=uuid4(), download_uuid=uuid4(), + download_url="http://www.example.com/certificates/download", grade="0.95", key='the_key', distinction=True, @@ -429,8 +429,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_valid_certificate(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) @@ -452,8 +451,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_with_valid_signatories(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) @@ -469,8 +467,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): # if certificate in descriptor has not course_title then course name should not be overridden with this title. test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) test_certificates = [ { @@ -493,8 +490,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_certificate_view_without_org_logo(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) test_certificates = [ { @@ -516,8 +512,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_without_signatories(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course) ) self._add_course_certificates(count=1, signatory_count=0) response = self.client.get(test_url) @@ -528,17 +523,15 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_disabled_feature_flag_returns_static_url(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) - self.assertIn(str(self.cert.verify_uuid), test_url) + self.assertIn(str(self.cert.download_url), test_url) @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) def test_render_html_view_invalid_course_id(self): test_url = get_certificate_url( user_id=self.user.id, - course_id='az/23423/4vs', - verify_uuid=self.cert.verify_uuid + course_id='az/23423/4vs' ) response = self.client.get(test_url) @@ -548,8 +541,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_invalid_course(self): test_url = get_certificate_url( user_id=self.user.id, - course_id='missing/course/key', - verify_uuid=self.cert.verify_uuid + course_id='missing/course/key' ) response = self.client.get(test_url) self.assertIn('invalid', response.content) @@ -558,8 +550,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_invalid_user(self): test_url = get_certificate_url( user_id=111, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) response = self.client.get(test_url) self.assertIn('invalid', response.content) @@ -570,8 +561,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): self.assertEqual(len(GeneratedCertificate.objects.all()), 0) test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) response = self.client.get(test_url) self.assertIn('invalid', response.content) @@ -587,8 +577,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) response = self.client.get(test_url + '?preview=honor') self.assertNotIn(self.course.display_name, response.content) @@ -606,8 +595,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_render_html_view_invalid_certificate_configuration(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) response = self.client.get(test_url) self.assertIn("Invalid Certificate", response.content) @@ -619,8 +607,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): self.recreate_tracker() test_url = get_certificate_url( user_id=self.user.id, - course_id=unicode(self.course.id), - verify_uuid=self.cert.verify_uuid + course_id=unicode(self.course.id) ) response = self.client.get(test_url) self.assertEqual(response.status_code, 200) @@ -642,8 +629,7 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): def test_evidence_event_sent(self): cert_url = get_certificate_url( user_id=self.user.id, - course_id=self.course_id, - verify_uuid=self.cert.verify_uuid + course_id=self.course_id ) test_url = '{}?evidence_visit=1'.format(cert_url) self.recreate_tracker() diff --git a/lms/djangoapps/certificates/views.py b/lms/djangoapps/certificates/views.py index 7d0c7bf40a..c11be79ee3 100644 --- a/lms/djangoapps/certificates/views.py +++ b/lms/djangoapps/certificates/views.py @@ -439,8 +439,7 @@ def _update_certificate_context(context, course, user, user_certificate): user_certificate.mode, get_certificate_url( user_id=user.id, - course_id=unicode(course.id), - verify_uuid=user_certificate.verify_uuid + course_id=unicode(course.id) ) ) diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index e5b69c0952..ff07c49950 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -861,8 +861,7 @@ class ProgressPageTests(ModuleStoreTestCase): self.assertContains(resp, u"You can now view your certificate") cert_url = certs_api.get_certificate_url( user_id=self.user.id, - course_id=self.course.id, - verify_uuid=certificate.verify_uuid + course_id=self.course.id ) self.assertContains(resp, cert_url) diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index de5252bbfe..2896dad7a6 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -1088,8 +1088,7 @@ def _progress(request, course_key, student_id): 'cert_web_view_url': u'{url}'.format( url=certs_api.get_certificate_url( user_id=student.id, - course_id=unicode(course.id), - verify_uuid=None + course_id=unicode(course.id) ) ) }) diff --git a/lms/envs/aws.py b/lms/envs/aws.py index 5a497f425f..c11231db00 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -668,9 +668,6 @@ EDXNOTES_INTERNAL_API = ENV_TOKENS.get('EDXNOTES_INTERNAL_API', EDXNOTES_INTERNA CREDIT_PROVIDER_SECRET_KEYS = AUTH_TOKENS.get("CREDIT_PROVIDER_SECRET_KEYS", {}) -############ CERTIFICATE VERIFICATION URL (STATIC FILES) ########### -ENV_TOKENS.get('CERTIFICATES_STATIC_VERIFY_URL', CERTIFICATES_STATIC_VERIFY_URL) - ##################### LTI Provider ##################### if FEATURES.get('ENABLE_LTI_PROVIDER'): INSTALLED_APPS += ('lti_provider',) diff --git a/lms/envs/common.py b/lms/envs/common.py index 63cb891399..fb747bbbf0 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -2098,9 +2098,6 @@ REGISTRATION_EXTRA_FIELDS = { CERT_NAME_SHORT = "Certificate" CERT_NAME_LONG = "Certificate of Achievement" -############ CERTIFICATE VERIFICATION URL (STATIC FILES) ########### -CERTIFICATES_STATIC_VERIFY_URL = "https://verify-test.edx.org/cert/" - #################### Badgr OpenBadges generation ####################### # Be sure to set up images for course modes using the BadgeImageConfiguration model in the certificates app. BADGR_API_TOKEN = None From 91955d43bfee9e2bd77c54dac0c29658fc412b7e Mon Sep 17 00:00:00 2001 From: Alison Hodges Date: Wed, 1 Jul 2015 10:00:38 -0400 Subject: [PATCH 004/104] Mark's edits --- .../instructor/instructor_dashboard_2/course_info.html | 2 +- lms/templates/instructor/instructor_dashboard_2/membership.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/templates/instructor/instructor_dashboard_2/course_info.html b/lms/templates/instructor/instructor_dashboard_2/course_info.html index db19bc1d0e..7df0a7fb35 100644 --- a/lms/templates/instructor/instructor_dashboard_2/course_info.html +++ b/lms/templates/instructor/instructor_dashboard_2/course_info.html @@ -7,7 +7,7 @@ %if settings.FEATURES.get('DISPLAY_ANALYTICS_ENROLLMENTS'): ## Translators: 'track' refers to the enrollment type ('honor', 'verified', or 'audit') - ${_("Number of enrollees (admins, staff, and students) by track")}instructors + ${_("Number of enrollees (admins, staff, and students) by track")}

    <% modes = section_data['enrollment_count'] %>
    diff --git a/lms/templates/instructor/instructor_dashboard_2/membership.html b/lms/templates/instructor/instructor_dashboard_2/membership.html index 153bf4d137..541480377d 100644 --- a/lms/templates/instructor/instructor_dashboard_2/membership.html +++ b/lms/templates/instructor/instructor_dashboard_2/membership.html @@ -210,7 +210,7 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_ data-rolename="beta" data-display-name="${_("Beta Testers")}" data-info-text=" - ${_("Beta Testers can see course content before otehr learners. " + ${_("Beta Testers can see course content before other learners. " "They can make sure that the content works, but have no additional " "privileges. You can only give course team roles to enrolled users.")}" data-list-endpoint="${ section_data['list_course_role_members_url'] }" From 473b43cba000bb18ecbc51bc618dc75133c2728f Mon Sep 17 00:00:00 2001 From: Alison Hodges Date: Wed, 1 Jul 2015 10:38:42 -0400 Subject: [PATCH 005/104] missing quote catch by Christine --- lms/templates/instructor/instructor_dashboard_2/membership.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/templates/instructor/instructor_dashboard_2/membership.html b/lms/templates/instructor/instructor_dashboard_2/membership.html index 541480377d..360e9536b3 100644 --- a/lms/templates/instructor/instructor_dashboard_2/membership.html +++ b/lms/templates/instructor/instructor_dashboard_2/membership.html @@ -255,7 +255,7 @@ from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_ ${_("Community TA's are members of the community whom you deem particularly " "helpful on the discussion boards. They can edit or delete any post, clear " "misuse flags, close and re-open threads, endorse responses, and see posts from " - all cohorts. Their posts are marked as 'Community TA'. You can only give course " + "all cohorts. Their posts are marked as 'Community TA'. You can only give course " "team roles to enrolled users.")}" data-list-endpoint="${ section_data['list_forum_members_url'] }" data-modify-endpoint="${ section_data['update_forum_role_membership_url'] }" From 07fda73ffa7fb34d7073ac9225abdba00ba829e5 Mon Sep 17 00:00:00 2001 From: Akiva Leffert Date: Wed, 1 Jul 2015 11:24:04 -0400 Subject: [PATCH 006/104] Remove border from chromeless xblock JIRA: https://openedx.atlassian.net/browse/MA-972 --- lms/djangoapps/courseware/testutils.py | 1 + lms/templates/courseware/courseware-chromeless.html | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/lms/djangoapps/courseware/testutils.py b/lms/djangoapps/courseware/testutils.py index 53984e189f..4f8148448f 100644 --- a/lms/djangoapps/courseware/testutils.py +++ b/lms/djangoapps/courseware/testutils.py @@ -30,6 +30,7 @@ class RenderXBlockTestMixin(object): '