Commit 3e52b8fa by Matt Drayer

mattdrayer/SOL-947: Refactor Web/HTML certificate URL patterns

parent c8b87179
...@@ -6,7 +6,10 @@ from io import BytesIO ...@@ -6,7 +6,10 @@ from io import BytesIO
from pytz import UTC from pytz import UTC
from PIL import Image from PIL import Image
import json import json
from django.conf import settings from django.conf import settings
from django.test.utils import override_settings
from contentstore.tests.utils import CourseTestCase from contentstore.tests.utils import CourseTestCase
from contentstore.views import assets from contentstore.views import assets
from contentstore.utils import reverse_course_url from contentstore.utils import reverse_course_url
...@@ -28,7 +31,11 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT ...@@ -28,7 +31,11 @@ TEST_DATA_DIR = settings.COMMON_TEST_DATA_ROOT
MAX_FILE_SIZE = settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB * 1000 ** 2 MAX_FILE_SIZE = settings.MAX_ASSET_UPLOAD_FILE_SIZE_IN_MB * 1000 ** 2
FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
class AssetsTestCase(CourseTestCase): class AssetsTestCase(CourseTestCase):
""" """
Parent class for all asset tests. Parent class for all asset tests.
......
...@@ -6,6 +6,9 @@ Group Configuration Tests. ...@@ -6,6 +6,9 @@ Group Configuration Tests.
import json import json
import mock import mock
from django.conf import settings
from django.test.utils import override_settings
from opaque_keys.edx.keys import AssetKey from opaque_keys.edx.keys import AssetKey
from opaque_keys.edx.locations import AssetLocation from opaque_keys.edx.locations import AssetLocation
...@@ -20,6 +23,9 @@ from contentstore.views.certificates import CertificateManager ...@@ -20,6 +23,9 @@ from contentstore.views.certificates import CertificateManager
from django.test.utils import override_settings from django.test.utils import override_settings
from contentstore.utils import get_lms_link_for_certificate_web_view from contentstore.utils import get_lms_link_for_certificate_web_view
FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True
CERTIFICATE_JSON = { CERTIFICATE_JSON = {
u'name': u'Test certificate', u'name': u'Test certificate',
u'description': u'Test description', u'description': u'Test description',
...@@ -185,6 +191,7 @@ class CertificatesBaseTestCase(object): ...@@ -185,6 +191,7 @@ class CertificatesBaseTestCase(object):
# pylint: disable=no-member # pylint: disable=no-member
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase, HelperMethods): class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase, HelperMethods):
""" """
Test cases for certificates_list_handler. Test cases for certificates_list_handler.
...@@ -323,6 +330,7 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase, ...@@ -323,6 +330,7 @@ class CertificatesListHandlerTestCase(CourseTestCase, CertificatesBaseTestCase,
self.assertNotEqual(new_certificate.get('id'), prev_certificate.get('id')) self.assertNotEqual(new_certificate.get('id'), prev_certificate.get('id'))
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase, HelperMethods): class CertificatesDetailHandlerTestCase(CourseTestCase, CertificatesBaseTestCase, HelperMethods):
""" """
Test cases for CertificatesDetailHandlerTestCase. Test cases for CertificatesDetailHandlerTestCase.
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
"FEATURES": { "FEATURES": {
"AUTH_USE_OPENID_PROVIDER": true, "AUTH_USE_OPENID_PROVIDER": true,
"CERTIFICATES_ENABLED": true, "CERTIFICATES_ENABLED": true,
"CERTIFICATES_HTML_VIEW": true,
"DASHBOARD_SHARE_SETTINGS": { "DASHBOARD_SHARE_SETTINGS": {
"CUSTOM_COURSE_URLS": true "CUSTOM_COURSE_URLS": true
}, },
......
<%namespace name='static' file='../static_content.html'/> <%namespace name='static' file='../static_content.html'/>
<%! <%!
from django.conf import settings
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from contentstore.context_processors import doc_url from contentstore.context_processors import doc_url
...@@ -35,8 +36,12 @@ ...@@ -35,8 +36,12 @@
grading_url = reverse('contentstore.views.grading_handler', kwargs={'course_key_string': unicode(course_key)}) grading_url = reverse('contentstore.views.grading_handler', kwargs={'course_key_string': unicode(course_key)})
advanced_settings_url = reverse('contentstore.views.advanced_settings_handler', kwargs={'course_key_string': unicode(course_key)}) advanced_settings_url = reverse('contentstore.views.advanced_settings_handler', kwargs={'course_key_string': unicode(course_key)})
tabs_url = reverse('contentstore.views.tabs_handler', kwargs={'course_key_string': unicode(course_key)}) tabs_url = reverse('contentstore.views.tabs_handler', kwargs={'course_key_string': unicode(course_key)})
%>
% if settings.FEATURES.get("CERTIFICATES_HTML_VIEW") and context_course:
<%
certificates_url = reverse('contentstore.views.certificates.certificates_list_handler', kwargs={'course_key_string': unicode(course_key)}) certificates_url = reverse('contentstore.views.certificates.certificates_list_handler', kwargs={'course_key_string': unicode(course_key)})
%> %>
% endif
<h2 class="info-course"> <h2 class="info-course">
<span class="sr">${_("Current Course:")}</span> <span class="sr">${_("Current Course:")}</span>
<a class="course-link" href="${index_url}"> <a class="course-link" href="${index_url}">
......
...@@ -112,14 +112,6 @@ urlpatterns += patterns( ...@@ -112,14 +112,6 @@ urlpatterns += patterns(
url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN), 'group_configurations_list_handler'), url(r'^group_configurations/{}$'.format(settings.COURSE_KEY_PATTERN), 'group_configurations_list_handler'),
url(r'^group_configurations/{}/(?P<group_configuration_id>\d+)(/)?(?P<group_id>\d+)?$'.format( url(r'^group_configurations/{}/(?P<group_configuration_id>\d+)(/)?(?P<group_id>\d+)?$'.format(
settings.COURSE_KEY_PATTERN), 'group_configurations_detail_handler'), settings.COURSE_KEY_PATTERN), 'group_configurations_detail_handler'),
url(r'^certificates/{}$'.format(settings.COURSE_KEY_PATTERN), 'certificates.certificates_list_handler'),
url(r'^certificates/{}/(?P<certificate_id>\d+)/signatories/(?P<signatory_id>\d+)?$'.format(
settings.COURSE_KEY_PATTERN), 'certificates.signatory_detail_handler'),
url(r'^certificates/{}/(?P<certificate_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN),
'certificates.certificates_detail_handler'),
url(r'^certificates/activation/{}/'.format(settings.COURSE_KEY_PATTERN),
'certificates.certificate_activation_handler'),
url(r'^api/val/v0/', include('edxval.urls')), url(r'^api/val/v0/', include('edxval.urls')),
) )
...@@ -178,6 +170,19 @@ if settings.FEATURES.get('ENTRANCE_EXAMS'): ...@@ -178,6 +170,19 @@ if settings.FEATURES.get('ENTRANCE_EXAMS'):
url(r'^course/{}/entrance_exam/?$'.format(settings.COURSE_KEY_PATTERN), 'contentstore.views.entrance_exam'), url(r'^course/{}/entrance_exam/?$'.format(settings.COURSE_KEY_PATTERN), 'contentstore.views.entrance_exam'),
) )
# Enable Web/HTML Certificates
if settings.FEATURES.get('CERTIFICATES_HTML_VIEW'):
urlpatterns += (
url(r'^certificates/activation/{}/'.format(settings.COURSE_KEY_PATTERN),
'contentstore.views.certificates.certificate_activation_handler'),
url(r'^certificates/{}/(?P<certificate_id>\d+)/signatories/(?P<signatory_id>\d+)?$'.format(
settings.COURSE_KEY_PATTERN), 'contentstore.views.certificates.signatory_detail_handler'),
url(r'^certificates/{}/(?P<certificate_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN),
'contentstore.views.certificates.certificates_detail_handler'),
url(r'^certificates/{}$'.format(settings.COURSE_KEY_PATTERN),
'contentstore.views.certificates.certificates_list_handler')
)
if settings.DEBUG: if settings.DEBUG:
try: try:
from .urls_dev import urlpatterns as dev_urlpatterns from .urls_dev import urlpatterns as dev_urlpatterns
......
...@@ -16,6 +16,9 @@ class SettingsPage(CoursePage): ...@@ -16,6 +16,9 @@ class SettingsPage(CoursePage):
url_path = "settings/details" url_path = "settings/details"
################
# Helpers
################
def is_browser_on_page(self): def is_browser_on_page(self):
return self.q(css='body.view-settings').present return self.q(css='body.view-settings').present
...@@ -38,6 +41,9 @@ class SettingsPage(CoursePage): ...@@ -38,6 +41,9 @@ class SettingsPage(CoursePage):
results = self.get_elements(css_selector=css_selector) results = self.get_elements(css_selector=css_selector)
return results[0] if results else None return results[0] if results else None
################
# Properties
################
@property @property
def pre_requisite_course_options(self): def pre_requisite_course_options(self):
""" """
...@@ -60,25 +66,6 @@ class SettingsPage(CoursePage): ...@@ -60,25 +66,6 @@ class SettingsPage(CoursePage):
""" """
return self.get_element('#alert-confirmation-title') return self.get_element('#alert-confirmation-title')
def require_entrance_exam(self, required=True):
"""
Set the entrance exam requirement via the checkbox.
"""
checkbox = self.entrance_exam_field
selected = checkbox.is_selected()
if required and not selected:
checkbox.click()
self.wait_for_element_visibility(
'#entrance-exam-minimum-score-pct',
'Entrance exam minimum score percent is visible'
)
if not required and selected:
checkbox.click()
self.wait_for_element_invisibility(
'#entrance-exam-minimum-score-pct',
'Entrance exam minimum score percent is invisible'
)
@property @property
def course_license(self): def course_license(self):
""" """
...@@ -123,6 +110,45 @@ class SettingsPage(CoursePage): ...@@ -123,6 +110,45 @@ class SettingsPage(CoursePage):
raise Exception("Invalid license name: {name}".format(name=license_name)) raise Exception("Invalid license name: {name}".format(name=license_name))
button.click() button.click()
################
# Waits
################
def wait_for_prerequisite_course_options(self):
"""
Ensure the pre_requisite_course_options dropdown selector is displayed
"""
EmptyPromise(
lambda: self.q(css="#pre-requisite-course").present,
'Prerequisite course dropdown selector is displayed'
).fulfill()
################
# Clicks
################
################
# Workflows
################
def require_entrance_exam(self, required=True):
"""
Set the entrance exam requirement via the checkbox.
"""
checkbox = self.entrance_exam_field
selected = checkbox.is_selected()
if required and not selected:
checkbox.click()
self.wait_for_element_visibility(
'#entrance-exam-minimum-score-pct',
'Entrance exam minimum score percent is visible'
)
if not required and selected:
checkbox.click()
self.wait_for_element_invisibility(
'#entrance-exam-minimum-score-pct',
'Entrance exam minimum score percent is invisible'
)
def save_changes(self, wait_for_confirmation=True): def save_changes(self, wait_for_confirmation=True):
""" """
Clicks save button, waits for confirmation unless otherwise specified Clicks save button, waits for confirmation unless otherwise specified
......
...@@ -299,9 +299,11 @@ class Certificate(object): ...@@ -299,9 +299,11 @@ class Certificate(object):
Delete the certificate Delete the certificate
""" """
self.wait_for_certificate_delete_button() self.wait_for_certificate_delete_button()
self.find_css('.actions .delete').first.click() self.find_css('.actions .delete').first.click()
self.page.wait_for_confirmation_prompt() self.page.wait_for_confirmation_prompt()
self.find_css('.action-primary').first.click() self.page.q(css='a.button.action-primary').first.click()
self.page.q(css='a.button.action-primary').first.click()
self.page.wait_for_ajax() self.page.wait_for_ajax()
......
...@@ -69,6 +69,7 @@ class SettingsMilestonesTest(StudioCourseTest): ...@@ -69,6 +69,7 @@ class SettingsMilestonesTest(StudioCourseTest):
# Refresh the page to load the new course fixture and populate the prrequisite course dropdown # Refresh the page to load the new course fixture and populate the prrequisite course dropdown
# Then select the prerequisite course and save the changes # Then select the prerequisite course and save the changes
self.settings_detail.refresh_page() self.settings_detail.refresh_page()
self.settings_detail.wait_for_prerequisite_course_options()
select_option_by_value( select_option_by_value(
browser_query=self.settings_detail.pre_requisite_course_options, browser_query=self.settings_detail.pre_requisite_course_options,
value=pre_requisite_course_id value=pre_requisite_course_id
...@@ -79,8 +80,9 @@ class SettingsMilestonesTest(StudioCourseTest): ...@@ -79,8 +80,9 @@ class SettingsMilestonesTest(StudioCourseTest):
self.settings_detail.alert_confirmation_title.text self.settings_detail.alert_confirmation_title.text
) )
# Refresh the page again to confirm the prerequisite course selection is properly reflected # Refresh the page again and confirm the prerequisite course selection is properly reflected
self.settings_detail.refresh_page() self.settings_detail.refresh_page()
self.settings_detail.wait_for_prerequisite_course_options()
self.assertTrue(is_option_value_selected( self.assertTrue(is_option_value_selected(
browser_query=self.settings_detail.pre_requisite_course_options, browser_query=self.settings_detail.pre_requisite_course_options,
value=pre_requisite_course_id value=pre_requisite_course_id
...@@ -99,6 +101,7 @@ class SettingsMilestonesTest(StudioCourseTest): ...@@ -99,6 +101,7 @@ class SettingsMilestonesTest(StudioCourseTest):
# Refresh the page again to confirm the None selection is properly reflected # Refresh the page again to confirm the None selection is properly reflected
self.settings_detail.refresh_page() self.settings_detail.refresh_page()
self.settings_detail.wait_for_prerequisite_course_options()
self.assertTrue(is_option_value_selected( self.assertTrue(is_option_value_selected(
browser_query=self.settings_detail.pre_requisite_course_options, browser_query=self.settings_detail.pre_requisite_course_options,
value='' value=''
......
...@@ -553,8 +553,9 @@ def render_html_view(request, user_id, course_id): ...@@ -553,8 +553,9 @@ def render_html_view(request, user_id, course_id):
# Get the active certificate configuration for this course # Get the active certificate configuration for this course
# If we do not have an active certificate, we'll need to send the user to the "Invalid" screen # If we do not have an active certificate, we'll need to send the user to the "Invalid" screen
# Passing in the 'preview' parameter, if specified, will return a configuration, if defined
active_configuration = get_active_web_certificate(course, request.GET.get('preview')) active_configuration = get_active_web_certificate(course, request.GET.get('preview'))
if active_configuration is None and request.GET.get('preview') is None: if active_configuration is None:
return render_to_response(invalid_template_path, context) return render_to_response(invalid_template_path, context)
else: else:
context['certificate_data'] = active_configuration context['certificate_data'] = active_configuration
...@@ -568,9 +569,6 @@ def render_html_view(request, user_id, course_id): ...@@ -568,9 +569,6 @@ def render_html_view(request, user_id, course_id):
# Append/Override the existing view context values with any course-specific static values from Advanced Settings # Append/Override the existing view context values with any course-specific static values from Advanced Settings
context.update(course.cert_html_view_overrides) context.update(course.cert_html_view_overrides)
# Override further with any course-specific static values
context.update(course.cert_html_view_overrides)
# FINALLY, generate and send the output the client # FINALLY, generate and send the output the client
return render_to_response("certificates/valid.html", context) return render_to_response("certificates/valid.html", context)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment