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
This commit is contained in:
Zia Fazal
2015-06-24 14:40:52 +05:00
parent 614bcafb7c
commit bcbd1464d4
17 changed files with 142 additions and 17 deletions

View File

@@ -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):
"""

View File

@@ -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

View File

@@ -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)

View File

@@ -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.");

View File

@@ -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),

View File

@@ -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
};
});

View File

@@ -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)

View File

@@ -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,

View File

@@ -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"),

View File

@@ -201,4 +201,5 @@ class AdvancedSettingsPage(CoursePage):
'social_sharing_url',
'teams_configuration',
'video_bumper',
'cert_html_view_enabled',
]

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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',

View File

@@ -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

View File

@@ -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)

View File

@@ -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,