Merge pull request #4655 from edx/diana/allow-only-verified
Allow verified to be offered without audit
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
# -*- 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']
|
||||
@@ -11,7 +11,17 @@ from django.db.models import Q
|
||||
|
||||
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):
|
||||
"""
|
||||
@@ -42,7 +52,11 @@ class CourseMode(models.Model):
|
||||
|
||||
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'
|
||||
|
||||
class Meta:
|
||||
@@ -66,7 +80,8 @@ class CourseMode(models.Model):
|
||||
mode.min_price,
|
||||
mode.suggested_prices,
|
||||
mode.currency,
|
||||
mode.expiration_datetime
|
||||
mode.expiration_datetime,
|
||||
mode.description
|
||||
) for mode in found_course_modes])
|
||||
if not modes:
|
||||
modes = [cls.DEFAULT_MODE]
|
||||
|
||||
@@ -50,7 +50,7 @@ class CourseModeModelTest(TestCase):
|
||||
|
||||
self.create_mode('verified', 'Verified Certificate')
|
||||
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)
|
||||
|
||||
modes_dict = CourseMode.modes_for_course_dict(self.course_key)
|
||||
@@ -62,8 +62,8 @@ class CourseModeModelTest(TestCase):
|
||||
"""
|
||||
Finding the modes when there's multiple modes
|
||||
"""
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 0, '', 'usd', None)
|
||||
mode2 = Mode(u'verified', u'Verified 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, None)
|
||||
set_modes = [mode1, mode2]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices)
|
||||
@@ -82,9 +82,9 @@ class CourseModeModelTest(TestCase):
|
||||
self.assertEqual(0, CourseMode.min_course_price_for_currency(self.course_key, 'usd'))
|
||||
|
||||
# create some modes
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None)
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None)
|
||||
mode1 = Mode(u'honor', u'Honor Code Certificate', 10, '', 'usd', None, None)
|
||||
mode2 = Mode(u'verified', u'Verified Certificate', 20, '', 'usd', None, None)
|
||||
mode3 = Mode(u'honor', u'Honor Code Certificate', 80, '', 'cny', None, None)
|
||||
set_modes = [mode1, mode2, mode3]
|
||||
for mode in set_modes:
|
||||
self.create_mode(mode.slug, mode.name, mode.min_price, mode.suggested_prices, mode.currency)
|
||||
@@ -99,7 +99,7 @@ class CourseModeModelTest(TestCase):
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
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)
|
||||
modes = CourseMode.modes_for_course(self.course_key)
|
||||
self.assertEqual([mode1], modes)
|
||||
@@ -107,7 +107,7 @@ class CourseModeModelTest(TestCase):
|
||||
expiration_datetime = datetime.now(pytz.UTC) + timedelta(days=1)
|
||||
expired_mode.expiration_datetime = expiration_datetime
|
||||
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)
|
||||
self.assertEqual([expired_mode_value, mode1], modes)
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ class ChooseModeView(View):
|
||||
"chosen_price": chosen_price,
|
||||
"error": error,
|
||||
"upgrade": upgrade,
|
||||
"can_audit": "audit" in modes,
|
||||
}
|
||||
if "verified" in modes:
|
||||
context["suggested_prices"] = [
|
||||
@@ -69,6 +70,8 @@ class ChooseModeView(View):
|
||||
]
|
||||
context["currency"] = modes["verified"].currency.upper()
|
||||
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)
|
||||
|
||||
|
||||
@@ -632,10 +632,16 @@ def change_enrollment(request):
|
||||
available_modes = CourseMode.modes_for_course(course_id)
|
||||
if len(available_modes) > 1:
|
||||
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]
|
||||
# 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)
|
||||
|
||||
return HttpResponse()
|
||||
|
||||
@@ -66,17 +66,27 @@ $(document).ready(function() {
|
||||
<div class="register-choice register-choice-certificate">
|
||||
<div class="wrapper-copy">
|
||||
<span class="deco-ribbon"></span>
|
||||
<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>
|
||||
%if verified_name == "Verified Certificate":
|
||||
<h4 class="title">${_("Certificate of Achievement (ID Verified)")}</h4>
|
||||
%else:
|
||||
<div class="copy">
|
||||
<p>${_("Sign up and work toward a verified Certificate of Achievement.")}</p>
|
||||
</div>
|
||||
<h4 class="title">${verified_name}</h4>
|
||||
%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 class="field field-certificate-contribution">
|
||||
|
||||
@@ -74,7 +74,8 @@ class VerifyView(View):
|
||||
# bookkeeping-wise just to start over.
|
||||
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
|
||||
# from the flow
|
||||
if not verify_mode:
|
||||
@@ -102,6 +103,7 @@ class VerifyView(View):
|
||||
"chosen_price": chosen_price,
|
||||
"min_price": verify_mode.min_price,
|
||||
"upgrade": upgrade,
|
||||
"can_audit": "audit" in modes_dict,
|
||||
}
|
||||
|
||||
return render_to_response('verify_student/photo_verification.html', context)
|
||||
@@ -121,7 +123,9 @@ class VerifiedView(View):
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
|
||||
if CourseEnrollment.enrollment_mode_for_user(request.user, course_id) == ('verified', True):
|
||||
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:
|
||||
return redirect(reverse('dashboard'))
|
||||
@@ -146,6 +150,7 @@ class VerifiedView(View):
|
||||
"chosen_price": chosen_price,
|
||||
"create_order_url": reverse("verify_student_create_order"),
|
||||
"upgrade": upgrade,
|
||||
"can_audit": "audit" in modes_dict,
|
||||
}
|
||||
return render_to_response('verify_student/verified.html', context)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
</div>
|
||||
</li>
|
||||
|
||||
%if can_audit:
|
||||
<li class="help-item help-item-coldfeet">
|
||||
%if upgrade:
|
||||
<h3 class="title">${_("Change your mind?")}</h3>
|
||||
@@ -23,6 +24,7 @@
|
||||
</div>
|
||||
%endif
|
||||
</li>
|
||||
%endif
|
||||
|
||||
<li class="help-item help-item-technical">
|
||||
<h3 class="title">${_("Technical Requirements")}</h3>
|
||||
|
||||
@@ -156,11 +156,13 @@
|
||||
|
||||
<nav class="nav-wizard ${"is-not-ready" if is_not_active else "is-ready"}">
|
||||
|
||||
%if can_audit:
|
||||
%if upgrade:
|
||||
<span class="help help-inline">${_("Missing something? You can always continue to audit this course instead.")}</span>
|
||||
%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>
|
||||
%endif
|
||||
%endif
|
||||
|
||||
<ol class="wizard-steps">
|
||||
<li class="wizard-step">
|
||||
|
||||
Reference in New Issue
Block a user