Commit eaad4a0c by Clinton Blackburn

Merge pull request #261 from edx/audit-display

Added support for the display and editing of audit modes
parents c5af4521 1ffd2355
......@@ -174,9 +174,7 @@ class AtomicPublicationSerializer(serializers.Serializer): # pylint: disable=ab
# Verify that attributes required to create a Seat are present.
attrs = self._flatten(product['attribute_values'])
if attrs.get('certificate_type') is None:
raise serializers.ValidationError(_(u"Products must have a certificate type."))
elif attrs.get('id_verification_required') is None:
if attrs.get('id_verification_required') is None:
raise serializers.ValidationError(_(u"Products must indicate whether ID verification is required."))
# Verify that a price is present.
......
......@@ -89,10 +89,10 @@ define([
* Mapping of course type to an array of course seat types.
*/
courseTypeSeatMapping: {
honor: ['honor'],
verified: ['honor', 'verified'],
honor: ['audit', 'honor'],
verified: ['audit', 'honor', 'verified'],
professional: ['professional'],
credit: ['honor', 'verified', 'credit']
credit: ['audit', 'honor', 'verified', 'credit']
},
initialize: function () {
......@@ -146,6 +146,7 @@ define([
return (product instanceof CourseSeat) && (product.seatType === seatType);
});
// Do NOT create new audit seats
if (!seat) {
seatClass = CourseUtils.getCourseSeatModel(seatType);
seat = new seatClass();
......@@ -206,6 +207,16 @@ define([
}, this);
},
courseSeatTypes: function(){
var seatTypes = this.seats().map(function(seat){
return seat.getSeatType();
});
// Note (CCB): Audit is intentionally left out of this list, to avoid
// creating new audit seats (which we do not yet support).
return seatTypes.length > 0 ? seatTypes : ['honor', 'verified', 'professional'];
},
/**
* Save the Course using the publication endpoint.
*
......
......@@ -53,8 +53,10 @@ define([
case 'professional':
case 'no-id-professional':
return gettext('Professional');
default:
case 'honor':
return gettext('Honor');
default:
return gettext('Audit');
}
},
......@@ -68,8 +70,11 @@ define([
case 'no-id-professional':
return gettext('Professional Certificate');
default:
case 'honor':
return gettext('Honor Certificate');
default:
return '(' + gettext('No Certificate') + ')';
}
}
});
......
......@@ -15,6 +15,10 @@ define([
'use strict';
return {
seatSortObj: _.invert(_.object(_.pairs([
'audit', 'honor', 'verified', 'no-id-professional', 'professional', 'credit'
]))),
/**
* Returns a mapping of seat types to CourseSeat classes.
*
......@@ -68,6 +72,24 @@ define([
}
return seatType;
},
/**
* Returns an array of CourseSeats, ordered as they should be displayed.
* @param {CourseSeat[]} seats
* @returns {CourseSeat[]}
*/
orderSeatsForDisplay: function (seats) {
return _.sortBy(seats, function (seat) {
return this.seatSortObj[seat.getSeatType()];
}, this);
},
orderSeatTypesForDisplay: function(seatTypes){
return _.sortBy(seatTypes, function (seatType) {
return this.seatSortObj[seatType];
}, this);
}
}
}
......
......@@ -5,7 +5,8 @@ define([
'underscore.string',
'moment',
'text!templates/course_detail.html',
'text!templates/_course_seat.html'
'text!templates/_course_seat.html',
'utils/course_utils'
],
function ($,
Backbone,
......@@ -13,7 +14,8 @@ define([
_s,
moment,
CourseDetailTemplate,
CourseSeatTemplate) {
CourseSeatTemplate,
CourseUtils) {
'use strict';
return Backbone.View.extend({
......@@ -23,24 +25,6 @@ define([
this.listenTo(this.model, 'change', this.render);
},
/**
* Returns an array of CourseSeat models, sorted in the order expected for display.
* @returns {CourseSeat[]}
*/
getSeats: function () {
// Returns an array of seats sorted for display
var seats,
sortObj = _.invert(_.object(_.pairs([
'audit', 'honor', 'verified', 'no-id-professional', 'professional', 'credit'
])));
seats = _.sortBy(this.model.seats(), function (seat) {
return sortObj[seat.getSeatType()];
});
return seats;
},
render: function () {
var html,
verificationDeadline = this.model.get('verification_deadline'),
......@@ -62,9 +46,10 @@ define([
renderSeats: function () {
var html = '',
seats = CourseUtils.orderSeatsForDisplay(this.model.seats()),
$seatHolder = $('.course-seats', this.$el);
_.each(this.getSeats(), function (seat) {
_.each(seats, function (seat) {
html += _.template(CourseSeatTemplate)({seat: seat, moment: moment});
});
......
......@@ -9,11 +9,12 @@ define([
'underscore.string',
'text!templates/course_form.html',
'text!templates/_course_type_radio_field.html',
'views/course_seat_form_fields/audit_course_seat_form_field_view',
'views/course_seat_form_fields/honor_course_seat_form_field_view',
'views/course_seat_form_fields/verified_course_seat_form_field_view',
'views/course_seat_form_fields/professional_course_seat_form_field_view',
'views/alert_view',
'jquery-cookie'
'utils/course_utils'
],
function ($,
Backbone,
......@@ -25,11 +26,12 @@ define([
_s,
CourseFormTemplate,
CourseTypeRadioTemplate,
AuditCourseSeatFormFieldView,
HonorCourseSeatFormFieldView,
VerifiedCourseSeatFormFieldView,
ProfessionalCourseSeatFormFieldView,
AlertView,
cookie) {
CourseUtils) {
'use strict';
// Extend the callbacks to work with Bootstrap.
......@@ -83,19 +85,9 @@ define([
}
},
// Map course types to the available seats
courseTypeSeatMapping: {
honor: ['honor'],
verified: ['honor', 'verified'],
professional: ['professional'],
credit: ['honor', 'verified', 'credit']
},
// TODO Activate credit
courseSeatTypes: ['honor', 'verified', 'professional'],
// Map course seats to view classes
courseSeatViewMappings: {
audit: AuditCourseSeatFormFieldView,
honor: HonorCourseSeatFormFieldView,
verified: VerifiedCourseSeatFormFieldView,
professional: ProfessionalCourseSeatFormFieldView
......@@ -261,6 +253,7 @@ define([
*/
renderCourseSeats: function () {
var $courseSeats,
seatTypes,
$courseSeatsContainer = this.$el.find('.course-seats'),
activeSeats = this.model.validSeatTypes();
......@@ -270,7 +263,9 @@ define([
}
if (_.isEmpty(this.courseSeatViews)) {
_.each(this.courseSeatTypes, function (seatType) {
seatTypes = CourseUtils.orderSeatTypesForDisplay(this.model.courseSeatTypes());
_.each(seatTypes, function (seatType) {
var view,
model = this.model.getOrCreateSeat(seatType),
viewClass = this.courseSeatViewMappings[seatType];
......
define([
'views/course_seat_form_fields/course_seat_form_field_view',
'text!templates/audit_course_seat_form_field.html'
],
function (CourseSeatFormFieldView,
FieldTemplate) {
'use strict';
return CourseSeatFormFieldView.extend({
certificateType: null,
idVerificationRequired: false,
seatType: 'audit',
template: _.template(FieldTemplate)
});
}
);
......@@ -57,5 +57,9 @@
.form-actions {
margin-top: spacing-vertical(large);
}
.price-label {
@extend label;
}
}
}
<div class="col-sm-12">
<div class="seat-type"><%= gettext('Audit') %></div>
</div>
<div class="col-sm-4">
<span class="price-label"><%= gettext('Price (in USD)') %>:</span> <span class="seat-price">$0.00</span>
<input type="hidden" name="price" value="0">
<input type="hidden" name="certificate_type" value="">
<input type="hidden" name="id_verification_required" value="false">
</div>
<div class="col-sm-4 seat-certificate-type">
(<%= gettext('No Certificate') %>)
</div>
<div class="col-sm-4 seat-additional-info"></div>
<div class="col-sm-12">
<div class="seat-type"><%= gettext('Free (Honor)') %></div>
<div class="seat-type"><%= gettext('Honor') %></div>
</div>
<div class="col-sm-4">
<label class="price-label"><%= gettext('Price (in USD)') %>:</label> <span class="seat-price">$0.00</span>
<span class="price-label"><%= gettext('Price (in USD)') %>:</span> <span class="seat-price">$0.00</span>
<input type="hidden" name="price" value="0">
<input type="hidden" name="certificate_type" value="honor">
<input type="hidden" name="id_verification_required" value="false">
......
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