Readonly for enrollment end date/time on edX (for non-global-staff)
TNL-2694 Add accessibility aria-readonly attributes
This commit is contained in:
@@ -16,6 +16,9 @@ from models.settings.course_details import (CourseDetails, CourseSettingsEncoder
|
||||
from models.settings.course_grading import CourseGradingModel
|
||||
from contentstore.utils import reverse_course_url, reverse_usage_url
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from student.roles import CourseInstructorRole
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
|
||||
from models.settings.course_metadata import CourseMetadata
|
||||
from xmodule.fields import Date
|
||||
@@ -1106,3 +1109,116 @@ class CourseGraderUpdatesTest(CourseTestCase):
|
||||
self.assertEqual(obj, grader)
|
||||
current_graders = CourseGradingModel.fetch(self.course.id).graders
|
||||
self.assertEqual(len(self.starting_graders) + 1, len(current_graders))
|
||||
|
||||
|
||||
class CourseEnrollmentEndFieldTest(CourseTestCase):
|
||||
"""
|
||||
Base class to test the enrollment end fields in the course settings details view in Studio
|
||||
when using marketing site flag and global vs non-global staff to access the page.
|
||||
"""
|
||||
NOT_EDITABLE_HELPER_MESSAGE = "Contact your edX Partner Manager to update these settings."
|
||||
NOT_EDITABLE_DATE_WRAPPER = "<div class=\"field date is-not-editable\" id=\"field-enrollment-end-date\">"
|
||||
NOT_EDITABLE_TIME_WRAPPER = "<div class=\"field time is-not-editable\" id=\"field-enrollment-end-time\">"
|
||||
NOT_EDITABLE_DATE_FIELD = "<input type=\"text\" class=\"end-date date end\" \
|
||||
id=\"course-enrollment-end-date\" placeholder=\"MM/DD/YYYY\" autocomplete=\"off\" readonly aria-readonly=\"true\" />"
|
||||
NOT_EDITABLE_TIME_FIELD = "<input type=\"text\" class=\"time end\" id=\"course-enrollment-end-time\" \
|
||||
value=\"\" placeholder=\"HH:MM\" autocomplete=\"off\" readonly aria-readonly=\"true\" />"
|
||||
|
||||
EDITABLE_DATE_WRAPPER = "<div class=\"field date \" id=\"field-enrollment-end-date\">"
|
||||
EDITABLE_TIME_WRAPPER = "<div class=\"field time \" id=\"field-enrollment-end-time\">"
|
||||
EDITABLE_DATE_FIELD = "<input type=\"text\" class=\"end-date date end\" \
|
||||
id=\"course-enrollment-end-date\" placeholder=\"MM/DD/YYYY\" autocomplete=\"off\" />"
|
||||
EDITABLE_TIME_FIELD = "<input type=\"text\" class=\"time end\" \
|
||||
id=\"course-enrollment-end-time\" value=\"\" placeholder=\"HH:MM\" autocomplete=\"off\" />"
|
||||
|
||||
EDITABLE_ELEMENTS = [
|
||||
EDITABLE_DATE_WRAPPER,
|
||||
EDITABLE_TIME_WRAPPER,
|
||||
EDITABLE_DATE_FIELD,
|
||||
EDITABLE_TIME_FIELD,
|
||||
]
|
||||
|
||||
NOT_EDITABLE_ELEMENTS = [
|
||||
NOT_EDITABLE_HELPER_MESSAGE,
|
||||
NOT_EDITABLE_DATE_WRAPPER,
|
||||
NOT_EDITABLE_TIME_WRAPPER,
|
||||
NOT_EDITABLE_DATE_FIELD,
|
||||
NOT_EDITABLE_TIME_FIELD,
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
""" Initialize course used to test enrollment fields. """
|
||||
super(CourseEnrollmentEndFieldTest, self).setUp()
|
||||
self.course = CourseFactory.create(org='edX', number='dummy', display_name='Marketing Site Course')
|
||||
self.course_details_url = reverse_course_url('settings_handler', unicode(self.course.id))
|
||||
|
||||
def _get_course_details_response(self, global_staff):
|
||||
""" Return the course details page as either global or non-global staff"""
|
||||
user = UserFactory(is_staff=global_staff)
|
||||
CourseInstructorRole(self.course.id).add_users(user)
|
||||
|
||||
self.client.login(username=user.username, password='test')
|
||||
|
||||
return self.client.get_html(self.course_details_url)
|
||||
|
||||
def _verify_editable(self, response):
|
||||
""" Verify that the response has expected editable fields.
|
||||
|
||||
Assert that all editable field content exists and no
|
||||
uneditable field content exists for enrollment end fields.
|
||||
"""
|
||||
self.assertEqual(response.status_code, 200)
|
||||
for element in self.NOT_EDITABLE_ELEMENTS:
|
||||
self.assertNotContains(response, element)
|
||||
|
||||
for element in self.EDITABLE_ELEMENTS:
|
||||
self.assertContains(response, element)
|
||||
|
||||
def _verify_not_editable(self, response):
|
||||
""" Verify that the response has expected non-editable fields.
|
||||
|
||||
Assert that all uneditable field content exists and no
|
||||
editable field content exists for enrollment end fields.
|
||||
"""
|
||||
self.assertEqual(response.status_code, 200)
|
||||
for element in self.NOT_EDITABLE_ELEMENTS:
|
||||
self.assertContains(response, element)
|
||||
|
||||
for element in self.EDITABLE_ELEMENTS:
|
||||
self.assertNotContains(response, element)
|
||||
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': False})
|
||||
def test_course_details_with_disabled_setting_global_staff(self):
|
||||
""" Test that user enrollment end date is editable in response.
|
||||
|
||||
Feature flag 'ENABLE_MKTG_SITE' is not enabled.
|
||||
User is global staff.
|
||||
"""
|
||||
self._verify_editable(self._get_course_details_response(True))
|
||||
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': False})
|
||||
def test_course_details_with_disabled_setting_non_global_staff(self):
|
||||
""" Test that user enrollment end date is editable in response.
|
||||
|
||||
Feature flag 'ENABLE_MKTG_SITE' is not enabled.
|
||||
User is non-global staff.
|
||||
"""
|
||||
self._verify_editable(self._get_course_details_response(False))
|
||||
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': True})
|
||||
def test_course_details_with_enabled_setting_global_staff(self):
|
||||
""" Test that user enrollment end date is editable in response.
|
||||
|
||||
Feature flag 'ENABLE_MKTG_SITE' is enabled.
|
||||
User is global staff.
|
||||
"""
|
||||
self._verify_editable(self._get_course_details_response(True))
|
||||
|
||||
@mock.patch.dict("django.conf.settings.FEATURES", {'ENABLE_MKTG_SITE': True})
|
||||
def test_course_details_with_enabled_setting_non_global_staff(self):
|
||||
""" Test that user enrollment end date is not editable in response.
|
||||
|
||||
Feature flag 'ENABLE_MKTG_SITE' is enabled.
|
||||
User is non-global staff.
|
||||
"""
|
||||
self._verify_not_editable(self._get_course_details_response(False))
|
||||
|
||||
@@ -903,12 +903,15 @@ def settings_handler(request, course_key_string):
|
||||
|
||||
# see if the ORG of this course can be attributed to a 'Microsite'. In that case, the
|
||||
# course about page should be editable in Studio
|
||||
about_page_editable = not microsite.get_value_for_org(
|
||||
marketing_site_enabled = microsite.get_value_for_org(
|
||||
course_module.location.org,
|
||||
'ENABLE_MKTG_SITE',
|
||||
settings.FEATURES.get('ENABLE_MKTG_SITE', False)
|
||||
)
|
||||
|
||||
about_page_editable = not marketing_site_enabled
|
||||
enrollment_end_editable = GlobalStaff().has_user(request.user) or not marketing_site_enabled
|
||||
|
||||
short_description_editable = settings.FEATURES.get('EDITABLE_SHORT_DESCRIPTION', True)
|
||||
settings_context = {
|
||||
'context_course': course_module,
|
||||
@@ -924,6 +927,7 @@ def settings_handler(request, course_key_string):
|
||||
'credit_eligibility_enabled': credit_eligibility_enabled,
|
||||
'is_credit_course': False,
|
||||
'show_min_grade_warning': False,
|
||||
'enrollment_end_editable': enrollment_end_editable,
|
||||
}
|
||||
if prerequisite_course_enabled:
|
||||
courses, in_process_course_actions = get_courses_accessible_to_user(request)
|
||||
|
||||
@@ -62,6 +62,27 @@
|
||||
margin-top: ($baseline);
|
||||
}
|
||||
|
||||
// specific fields - settings details
|
||||
.settings-details {
|
||||
|
||||
// course details that should appear more like content than elements to change
|
||||
.is-not-editable {
|
||||
|
||||
label {
|
||||
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
@extend %t-copy-lead1;
|
||||
@extend %t-strong;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// in form - elements
|
||||
.group-settings {
|
||||
@@ -305,21 +326,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
// course details that should appear more like content than elements to change
|
||||
.field.is-not-editable {
|
||||
|
||||
label {
|
||||
|
||||
}
|
||||
.is-not-editable {
|
||||
|
||||
input, textarea {
|
||||
@extend %t-copy-lead1;
|
||||
@extend %t-strong;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,6 +448,13 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.is-not-editable {
|
||||
|
||||
input, textarea {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.field {
|
||||
@include float(left);
|
||||
width: flex-grid(3, 9);
|
||||
|
||||
@@ -220,17 +220,25 @@ CMS.URL.UPLOAD_ASSET = '${upload_asset_url}';
|
||||
<span class="tip tip-stacked timezone">${_("(UTC)")}</span>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<%
|
||||
enrollment_end_readonly = "readonly aria-readonly=\"true\"" if not enrollment_end_editable else ""
|
||||
enrollment_end_editable_class = "is-not-editable" if not enrollment_end_editable else ""
|
||||
%>
|
||||
<li class="field-group field-group-enrollment-end" id="enrollment-end">
|
||||
<div class="field date" id="field-enrollment-end-date">
|
||||
<div class="field date ${enrollment_end_editable_class}" id="field-enrollment-end-date">
|
||||
<label for="course-enrollment-end-date">${_("Enrollment End Date")}</label>
|
||||
<input type="text" class="end-date date end" id="course-enrollment-end-date" placeholder="MM/DD/YYYY" autocomplete="off" />
|
||||
<span class="tip tip-stacked">${_("Last day students can enroll")}</span>
|
||||
<input type="text" class="end-date date end" id="course-enrollment-end-date" placeholder="MM/DD/YYYY" autocomplete="off" ${enrollment_end_readonly} />
|
||||
<span class="tip tip-stacked">
|
||||
${_("Last day students can enroll.")}
|
||||
% if not enrollment_end_editable:
|
||||
${_("Contact your edX Partner Manager to update these settings.")}
|
||||
% endif
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="field time" id="field-enrollment-end-time">
|
||||
<div class="field time ${enrollment_end_editable_class}" id="field-enrollment-end-time">
|
||||
<label for="course-enrollment-end-time">${_("Enrollment End Time")}</label>
|
||||
<input type="text" class="time end" id="course-enrollment-end-time" value="" placeholder="HH:MM" autocomplete="off" />
|
||||
<input type="text" class="time end" id="course-enrollment-end-time" value="" placeholder="HH:MM" autocomplete="off" ${enrollment_end_readonly} />
|
||||
<span class="tip tip-stacked timezone">${_("(UTC)")}</span>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
Reference in New Issue
Block a user