From 2c09ebb20899c67e9c8397d018994b5f36aaae76 Mon Sep 17 00:00:00 2001 From: Waheed Ahmed Date: Wed, 18 Apr 2018 17:59:38 +0500 Subject: [PATCH] Update support form to make course required. Update support form to auto select course and make course selection required to submit form. LEARNER-4254 --- lms/djangoapps/courseware/middleware.py | 18 ++++++++++++++++++ lms/djangoapps/courseware/tests/test_views.py | 18 +++++++++++------- .../django_comment_client/base/tests.py | 8 ++++---- .../static/support/jsx/logged_in_user.jsx | 8 ++++++-- .../support/jsx/single_support_form.jsx | 19 ++++++++++++++----- lms/djangoapps/support/views/contact_us.py | 1 + lms/envs/common.py | 1 + lms/templates/support/contact_us.html | 3 ++- .../tests/views/test_course_home.py | 2 +- .../tests/views/test_course_updates.py | 2 +- 10 files changed, 59 insertions(+), 21 deletions(-) diff --git a/lms/djangoapps/courseware/middleware.py b/lms/djangoapps/courseware/middleware.py index 0b973732a1..5e2063eceb 100644 --- a/lms/djangoapps/courseware/middleware.py +++ b/lms/djangoapps/courseware/middleware.py @@ -5,6 +5,7 @@ Middleware for the courseware app from django.shortcuts import redirect from lms.djangoapps.courseware.exceptions import Redirect +from util.request import COURSE_REGEX class RedirectMiddleware(object): @@ -17,3 +18,20 @@ class RedirectMiddleware(object): """ if isinstance(exception, Redirect): return redirect(exception.url) + + +class CacheCourseIdMiddleware(object): + """Middleware that adds course_id to user request session.""" + + def process_request(self, request): + """ + Add a course_id to user request session. + """ + if request.user.is_authenticated(): + match = COURSE_REGEX.match(request.build_absolute_uri()) + course_id = None + if match: + course_id = match.group('course_id') + + if course_id and course_id != request.session.get('course_id'): + request.session['course_id'] = course_id diff --git a/lms/djangoapps/courseware/tests/test_views.py b/lms/djangoapps/courseware/tests/test_views.py index d304b427f6..1958491851 100644 --- a/lms/djangoapps/courseware/tests/test_views.py +++ b/lms/djangoapps/courseware/tests/test_views.py @@ -203,8 +203,8 @@ class IndexQueryTestCase(ModuleStoreTestCase): NUM_PROBLEMS = 20 @ddt.data( - (ModuleStoreEnum.Type.mongo, 10, 143), - (ModuleStoreEnum.Type.split, 4, 143), + (ModuleStoreEnum.Type.mongo, 10, 146), + (ModuleStoreEnum.Type.split, 4, 146), ) @ddt.unpack def test_index_query_counts(self, store_type, expected_mongo_query_count, expected_mysql_query_count): @@ -1424,17 +1424,21 @@ class ProgressPageTests(ProgressPageBaseTests): resp = self._get_progress_page() self.assertContains(resp, u"Download Your Certificate") - @ddt.data(True, False) - def test_progress_queries_paced_courses(self, self_paced): + @ddt.data( + (True, 37), + (False, 36) + ) + @ddt.unpack + def test_progress_queries_paced_courses(self, self_paced, query_count): """Test that query counts remain the same for self-paced and instructor-paced courses.""" self.setup_course(self_paced=self_paced) - with self.assertNumQueries(34 if self_paced else 33, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST), check_mongo_calls(1): + with self.assertNumQueries(query_count, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST), check_mongo_calls(1): self._get_progress_page() @patch.dict(settings.FEATURES, {'ASSUME_ZERO_GRADE_IF_ABSENT_FOR_ALL_TESTS': False}) @ddt.data( - (False, 40, 27), - (True, 33, 23) + (False, 43, 27), + (True, 36, 23) ) @ddt.unpack def test_progress_queries(self, enable_waffle, initial, subsequent): diff --git a/lms/djangoapps/django_comment_client/base/tests.py b/lms/djangoapps/django_comment_client/base/tests.py index 64c482239e..a2946010f2 100644 --- a/lms/djangoapps/django_comment_client/base/tests.py +++ b/lms/djangoapps/django_comment_client/base/tests.py @@ -406,8 +406,8 @@ class ViewsQueryCountTestCase( return inner @ddt.data( - (ModuleStoreEnum.Type.mongo, 3, 4, 32), - (ModuleStoreEnum.Type.split, 3, 13, 32), + (ModuleStoreEnum.Type.mongo, 3, 4, 35), + (ModuleStoreEnum.Type.split, 3, 13, 35), ) @ddt.unpack @count_queries @@ -415,8 +415,8 @@ class ViewsQueryCountTestCase( self.create_thread_helper(mock_request) @ddt.data( - (ModuleStoreEnum.Type.mongo, 3, 3, 28), - (ModuleStoreEnum.Type.split, 3, 10, 28), + (ModuleStoreEnum.Type.mongo, 3, 3, 31), + (ModuleStoreEnum.Type.split, 3, 10, 31), ) @ddt.unpack @count_queries diff --git a/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx b/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx index 6a1f31735c..95c173020b 100644 --- a/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx +++ b/lms/djangoapps/support/static/support/jsx/logged_in_user.jsx @@ -10,7 +10,11 @@ function LoggedInUser({ userInformation, setErrorState, zendeskApiHost, submitFo if (userInformation.enrollments) { courseElement = (
- + + {userInformation.enrollments.map(enrollment => (
); } else { courseElement = (
- +
); } diff --git a/lms/djangoapps/support/static/support/jsx/single_support_form.jsx b/lms/djangoapps/support/static/support/jsx/single_support_form.jsx index 0d619386ce..ed0c14c82c 100644 --- a/lms/djangoapps/support/static/support/jsx/single_support_form.jsx +++ b/lms/djangoapps/support/static/support/jsx/single_support_form.jsx @@ -41,9 +41,11 @@ class RenderForm extends React.Component { body: $('#message').val(), }, tags: this.props.context.tags, - }; + }, + errors = []; let course; + this.clearErrors(); data.requester = { email: $userInfo.data('email'), @@ -54,13 +56,16 @@ class RenderForm extends React.Component { if (!course) { course = $course.val(); } - + if (!course) { + $('#course').closest('.form-group').addClass('has-error'); + errors.push(gettext('Select a course or select "Not specific to a course" for your support request.')); + } data.custom_fields = [{ id: this.props.context.customFields.course_id, value: course, }]; - if (this.validateData(data)) { + if (this.validateData(data, errors)) { request.open('POST', url, true); request.setRequestHeader('Content-type', 'application/json;charset=UTF-8'); request.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')); @@ -81,8 +86,12 @@ class RenderForm extends React.Component { } } - validateData(data) { - const errors = []; + clearErrors() { + this.setErrorState([]); + $('.form-group').removeClass('has-error'); + } + + validateData(data, errors) { if (!data.subject) { errors.push(gettext('Enter a subject for your support request.')); $('#subject').closest('.form-group').addClass('has-error'); diff --git a/lms/djangoapps/support/views/contact_us.py b/lms/djangoapps/support/views/contact_us.py index ff74e10c00..0b639b6881 100644 --- a/lms/djangoapps/support/views/contact_us.py +++ b/lms/djangoapps/support/views/contact_us.py @@ -32,6 +32,7 @@ class ContactUsView(View): tags.append("site_name_{site}".format(site=current_site_name)) if request.user.is_authenticated(): + context['course_id'] = request.session.get('course_id', '') context['user_enrollments'] = CourseEnrollment.enrollments_for_user_with_overviews_preload(request.user) enterprise_learner_data = enterprise_api.get_enterprise_learner_data(user=request.user) if enterprise_learner_data: diff --git a/lms/envs/common.py b/lms/envs/common.py index b2798ac0a3..7564e83f5f 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1288,6 +1288,7 @@ MIDDLEWARE_CLASSES = [ 'django.middleware.clickjacking.XFrameOptionsMiddleware', # to redirected unenrolled students to the course info page + 'courseware.middleware.CacheCourseIdMiddleware', 'courseware.middleware.RedirectMiddleware', 'course_wiki.middleware.WikiAccessMiddleware', diff --git a/lms/templates/support/contact_us.html b/lms/templates/support/contact_us.html index 1de9eb4d51..ceb8544c6e 100644 --- a/lms/templates/support/contact_us.html +++ b/lms/templates/support/contact_us.html @@ -42,7 +42,8 @@ from openedx.core.djangolib.js_utils import js_escaped_string, dump_js_escaped_j % if user.is_authenticated(): context['user'] = { 'username': "${user.username | n, js_escaped_string}", - 'email': "${user.email | n, js_escaped_string}" + 'email': "${user.email | n, js_escaped_string}", + 'course_id': "${course_id | n, js_escaped_string}" } % if user_enrollments: diff --git a/openedx/features/course_experience/tests/views/test_course_home.py b/openedx/features/course_experience/tests/views/test_course_home.py index 3d22685fa8..c4363dfa77 100644 --- a/openedx/features/course_experience/tests/views/test_course_home.py +++ b/openedx/features/course_experience/tests/views/test_course_home.py @@ -175,7 +175,7 @@ class TestCourseHomePage(CourseHomePageTestCase): course_home_url(self.course) # Fetch the view and verify the query counts - with self.assertNumQueries(50, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(53, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_home_url(self.course) self.client.get(url) diff --git a/openedx/features/course_experience/tests/views/test_course_updates.py b/openedx/features/course_experience/tests/views/test_course_updates.py index ab0bb2806c..a2f8eaa93b 100644 --- a/openedx/features/course_experience/tests/views/test_course_updates.py +++ b/openedx/features/course_experience/tests/views/test_course_updates.py @@ -126,7 +126,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase): course_updates_url(self.course) # Fetch the view and verify that the query counts haven't changed - with self.assertNumQueries(30, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): + with self.assertNumQueries(33, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST): with check_mongo_calls(4): url = course_updates_url(self.course) self.client.get(url)