Commit 1e1b321b by Diana Huang

Merge pull request #4655 from edx/diana/allow-only-verified

Allow verified to be offered without audit
parents ea4e76b0 ec13aabe
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'CourseMode.description'
db.add_column('course_modes_coursemode', 'description',
self.gf('django.db.models.fields.TextField')(null=True, blank=True),
keep_default=False)
# Changing field 'CourseMode.course_id'
db.alter_column('course_modes_coursemode', 'course_id', self.gf('xmodule_django.models.CourseKeyField')(max_length=255))
def backwards(self, orm):
# Deleting field 'CourseMode.description'
db.delete_column('course_modes_coursemode', 'description')
# Changing field 'CourseMode.course_id'
db.alter_column('course_modes_coursemode', 'course_id', self.gf('django.db.models.fields.CharField')(max_length=255))
models = {
'course_modes.coursemode': {
'Meta': {'unique_together': "(('course_id', 'mode_slug', 'currency'),)", 'object_name': 'CourseMode'},
'course_id': ('xmodule_django.models.CourseKeyField', [], {'max_length': '255', 'db_index': 'True'}),
'currency': ('django.db.models.fields.CharField', [], {'default': "'usd'", 'max_length': '8'}),
'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'expiration_datetime': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'min_price': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'mode_display_name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'mode_slug': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'suggested_prices': ('django.db.models.fields.CommaSeparatedIntegerField', [], {'default': "''", 'max_length': '255', 'blank': 'True'})
}
}
complete_apps = ['course_modes']
\ No newline at end of file
...@@ -11,7 +11,17 @@ from django.db.models import Q ...@@ -11,7 +11,17 @@ from django.db.models import Q
from xmodule_django.models import CourseKeyField from xmodule_django.models import CourseKeyField
Mode = namedtuple('Mode', ['slug', 'name', 'min_price', 'suggested_prices', 'currency', 'expiration_datetime']) Mode = namedtuple('Mode',
[
'slug',
'name',
'min_price',
'suggested_prices',
'currency',
'expiration_datetime',
'description'
])
class CourseMode(models.Model): class CourseMode(models.Model):
""" """
...@@ -42,7 +52,11 @@ class CourseMode(models.Model): ...@@ -42,7 +52,11 @@ class CourseMode(models.Model):
expiration_datetime = models.DateTimeField(default=None, null=True, blank=True) expiration_datetime = models.DateTimeField(default=None, null=True, blank=True)
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None) # optional description override
# WARNING: will not be localized
description = models.TextField(null=True, blank=True)
DEFAULT_MODE = Mode('honor', _('Honor Code Certificate'), 0, '', 'usd', None, None)
DEFAULT_MODE_SLUG = 'honor' DEFAULT_MODE_SLUG = 'honor'
class Meta: class Meta:
...@@ -66,7 +80,8 @@ class CourseMode(models.Model): ...@@ -66,7 +80,8 @@ class CourseMode(models.Model):
mode.min_price, mode.min_price,
mode.suggested_prices, mode.suggested_prices,
mode.currency, mode.currency,
mode.expiration_datetime mode.expiration_datetime,
mode.description
) for mode in found_course_modes]) ) for mode in found_course_modes])
if not modes: if not modes:
modes = [cls.DEFAULT_MODE] modes = [cls.DEFAULT_MODE]
......
...@@ -50,7 +50,7 @@ class CourseModeModelTest(TestCase): ...@@ -50,7 +50,7 @@ class CourseModeModelTest(TestCase):
self.create_mode('verified', 'Verified Certificate') self.create_mode('verified', 'Verified Certificate')
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None) mode = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None)
self.assertEqual([mode], modes) self.assertEqual([mode], modes)
modes_dict = CourseMode.modes_for_course_dict(self.course_key) modes_dict = CourseMode.modes_for_course_dict(self.course_key)
...@@ -62,8 +62,8 @@ class CourseModeModelTest(TestCase): ...@@ -62,8 +62,8 @@ class CourseModeModelTest(TestCase):
""" """
Finding the modes when there's multiple modes Finding the modes when there's multiple modes
""" """
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None) mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)
mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None) mode2 = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', None, None)
set_modes = [mode1, mode2] set_modes = [mode1, mode2]
for mode in set_modes: for mode in set_modes:
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices) self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices)
...@@ -82,9 +82,9 @@ class CourseModeModelTest(TestCase): ...@@ -82,9 +82,9 @@ class CourseModeModelTest(TestCase):
self.assertEqual(0, CourseMode.min_course_price_for_currency(self.course_key, 'usd')) self.assertEqual(0, CourseMode.min_course_price_for_currency(self.course_key, 'usd'))
# create some modes # create some modes
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None) mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None, None)
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None) mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None, None)
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None) mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None, None)
set_modes = [mode1, mode2, mode3] set_modes = [mode1, mode2, mode3]
for mode in set_modes: for mode in set_modes:
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency) self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency)
...@@ -99,7 +99,7 @@ class CourseModeModelTest(TestCase): ...@@ -99,7 +99,7 @@ class CourseModeModelTest(TestCase):
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
self.assertEqual([CourseMode.DEFAULT_MODE], modes) self.assertEqual([CourseMode.DEFAULT_MODE], modes)
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None) mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None, None)
self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices) self.create_mode(mode1.slug, mode1.name, mode1.min_price, mode1.suggested_prices)
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
self.assertEqual([mode1], modes) self.assertEqual([mode1], modes)
...@@ -107,7 +107,7 @@ class CourseModeModelTest(TestCase): ...@@ -107,7 +107,7 @@ class CourseModeModelTest(TestCase):
expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1) expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1)
expired_mode.expiration_datetime = expiration_datetime expired_mode.expiration_datetime = expiration_datetime
expired_mode.save() expired_mode.save()
expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_datetime) expired_mode_value = Mode(u'verified', u'Verified Certificate', 0, '', 'usd', expiration_datetime, None)
modes = CourseMode.modes_for_course(self.course_key) modes = CourseMode.modes_for_course(self.course_key)
self.assertEqual([expired_mode_value, mode1], modes) self.assertEqual([expired_mode_value, mode1], modes)
......
...@@ -60,6 +60,7 @@ class ChooseModeView(View): ...@@ -60,6 +60,7 @@ class ChooseModeView(View):
"chosen_price": chosen_price, "chosen_price": chosen_price,
"error": error, "error": error,
"upgrade": upgrade, "upgrade": upgrade,
"can_audit": "audit" in modes,
} }
if "verified" in modes: if "verified" in modes:
context["suggested_prices"] = [ context["suggested_prices"] = [
...@@ -69,6 +70,8 @@ class ChooseModeView(View): ...@@ -69,6 +70,8 @@ class ChooseModeView(View):
] ]
context["currency"] = modes["verified"].currency.upper() context["currency"] = modes["verified"].currency.upper()
context["min_price"] = modes["verified"].min_price context["min_price"] = modes["verified"].min_price
context["verified_name"] = modes["verified"].name
context["verified_description"] = modes["verified"].description
return render_to_response("course_modes/choose.html", context) return render_to_response("course_modes/choose.html", context)
......
...@@ -632,10 +632,16 @@ def change_enrollment(request): ...@@ -632,10 +632,16 @@ def change_enrollment(request):
available_modes = CourseMode.modes_for_course(course_id) available_modes = CourseMode.modes_for_course(course_id)
if len(available_modes) > 1: if len(available_modes) > 1:
return HttpResponse( return HttpResponse(
reverse("course_modes_choose", kwargs={'course_id': course_id.to_deprecated_string()}) reverse("course_modes_choose", kwargs={'course_id': unicode(course_id)})
) )
current_mode = available_modes[0] current_mode = available_modes[0]
# only automatically enroll people if the only mode is 'honor'
if current_mode.slug != 'honor':
return HttpResponse(
reverse("course_modes_choose", kwargs={'course_id': unicode(course_id)})
)
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug) CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
return HttpResponse() return HttpResponse()
......
...@@ -66,17 +66,27 @@ $(document).ready(function() { ...@@ -66,17 +66,27 @@ $(document).ready(function() {
<div class="register-choice register-choice-certificate"> <div class="register-choice register-choice-certificate">
<div class="wrapper-copy"> <div class="wrapper-copy">
<span class="deco-ribbon"></span> <span class="deco-ribbon"></span>
<h4 class="title">${_("Certificate of Achievement (ID Verified)")}</h4> %if verified_name == "Verified Certificate":
<h4 class="title">${_("Certificate of Achievement (ID Verified)")}</h4>
%if upgrade:
<div class="copy">
<p>${_("Upgrade and work toward a verified Certificate of Achievement.")}</p>
</div>
%else: %else:
<div class="copy"> <h4 class="title">${verified_name}</h4>
<p>${_("Sign up and work toward a verified Certificate of Achievement.")}</p>
</div>
%endif %endif
%if verified_name == "Verified Certificate":
%if upgrade:
<div class="copy">
<p>${_("Upgrade and work toward a verified Certificate of Achievement.")}</p>
</div>
%else:
<div class="copy">
<p>${_("Sign up and work toward a verified Certificate of Achievement.")}</p>
</div>
%endif
%else:
<div class="copy">
<p>${verified_description}</p>
</div>
%endif
</div> </div>
<div class="field field-certificate-contribution"> <div class="field field-certificate-contribution">
......
...@@ -74,7 +74,8 @@ class VerifyView(View): ...@@ -74,7 +74,8 @@ class VerifyView(View):
# bookkeeping-wise just to start over. # bookkeeping-wise just to start over.
progress_state = "start" progress_state = "start"
verify_mode = CourseMode.mode_for_course(course_id, "verified") modes_dict = CourseMode.modes_for_course_dict(course_id)
verify_mode = modes_dict.get('verified', None)
# if the course doesn't have a verified mode, we want to kick them # if the course doesn't have a verified mode, we want to kick them
# from the flow # from the flow
if not verify_mode: if not verify_mode:
...@@ -102,6 +103,7 @@ class VerifyView(View): ...@@ -102,6 +103,7 @@ class VerifyView(View):
"chosen_price": chosen_price, "chosen_price": chosen_price,
"min_price": verify_mode.min_price, "min_price": verify_mode.min_price,
"upgrade": upgrade, "upgrade": upgrade,
"can_audit": "audit" in modes_dict,
} }
return render_to_response('verify_student/photo_verification.html', context) return render_to_response('verify_student/photo_verification.html', context)
...@@ -121,7 +123,9 @@ class VerifiedView(View): ...@@ -121,7 +123,9 @@ class VerifiedView(View):
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id) course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True): if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
verify_mode = CourseMode.mode_for_course(course_id, "verified")
modes_dict = CourseMode.modes_for_course_dict(course_id)
verify_mode = modes_dict.get('verified', None)
if verify_mode is None: if verify_mode is None:
return redirect(reverse('dashboard')) return redirect(reverse('dashboard'))
...@@ -146,6 +150,7 @@ class VerifiedView(View): ...@@ -146,6 +150,7 @@ class VerifiedView(View):
"chosen_price": chosen_price, "chosen_price": chosen_price,
"create_order_url": reverse("verify_student_create_order"), "create_order_url": reverse("verify_student_create_order"),
"upgrade": upgrade, "upgrade": upgrade,
"can_audit": "audit" in modes_dict,
} }
return render_to_response('verify_student/verified.html', context) return render_to_response('verify_student/verified.html', context)
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
</div> </div>
</li> </li>
%if can_audit:
<li class="help-item help-item-coldfeet"> <li class="help-item help-item-coldfeet">
%if upgrade: %if upgrade:
<h3 class="title">${_("Change your mind?")}</h3> <h3 class="title">${_("Change your mind?")}</h3>
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
</div> </div>
%endif %endif
</li> </li>
%endif
<li class="help-item help-item-technical"> <li class="help-item help-item-technical">
<h3 class="title">${_("Technical Requirements")}</h3> <h3 class="title">${_("Technical Requirements")}</h3>
......
...@@ -156,11 +156,13 @@ ...@@ -156,11 +156,13 @@
<nav class="nav-wizard ${"is-not-ready" if is_not_active else "is-ready"}"> <nav class="nav-wizard ${"is-not-ready" if is_not_active else "is-ready"}">
%if can_audit:
%if upgrade: %if upgrade:
<span class="help help-inline">${_("Missing something? You can always continue to audit this course instead.")}</span> <span class="help help-inline">${_("Missing something? You can always continue to audit this course instead.")}</span>
%else: %else:
<span class="help help-inline">${_("Missing something? You can always {a_start}audit this course instead{a_end}").format(a_start='<a href="{}">'.format(course_modes_choose_url), a_end="</a>")}</span> <span class="help help-inline">${_("Missing something? You can always {a_start}audit this course instead{a_end}").format(a_start='<a href="{}">'.format(course_modes_choose_url), a_end="</a>")}</span>
%endif %endif
%endif
<ol class="wizard-steps"> <ol class="wizard-steps">
<li class="wizard-step"> <li class="wizard-step">
......
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