enable users to select course when making support requests
ECOM-5936
This commit is contained in:
@@ -11,8 +11,10 @@ from util import views
|
||||
from zendesk import ZendeskError
|
||||
import json
|
||||
import mock
|
||||
from ddt import ddt, data, unpack
|
||||
|
||||
from student.tests.test_configuration_overrides import fake_get_value
|
||||
from student.tests.factories import CourseEnrollmentFactory
|
||||
|
||||
|
||||
def fake_support_backend_values(name, default=None): # pylint: disable=unused-argument
|
||||
@@ -26,8 +28,9 @@ def fake_support_backend_values(name, default=None): # pylint: disable=unused-a
|
||||
return config_dict[name]
|
||||
|
||||
|
||||
@ddt
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_FEEDBACK_SUBMISSION": True})
|
||||
@override_settings(ZENDESK_URL="dummy", ZENDESK_USER="dummy", ZENDESK_API_KEY="dummy")
|
||||
@override_settings(ZENDESK_URL="dummy", ZENDESK_USER="dummy", ZENDESK_API_KEY="dummy", ZENDESK_CUSTOM_FIELDS={})
|
||||
@mock.patch("util.views.dog_stats_api")
|
||||
@mock.patch("util.views._ZendeskApi", autospec=True)
|
||||
class SubmitFeedbackTest(TestCase):
|
||||
@@ -44,14 +47,12 @@ class SubmitFeedbackTest(TestCase):
|
||||
username="test",
|
||||
profile__name="Test User"
|
||||
)
|
||||
# This contains issue_type and course_id to ensure that tags are submitted correctly
|
||||
self._anon_fields = {
|
||||
"email": "test@edx.org",
|
||||
"name": "Test User",
|
||||
"subject": "a subject",
|
||||
"details": "some details",
|
||||
"issue_type": "test_issue",
|
||||
"course_id": "test_course"
|
||||
"issue_type": "test_issue"
|
||||
}
|
||||
# This does not contain issue_type nor course_id to ensure that they are optional
|
||||
self._auth_fields = {"subject": "a subject", "details": "some details"}
|
||||
@@ -130,13 +131,9 @@ class SubmitFeedbackTest(TestCase):
|
||||
resp = self._build_and_run_request(user, fields)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def _assert_datadog_called(self, datadog_mock, with_tags):
|
||||
expected_datadog_calls = [
|
||||
mock.call.increment(
|
||||
views.DATADOG_FEEDBACK_METRIC,
|
||||
tags=(["course_id:test_course", "issue_type:test_issue"] if with_tags else [])
|
||||
)
|
||||
]
|
||||
def _assert_datadog_called(self, datadog_mock, tags):
|
||||
"""Assert that datadog was called with the correct tags."""
|
||||
expected_datadog_calls = [mock.call.increment(views.DATADOG_FEEDBACK_METRIC, tags=tags)]
|
||||
self.assertEqual(datadog_mock.mock_calls, expected_datadog_calls)
|
||||
|
||||
def test_bad_request_anon_user_no_name(self, zendesk_mock_class, datadog_mock):
|
||||
@@ -184,7 +181,7 @@ class SubmitFeedbackTest(TestCase):
|
||||
"requester": {"name": "Test User", "email": "test@edx.org"},
|
||||
"subject": "a subject",
|
||||
"comment": {"body": "some details"},
|
||||
"tags": ["test_course", "test_issue", "LMS"]
|
||||
"tags": ["test_issue", "LMS"]
|
||||
}
|
||||
}
|
||||
),
|
||||
@@ -206,7 +203,7 @@ class SubmitFeedbackTest(TestCase):
|
||||
)
|
||||
]
|
||||
self.assertEqual(zendesk_mock_instance.mock_calls, expected_zendesk_calls)
|
||||
self._assert_datadog_called(datadog_mock, with_tags=True)
|
||||
self._assert_datadog_called(datadog_mock, ["issue_type:test_issue"])
|
||||
|
||||
@mock.patch("openedx.core.djangoapps.site_configuration.helpers.get_value", fake_get_value)
|
||||
def test_valid_request_anon_user_configuration_override(self, zendesk_mock_class, datadog_mock):
|
||||
@@ -228,7 +225,7 @@ class SubmitFeedbackTest(TestCase):
|
||||
"requester": {"name": "Test User", "email": "test@edx.org"},
|
||||
"subject": "a subject",
|
||||
"comment": {"body": "some details"},
|
||||
"tags": ["test_course", "test_issue", "LMS", "whitelabel_fakeorg"]
|
||||
"tags": ["test_issue", "LMS", "whitelabel_fakeorg"]
|
||||
}
|
||||
}
|
||||
),
|
||||
@@ -250,7 +247,69 @@ class SubmitFeedbackTest(TestCase):
|
||||
)
|
||||
]
|
||||
self.assertEqual(zendesk_mock_instance.mock_calls, expected_zendesk_calls)
|
||||
self._assert_datadog_called(datadog_mock, with_tags=True)
|
||||
self._assert_datadog_called(datadog_mock, ["issue_type:test_issue"])
|
||||
|
||||
@data("course-v1:testOrg+testCourseNumber+testCourseRun", "", None)
|
||||
@override_settings(ZENDESK_CUSTOM_FIELDS={"course_id": 1234, "enrollment_mode": 5678})
|
||||
def test_valid_request_anon_user_with_custom_fields(self, course_id, zendesk_mock, datadog_mock):
|
||||
"""
|
||||
Test a valid request from an anonymous user when configured to use Zendesk Custom Fields.
|
||||
|
||||
The response should have a 200 (success) status code, and a ticket with
|
||||
the given information should have been submitted via the Zendesk API. When course_id is
|
||||
present, it should be sent to Zendesk via a custom field. When course_id is blank or missing,
|
||||
the request should still be processed successfully.
|
||||
"""
|
||||
zendesk_mock_instance = zendesk_mock.return_value
|
||||
zendesk_mock_instance.create_ticket.return_value = 42
|
||||
|
||||
fields = self._anon_fields.copy()
|
||||
|
||||
expected_zendesk_tags = None
|
||||
expected_datadog_tags = None
|
||||
if course_id is not None:
|
||||
fields["course_id"] = course_id
|
||||
expected_zendesk_tags = [course_id, "test_issue", "LMS"]
|
||||
expected_datadog_tags = ["course_id:{}".format(course_id), "issue_type:test_issue"]
|
||||
else:
|
||||
expected_zendesk_tags = ["test_issue", "LMS"]
|
||||
expected_datadog_tags = ["issue_type:test_issue"]
|
||||
|
||||
expected_create_ticket_request = {
|
||||
"ticket": {
|
||||
"recipient": "registration@example.com",
|
||||
"requester": {"name": "Test User", "email": "test@edx.org"},
|
||||
"subject": "a subject",
|
||||
"comment": {"body": "some details"},
|
||||
"tags": expected_zendesk_tags
|
||||
}
|
||||
}
|
||||
|
||||
expected_update_ticket_request = {
|
||||
"ticket": {
|
||||
"comment": {
|
||||
"public": False,
|
||||
"body":
|
||||
"Additional information:\n\n"
|
||||
"Client IP: 1.2.3.4\n"
|
||||
"Host: test_server\n"
|
||||
"Page: test_referer\n"
|
||||
"Browser: test_user_agent"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fields.get("course_id"):
|
||||
expected_custom_fields = [{"id": 1234, "value": fields["course_id"]}]
|
||||
expected_create_ticket_request["ticket"]["custom_fields"] = expected_custom_fields
|
||||
|
||||
self._test_success(self._anon_user, fields)
|
||||
expected_zendesk_calls = [
|
||||
mock.call.create_ticket(expected_create_ticket_request),
|
||||
mock.call.update_ticket(42, expected_update_ticket_request)
|
||||
]
|
||||
self.assertEqual(zendesk_mock_instance.mock_calls, expected_zendesk_calls)
|
||||
self._assert_datadog_called(datadog_mock, expected_datadog_tags)
|
||||
|
||||
def test_bad_request_auth_user_no_subject(self, zendesk_mock_class, datadog_mock):
|
||||
"""Test a request from an authenticated user not specifying `subject`."""
|
||||
@@ -303,7 +362,85 @@ class SubmitFeedbackTest(TestCase):
|
||||
)
|
||||
]
|
||||
self.assertEqual(zendesk_mock_instance.mock_calls, expected_zendesk_calls)
|
||||
self._assert_datadog_called(datadog_mock, with_tags=False)
|
||||
self._assert_datadog_called(datadog_mock, [])
|
||||
|
||||
@data(
|
||||
("course-v1:testOrg+testCourseNumber+testCourseRun", True),
|
||||
("course-v1:testOrg+testCourseNumber+testCourseRun", False),
|
||||
("", None),
|
||||
(None, None)
|
||||
)
|
||||
@unpack
|
||||
@override_settings(ZENDESK_CUSTOM_FIELDS={"course_id": 1234, "enrollment_mode": 5678})
|
||||
def test_valid_request_auth_user_with_custom_fields(self, course_id, enrollment_state, zendesk_mock, datadog_mock):
|
||||
"""
|
||||
Test a valid request from an authenticated user when configured to use Zendesk Custom Fields.
|
||||
|
||||
The response should have a 200 (success) status code, and a ticket with
|
||||
the given information should have been submitted via the Zendesk API. When course_id is
|
||||
present, it should be sent to Zendesk via a custom field, along with the enrollment mode
|
||||
if the user has an active enrollment for that course. When course_id is blank or missing,
|
||||
the request should still be processed successfully.
|
||||
"""
|
||||
zendesk_mock_instance = zendesk_mock.return_value
|
||||
zendesk_mock_instance.create_ticket.return_value = 42
|
||||
|
||||
fields = self._auth_fields.copy()
|
||||
|
||||
expected_zendesk_tags = None
|
||||
expected_datadog_tags = None
|
||||
if course_id is not None:
|
||||
fields["course_id"] = course_id
|
||||
expected_zendesk_tags = [course_id, "LMS"]
|
||||
expected_datadog_tags = ["course_id:{}".format(course_id)]
|
||||
else:
|
||||
expected_zendesk_tags = ["LMS"]
|
||||
expected_datadog_tags = []
|
||||
|
||||
expected_create_ticket_request = {
|
||||
"ticket": {
|
||||
"recipient": "registration@example.com",
|
||||
"requester": {"name": "Test User", "email": "test@edx.org"},
|
||||
"subject": "a subject",
|
||||
"comment": {"body": "some details"},
|
||||
"tags": expected_zendesk_tags
|
||||
}
|
||||
}
|
||||
|
||||
expected_update_ticket_request = {
|
||||
"ticket": {
|
||||
"comment": {
|
||||
"public": False,
|
||||
"body":
|
||||
"Additional information:\n\n"
|
||||
"username: test\n"
|
||||
"Client IP: 1.2.3.4\n"
|
||||
"Host: test_server\n"
|
||||
"Page: test_referer\n"
|
||||
"Browser: test_user_agent",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if fields.get("course_id"):
|
||||
expected_custom_fields = [{"id": 1234, "value": fields["course_id"]}]
|
||||
if enrollment_state is not None:
|
||||
enrollment = CourseEnrollmentFactory.create(
|
||||
user=self._auth_user,
|
||||
course_id=course_id,
|
||||
is_active=enrollment_state
|
||||
)
|
||||
if enrollment.is_active:
|
||||
expected_custom_fields.append({"id": 5678, "value": enrollment.mode})
|
||||
expected_create_ticket_request["ticket"]["custom_fields"] = expected_custom_fields
|
||||
|
||||
self._test_success(self._auth_user, fields)
|
||||
expected_zendesk_calls = [
|
||||
mock.call.create_ticket(expected_create_ticket_request),
|
||||
mock.call.update_ticket(42, expected_update_ticket_request)
|
||||
]
|
||||
self.assertEqual(zendesk_mock_instance.mock_calls, expected_zendesk_calls)
|
||||
self._assert_datadog_called(datadog_mock, expected_datadog_tags)
|
||||
|
||||
def test_get_request(self, zendesk_mock_class, datadog_mock):
|
||||
"""Test that a GET results in a 405 even with all required fields"""
|
||||
@@ -329,7 +466,7 @@ class SubmitFeedbackTest(TestCase):
|
||||
resp = self._build_and_run_request(self._anon_user, self._anon_fields)
|
||||
self.assertEqual(resp.status_code, 500)
|
||||
self.assertFalse(resp.content)
|
||||
self._assert_datadog_called(datadog_mock, with_tags=True)
|
||||
self._assert_datadog_called(datadog_mock, ["issue_type:test_issue"])
|
||||
|
||||
def test_zendesk_error_on_update(self, zendesk_mock_class, datadog_mock):
|
||||
"""
|
||||
@@ -344,7 +481,7 @@ class SubmitFeedbackTest(TestCase):
|
||||
zendesk_mock_instance.update_ticket.side_effect = err
|
||||
resp = self._build_and_run_request(self._anon_user, self._anon_fields)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self._assert_datadog_called(datadog_mock, with_tags=True)
|
||||
self._assert_datadog_called(datadog_mock, ["issue_type:test_issue"])
|
||||
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {"ENABLE_FEEDBACK_SUBMISSION": False})
|
||||
def test_not_enabled(self, zendesk_mock_class, datadog_mock):
|
||||
|
||||
@@ -25,6 +25,7 @@ from edxmako.shortcuts import render_to_response, render_to_string
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
import track.views
|
||||
from student.roles import GlobalStaff
|
||||
from student.models import CourseEnrollment
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -222,6 +223,40 @@ class _ZendeskApi(object):
|
||||
return None
|
||||
|
||||
|
||||
def _get_zendesk_custom_field_context(request):
|
||||
"""
|
||||
Construct a dictionary of data that can be stored in Zendesk custom fields.
|
||||
"""
|
||||
context = {}
|
||||
|
||||
course_id = request.POST.get("course_id")
|
||||
if not course_id:
|
||||
return context
|
||||
|
||||
context["course_id"] = course_id
|
||||
if not request.user.is_authenticated():
|
||||
return context
|
||||
|
||||
enrollment = CourseEnrollment.get_enrollment(request.user, CourseKey.from_string(course_id))
|
||||
if enrollment and enrollment.is_active:
|
||||
context["enrollment_mode"] = enrollment.mode
|
||||
|
||||
return context
|
||||
|
||||
|
||||
def _format_zendesk_custom_fields(context):
|
||||
"""
|
||||
Format the data in `context` for compatibility with the Zendesk API.
|
||||
Ignore any keys that have not been configured in `ZENDESK_CUSTOM_FIELDS`.
|
||||
"""
|
||||
custom_fields = []
|
||||
for key, val, in settings.ZENDESK_CUSTOM_FIELDS.items():
|
||||
if key in context:
|
||||
custom_fields.append({"id": val, "value": context[key]})
|
||||
|
||||
return custom_fields
|
||||
|
||||
|
||||
def _record_feedback_in_zendesk(
|
||||
realname,
|
||||
email,
|
||||
@@ -231,7 +266,8 @@ def _record_feedback_in_zendesk(
|
||||
additional_info,
|
||||
group_name=None,
|
||||
require_update=False,
|
||||
support_email=None
|
||||
support_email=None,
|
||||
custom_fields=None
|
||||
):
|
||||
"""
|
||||
Create a new user-requested Zendesk ticket.
|
||||
@@ -246,6 +282,8 @@ def _record_feedback_in_zendesk(
|
||||
If `require_update` is provided, returns False when the update does not
|
||||
succeed. This allows using the private comment to add necessary information
|
||||
which the user will not see in followup emails from support.
|
||||
|
||||
If `custom_fields` is provided, submits data to those fields in Zendesk.
|
||||
"""
|
||||
zendesk_api = _ZendeskApi()
|
||||
|
||||
@@ -271,6 +309,10 @@ def _record_feedback_in_zendesk(
|
||||
"tags": zendesk_tags
|
||||
}
|
||||
}
|
||||
|
||||
if custom_fields:
|
||||
new_ticket["ticket"]["custom_fields"] = custom_fields
|
||||
|
||||
group = None
|
||||
if group_name is not None:
|
||||
group = zendesk_api.get_group(group_name)
|
||||
@@ -412,6 +454,11 @@ def submit_feedback(request):
|
||||
if not settings.ZENDESK_URL or not settings.ZENDESK_USER or not settings.ZENDESK_API_KEY:
|
||||
raise Exception("Zendesk enabled but not configured")
|
||||
|
||||
custom_fields = None
|
||||
if settings.ZENDESK_CUSTOM_FIELDS:
|
||||
custom_field_context = _get_zendesk_custom_field_context(request)
|
||||
custom_fields = _format_zendesk_custom_fields(custom_field_context)
|
||||
|
||||
success = _record_feedback_in_zendesk(
|
||||
context["realname"],
|
||||
context["email"],
|
||||
@@ -419,7 +466,8 @@ def submit_feedback(request):
|
||||
context["details"],
|
||||
context["tags"],
|
||||
context["additional_info"],
|
||||
support_email=context["support_email"]
|
||||
support_email=context["support_email"],
|
||||
custom_fields=custom_fields
|
||||
)
|
||||
|
||||
_record_feedback_in_datadog(context["tags"])
|
||||
|
||||
@@ -333,6 +333,8 @@ COMMENTS_SERVICE_URL = ENV_TOKENS.get("COMMENTS_SERVICE_URL", '')
|
||||
COMMENTS_SERVICE_KEY = ENV_TOKENS.get("COMMENTS_SERVICE_KEY", '')
|
||||
CERT_QUEUE = ENV_TOKENS.get("CERT_QUEUE", 'test-pull')
|
||||
ZENDESK_URL = ENV_TOKENS.get('ZENDESK_URL', ZENDESK_URL)
|
||||
ZENDESK_CUSTOM_FIELDS = ENV_TOKENS.get('ZENDESK_CUSTOM_FIELDS', ZENDESK_CUSTOM_FIELDS)
|
||||
|
||||
FEEDBACK_SUBMISSION_EMAIL = ENV_TOKENS.get("FEEDBACK_SUBMISSION_EMAIL")
|
||||
MKTG_URLS = ENV_TOKENS.get('MKTG_URLS', MKTG_URLS)
|
||||
|
||||
|
||||
@@ -1003,6 +1003,7 @@ FEEDBACK_SUBMISSION_EMAIL = None
|
||||
ZENDESK_URL = None
|
||||
ZENDESK_USER = None
|
||||
ZENDESK_API_KEY = None
|
||||
ZENDESK_CUSTOM_FIELDS = {}
|
||||
|
||||
##### EMBARGO #####
|
||||
EMBARGO_SITE_REDIRECT_URL = None
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
@import 'shared/modal';
|
||||
@import 'shared/activation_messages';
|
||||
@import 'shared/unsubscribe';
|
||||
@import 'shared/help-tab';
|
||||
|
||||
// shared - platform
|
||||
@import 'multicourse/home';
|
||||
|
||||
@@ -78,3 +78,9 @@
|
||||
padding: 0 $baseline $baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.feedback-form-select {
|
||||
background: $white;
|
||||
margin-bottom: $baseline;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
5
lms/static/sass/shared/_help-tab.scss
Normal file
5
lms/static/sass/shared/_help-tab.scss
Normal file
@@ -0,0 +1,5 @@
|
||||
.feedback-form-select {
|
||||
background: $white;
|
||||
margin-bottom: $baseline;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -99,15 +99,21 @@ from xmodule.tabs import CourseTabList
|
||||
<label data-field="email" for="feedback_form_email">${_('E-mail')}*</label>
|
||||
<input name="email" type="text" id="feedback_form_email" required>
|
||||
% endif
|
||||
|
||||
<div class="js-course-id-anchor">
|
||||
% if course:
|
||||
<input name="course_id" type="hidden" value="${unicode(course.id)}">
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<label data-field="subject" for="feedback_form_subject">${_('Briefly describe your issue')}*</label>
|
||||
<input name="subject" type="text" id="feedback_form_subject" required>
|
||||
|
||||
<label data-field="details" for="feedback_form_details">${_('Tell us the details')}*</label>
|
||||
<span class="tip" id="feedback_form_details_tip">${_('Describe what you were doing when you encountered the issue. Include any details that will help us to troubleshoot, including error messages that you saw.')}</span>
|
||||
<textarea name="details" id="feedback_form_details" required aria-describedby="feedback_form_details_tip"></textarea>
|
||||
|
||||
<input name="issue_type" type="hidden">
|
||||
% if course:
|
||||
<input name="course_id" type="hidden" value="${unicode(course.id)}">
|
||||
% endif
|
||||
<div class="submit">
|
||||
<input name="submit" type="submit" value="${_('Submit')}" id="feedback_submit">
|
||||
</div>
|
||||
@@ -138,7 +144,12 @@ from xmodule.tabs import CourseTabList
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
var $helpModal = $("#help-modal"),
|
||||
var currentCourseId,
|
||||
courseOptions = [],
|
||||
userAuthenticated = false,
|
||||
courseOptionsLoadInProgress = false,
|
||||
finishedLoadingCourseOptions = false,
|
||||
$helpModal = $("#help-modal"),
|
||||
$closeButton = $("#help-modal .close-modal"),
|
||||
$leanOverlay = $("#lean_overlay"),
|
||||
$feedbackForm = $("#feedback_form"),
|
||||
@@ -149,11 +160,101 @@ $(document).ready(function() {
|
||||
$('area,input,select,textarea,button').removeAttr('tabindex');
|
||||
$(".help-tab a").focus();
|
||||
$leanOverlay.removeAttr('tabindex');
|
||||
},
|
||||
showFeedback = function(event, issue_type, title, subject_label, details_label) {
|
||||
event.preventDefault();
|
||||
DialogTabControls.initializeTabKeyValues("#feedback_form_wrapper", $closeButton);
|
||||
$("#feedback_form input[name='issue_type']").val(issue_type);
|
||||
$("#feedback_form_wrapper header").html("<h2>" + title + "</h2><hr>");
|
||||
$("#feedback_form_wrapper label[data-field='subject']").html(subject_label);
|
||||
$("#feedback_form_wrapper label[data-field='details']").html(details_label);
|
||||
if (userAuthenticated && finishedLoadingCourseOptions && courseOptions.length > 1) {
|
||||
$('.js-course-id-anchor').html([
|
||||
'<label for="feedback_form_course">' + '${_("Course") | n, js_escaped_string}' + '</label>',
|
||||
'<select name="course_id" id="feedback_form_course" class="feedback-form-select">',
|
||||
courseOptions.join(''),
|
||||
'</select>'
|
||||
].join(''));
|
||||
}
|
||||
$("#help_wrapper").css("display", "none");
|
||||
$("#feedback_form_wrapper").css("display", "block");
|
||||
$closeButton.focus();
|
||||
},
|
||||
loadCourseOptions = function() {
|
||||
courseOptionsLoadInProgress = true;
|
||||
$.ajax({
|
||||
url: '/api/enrollment/v1/enrollment',
|
||||
success: function(data) {
|
||||
var i,
|
||||
courseDetails,
|
||||
courseName,
|
||||
courseId,
|
||||
option,
|
||||
defaultOptionText = '${_("- Select -") | n, js_escaped_string}',
|
||||
markedSelectedOption = false;
|
||||
|
||||
// Make sure courseOptions is empty before we begin pushing options into it.
|
||||
courseOptions = [];
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
courseDetails = data[i].course_details;
|
||||
if (!courseDetails) {
|
||||
continue;
|
||||
}
|
||||
|
||||
courseName = courseDetails.course_name;
|
||||
courseId = courseDetails.course_id;
|
||||
if (!(courseName && courseId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Build an option for this course and select it if it's the course we're currently viewing.
|
||||
if (!markedSelectedOption && courseId === currentCourseId) {
|
||||
option = buildCourseOption(courseName, courseId, true);
|
||||
markedSelectedOption = true;
|
||||
} else {
|
||||
option = buildCourseOption(courseName, courseId, false);
|
||||
}
|
||||
|
||||
courseOptions.push(option);
|
||||
}
|
||||
|
||||
// Build the default option and select it if we haven't already selected another option.
|
||||
option = buildCourseOption(defaultOptionText, '', !markedSelectedOption);
|
||||
|
||||
// Add the default option to the head of the courseOptions Array.
|
||||
courseOptions.unshift(option);
|
||||
|
||||
finishedLoadingCourseOptions = true;
|
||||
},
|
||||
complete: function() {
|
||||
courseOptionsLoadInProgress = false;
|
||||
}
|
||||
});
|
||||
},
|
||||
buildCourseOption = function(courseName, courseId, selected) {
|
||||
var option = '<option value="' + _.escape(courseId) + '"';
|
||||
if (selected) {
|
||||
option += ' selected';
|
||||
}
|
||||
option += '>' + _.escape(courseName) + '</option>';
|
||||
return option;
|
||||
};
|
||||
|
||||
% if user.is_authenticated():
|
||||
userAuthenticated = true;
|
||||
% endif
|
||||
|
||||
% if course:
|
||||
currentCourseId = "${unicode(course.id) | n, js_escaped_string}";
|
||||
% endif
|
||||
|
||||
DialogTabControls.setKeydownListener($helpModal, $closeButton);
|
||||
|
||||
$(".help-tab").click(function() {
|
||||
if (userAuthenticated && !finishedLoadingCourseOptions && !courseOptionsLoadInProgress) {
|
||||
loadCourseOptions();
|
||||
}
|
||||
$helpModal.css("position", "absolute");
|
||||
DialogTabControls.initializeTabKeyValues("#help_wrapper", $closeButton);
|
||||
$(".field-error").removeClass("field-error");
|
||||
@@ -171,18 +272,6 @@ $(document).ready(function() {
|
||||
$closeButton.focus();
|
||||
});
|
||||
|
||||
showFeedback = function(event, issue_type, title, subject_label, details_label) {
|
||||
$("#help_wrapper").css("display", "none");
|
||||
DialogTabControls.initializeTabKeyValues("#feedback_form_wrapper", $closeButton);
|
||||
$("#feedback_form input[name='issue_type']").val(issue_type);
|
||||
$("#feedback_form_wrapper").css("display", "block");
|
||||
$("#feedback_form_wrapper header").html("<h2>" + title + "</h2><hr>");
|
||||
$("#feedback_form_wrapper label[data-field='subject']").html(subject_label);
|
||||
$("#feedback_form_wrapper label[data-field='details']").html(details_label);
|
||||
$closeButton.focus();
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
$("#feedback_link_problem").click(function(event) {
|
||||
$("#feedback_form_details_tip").css({"display": "block", "padding-bottom": "5px"});
|
||||
showFeedback(
|
||||
|
||||
Reference in New Issue
Block a user