Add course grades to programs dashboard.
This commit is contained in:
@@ -38,6 +38,9 @@
|
||||
this.enrollModel.urlRoot = this.urlModel.get('commerce_api_url');
|
||||
}
|
||||
this.context = options.context || {};
|
||||
this.grade = this.context.courseData.grades[this.model.get('course_run_key')];
|
||||
this.grade = this.grade * 100;
|
||||
this.collectionCourseStatus = this.context.collectionCourseStatus || '';
|
||||
this.render();
|
||||
this.listenTo(this.model, 'change', this.render);
|
||||
},
|
||||
@@ -59,6 +62,8 @@
|
||||
this.enrollView = new CourseEnrollView({
|
||||
$parentEl: this.$('.course-actions'),
|
||||
model: this.model,
|
||||
grade: this.grade,
|
||||
collectionCourseStatus: this.collectionCourseStatus,
|
||||
urlModel: this.urlModel,
|
||||
enrollModel: this.enrollModel
|
||||
});
|
||||
|
||||
@@ -29,13 +29,18 @@
|
||||
this.$parentEl = options.$parentEl;
|
||||
this.enrollModel = options.enrollModel;
|
||||
this.urlModel = options.urlModel;
|
||||
this.grade = options.grade;
|
||||
this.collectionCourseStatus = options.collectionCourseStatus;
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var filledTemplate;
|
||||
var filledTemplate,
|
||||
context = this.model.toJSON();
|
||||
if (this.$parentEl && this.enrollModel) {
|
||||
filledTemplate = this.tpl(this.model.toJSON());
|
||||
context.grade = this.grade;
|
||||
context.collectionCourseStatus = this.collectionCourseStatus;
|
||||
filledTemplate = this.tpl(context);
|
||||
HtmlUtils.setHtml(this.$el, filledTemplate);
|
||||
HtmlUtils.setHtml(this.$parentEl, HtmlUtils.HTML(this.$el));
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
el: '.js-course-list-remaining',
|
||||
childView: CourseCardView,
|
||||
collection: this.remainingCourseCollection,
|
||||
context: this.options
|
||||
context: $.extend(this.options, {collectionCourseStatus: 'remaining'})
|
||||
}).render();
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
el: '.js-course-list-completed',
|
||||
childView: CourseCardView,
|
||||
collection: this.completedCourseCollection,
|
||||
context: this.options
|
||||
context: $.extend(this.options, {collectionCourseStatus: 'completed'})
|
||||
}).render();
|
||||
}
|
||||
|
||||
@@ -110,7 +110,9 @@
|
||||
el: '.js-course-list-in-progress',
|
||||
childView: CourseCardView,
|
||||
collection: this.inProgressCourseCollection,
|
||||
context: $.extend(this.options, {enrolled: gettext('Enrolled')})
|
||||
context: $.extend(this.options,
|
||||
{enrolled: gettext('Enrolled'), collectionCourseStatus: 'in_progress'}
|
||||
)
|
||||
}).render();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,27 @@ define([
|
||||
startDate = 'Feb 28, 2017',
|
||||
endDate = 'May 30, 2017',
|
||||
|
||||
setupView = function(data, isEnrolled) {
|
||||
var programData = $.extend({}, data);
|
||||
setupView = function(data, isEnrolled, collectionCourseStatus) {
|
||||
var programData = $.extend({}, data),
|
||||
context = {
|
||||
courseData: {
|
||||
grades: {
|
||||
'course-v1:WageningenX+FFESx+1T2017': 0.8
|
||||
}
|
||||
},
|
||||
collectionCourseStatus: collectionCourseStatus
|
||||
};
|
||||
|
||||
if (typeof collectionCourseStatus === 'undefined') {
|
||||
context.collectionCourseStatus = 'completed';
|
||||
}
|
||||
|
||||
programData.course_runs[0].is_enrolled = isEnrolled;
|
||||
setFixtures('<div class="program-course-card"></div>');
|
||||
courseCardModel = new CourseCardModel(programData);
|
||||
view = new CourseCardView({
|
||||
model: courseCardModel
|
||||
model: courseCardModel,
|
||||
context: context
|
||||
});
|
||||
},
|
||||
|
||||
@@ -84,6 +97,18 @@ define([
|
||||
validateCourseInfoDisplay();
|
||||
});
|
||||
|
||||
it('should render final grade if course is completed', function() {
|
||||
view.remove();
|
||||
setupView(course, true);
|
||||
expect(view.$('.grade-display').text()).toEqual('80%');
|
||||
});
|
||||
|
||||
it('should not render final grade if course has not been completed', function() {
|
||||
view.remove();
|
||||
setupView(course, true, 'in_progress');
|
||||
expect(view.$('.final-grade').length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should render the course card based on the data not enrolled', function() {
|
||||
validateCourseInfoDisplay();
|
||||
});
|
||||
|
||||
@@ -462,7 +462,10 @@ define([
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
grades: {
|
||||
'course-v1:Testx+DOGx002+1T2016': 0.9
|
||||
}
|
||||
},
|
||||
urls: {
|
||||
program_listing_url: '/dashboard/programs/',
|
||||
|
||||
@@ -520,6 +520,19 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.final-grade {
|
||||
.grade-header {
|
||||
color: palette(grayscale, base);
|
||||
font-weight: bold;
|
||||
}
|
||||
.grade-display {
|
||||
padding-right: 15px;
|
||||
font-size: 1.5em;
|
||||
color: palette(primary, accent);
|
||||
}
|
||||
}
|
||||
|
||||
.upgrade-message {
|
||||
flex-wrap: wrap;
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<% if (is_enrolled && (typeof expired === 'undefined' || expired === false)) { %>
|
||||
<% if (is_enrolled && collectionCourseStatus === 'completed') { %>
|
||||
<div class="final-grade">
|
||||
<div class="grade-header"><%- gettext('Final Grade') %><span class="sr"><%- StringUtils.interpolate(gettext('for {courseName}'), {courseName: title}) %></span></div>
|
||||
<div class="grade-display"><%- grade %>%</div>
|
||||
</div>
|
||||
<% } else if (is_enrolled && (typeof expired === 'undefined' || expired === false)) { %>
|
||||
<a href="<%- course_url %>" class="view-course-button btn-brand btn cta-primary">
|
||||
<% if (is_course_ended) { %>
|
||||
<%- gettext('View Archived Course') %>
|
||||
|
||||
@@ -12,3 +12,4 @@ class ProgressFactory(factory.Factory):
|
||||
completed = 0
|
||||
in_progress = 0
|
||||
not_started = 0
|
||||
grades = dict()
|
||||
|
||||
@@ -18,6 +18,7 @@ from course_modes.models import CourseMode
|
||||
from lms.djangoapps.certificates.api import MODES
|
||||
from lms.djangoapps.commerce.tests.test_utils import update_commerce_config
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.grades.tests.utils import mock_passing_grade
|
||||
from openedx.core.djangoapps.catalog.tests.factories import (
|
||||
generate_course_run_key,
|
||||
ProgramFactory,
|
||||
@@ -138,7 +139,7 @@ class TestProgramProgressMeter(TestCase):
|
||||
self.assertEqual(meter.engaged_programs, [program])
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program['uuid'], in_progress=1)
|
||||
ProgressFactory(uuid=program['uuid'], in_progress=1, grades={course_run_key: 0.0})
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -169,7 +170,8 @@ class TestProgramProgressMeter(TestCase):
|
||||
uuid=program['uuid'],
|
||||
completed=[],
|
||||
in_progress=[program['courses'][0]],
|
||||
not_started=[]
|
||||
not_started=[],
|
||||
grades={course_run_key: 0.0},
|
||||
)
|
||||
]
|
||||
|
||||
@@ -205,7 +207,8 @@ class TestProgramProgressMeter(TestCase):
|
||||
uuid=program['uuid'],
|
||||
completed=[],
|
||||
in_progress=[program['courses'][0]],
|
||||
not_started=[]
|
||||
not_started=[],
|
||||
grades={course_run_key: 0.0},
|
||||
)
|
||||
]
|
||||
|
||||
@@ -246,7 +249,8 @@ class TestProgramProgressMeter(TestCase):
|
||||
uuid=program['uuid'],
|
||||
completed=0,
|
||||
in_progress=1 if offset in [None, 1] else 0,
|
||||
not_started=1 if offset in [-1] else 0
|
||||
not_started=1 if offset in [-1] else 0,
|
||||
grades={course_run_key: 0.0},
|
||||
)
|
||||
]
|
||||
|
||||
@@ -285,9 +289,14 @@ class TestProgramProgressMeter(TestCase):
|
||||
self._attach_detail_url(data)
|
||||
programs = data[:2]
|
||||
self.assertEqual(meter.engaged_programs, programs)
|
||||
|
||||
grades = {
|
||||
newer_course_run_key: 0.0,
|
||||
older_course_run_key: 0.0,
|
||||
}
|
||||
self._assert_progress(
|
||||
meter,
|
||||
*(ProgressFactory(uuid=program['uuid'], in_progress=1) for program in programs)
|
||||
*(ProgressFactory(uuid=program['uuid'], in_progress=1, grades=grades) for program in programs)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -330,9 +339,15 @@ class TestProgramProgressMeter(TestCase):
|
||||
self._attach_detail_url(data)
|
||||
programs = data[:3]
|
||||
self.assertEqual(meter.engaged_programs, programs)
|
||||
|
||||
grades = {
|
||||
solo_course_run_key: 0.0,
|
||||
shared_course_run_key: 0.0,
|
||||
}
|
||||
|
||||
self._assert_progress(
|
||||
meter,
|
||||
*(ProgressFactory(uuid=program['uuid'], in_progress=1) for program in programs)
|
||||
*(ProgressFactory(uuid=program['uuid'], in_progress=1, grades=grades) for program in programs)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -366,7 +381,7 @@ class TestProgramProgressMeter(TestCase):
|
||||
program, program_uuid = data[0], data[0]['uuid']
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, in_progress=1, not_started=1)
|
||||
ProgressFactory(uuid=program_uuid, in_progress=1, not_started=1, grades={first_course_run_key: 0.0})
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -375,7 +390,14 @@ class TestProgramProgressMeter(TestCase):
|
||||
meter = ProgramProgressMeter(self.site, self.user)
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, in_progress=2)
|
||||
ProgressFactory(
|
||||
uuid=program_uuid,
|
||||
in_progress=2,
|
||||
grades={
|
||||
first_course_run_key: 0.0,
|
||||
second_course_run_key: 0.0,
|
||||
},
|
||||
)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -386,7 +408,15 @@ class TestProgramProgressMeter(TestCase):
|
||||
meter = ProgramProgressMeter(self.site, self.user)
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, completed=1, in_progress=1)
|
||||
ProgressFactory(
|
||||
uuid=program_uuid,
|
||||
completed=1,
|
||||
in_progress=1,
|
||||
grades={
|
||||
first_course_run_key: 0.0,
|
||||
second_course_run_key: 0.0,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -398,7 +428,15 @@ class TestProgramProgressMeter(TestCase):
|
||||
meter = ProgramProgressMeter(self.site, self.user)
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, completed=1, in_progress=1)
|
||||
ProgressFactory(
|
||||
uuid=program_uuid,
|
||||
completed=1,
|
||||
in_progress=1,
|
||||
grades={
|
||||
first_course_run_key: 0.0,
|
||||
second_course_run_key: 0.0,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [])
|
||||
|
||||
@@ -410,7 +448,14 @@ class TestProgramProgressMeter(TestCase):
|
||||
meter = ProgramProgressMeter(self.site, self.user)
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, completed=2)
|
||||
ProgressFactory(
|
||||
uuid=program_uuid,
|
||||
completed=2,
|
||||
grades={
|
||||
first_course_run_key: 0.0,
|
||||
second_course_run_key: 0.0,
|
||||
}
|
||||
)
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [program_uuid])
|
||||
|
||||
@@ -443,7 +488,7 @@ class TestProgramProgressMeter(TestCase):
|
||||
program, program_uuid = data[0], data[0]['uuid']
|
||||
self._assert_progress(
|
||||
meter,
|
||||
ProgressFactory(uuid=program_uuid, completed=1)
|
||||
ProgressFactory(uuid=program_uuid, completed=1, grades={course_run_key: 0.0})
|
||||
)
|
||||
self.assertEqual(meter.completed_programs, [program_uuid])
|
||||
|
||||
@@ -549,6 +594,38 @@ class TestProgramProgressMeter(TestCase):
|
||||
mock_completed_course_runs.return_value = [{'course_run_id': course_run_key, 'type': 'verified'}]
|
||||
self.assertEqual(meter._is_course_complete(course), True)
|
||||
|
||||
def test_course_grade_results(self, mock_get_programs):
|
||||
grade_percent = .8
|
||||
with mock_passing_grade(percent=grade_percent):
|
||||
course_run_key = generate_course_run_key()
|
||||
data = [
|
||||
ProgramFactory(
|
||||
courses=[
|
||||
CourseFactory(course_runs=[
|
||||
CourseRunFactory(key=course_run_key),
|
||||
]),
|
||||
]
|
||||
)
|
||||
]
|
||||
mock_get_programs.return_value = data
|
||||
|
||||
self._create_enrollments(course_run_key)
|
||||
|
||||
meter = ProgramProgressMeter(self.site, self.user)
|
||||
|
||||
program = data[0]
|
||||
expected = [
|
||||
ProgressFactory(
|
||||
uuid=program['uuid'],
|
||||
completed=[],
|
||||
in_progress=[program['courses'][0]],
|
||||
not_started=[],
|
||||
grades={course_run_key: grade_percent},
|
||||
)
|
||||
]
|
||||
|
||||
self.assertEqual(meter.progress(count_only=False), expected)
|
||||
|
||||
|
||||
def _create_course(self, course_price, course_run_count=1):
|
||||
"""
|
||||
|
||||
@@ -22,6 +22,8 @@ from course_modes.models import CourseMode
|
||||
from lms.djangoapps.certificates import api as certificate_api
|
||||
from lms.djangoapps.commerce.utils import EcommerceService
|
||||
from lms.djangoapps.courseware.access import has_access
|
||||
from lms.djangoapps.courseware.courses import get_course_with_access
|
||||
from lms.djangoapps.grades.course_grade_factory import CourseGradeFactory
|
||||
from openedx.core.djangoapps.catalog.utils import get_programs
|
||||
from openedx.core.djangoapps.commerce.utils import ecommerce_api_client
|
||||
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
||||
@@ -89,6 +91,8 @@ class ProgramProgressMeter(object):
|
||||
# We can't use dict.keys() for this because the course run ids need to be ordered
|
||||
self.course_run_ids.append(enrollment_id)
|
||||
|
||||
self.course_grade_factory = CourseGradeFactory()
|
||||
|
||||
if uuid:
|
||||
self.programs = [get_programs(self.site, uuid=uuid)]
|
||||
else:
|
||||
@@ -216,11 +220,17 @@ class ProgramProgressMeter(object):
|
||||
else:
|
||||
not_started.append(course)
|
||||
|
||||
grades = {}
|
||||
for run in self.course_run_ids:
|
||||
grade = self.course_grade_factory.read(self.user, course_key=CourseKey.from_string(run))
|
||||
grades[run] = grade.percent
|
||||
|
||||
progress.append({
|
||||
'uuid': program_copy['uuid'],
|
||||
'completed': len(completed) if count_only else completed,
|
||||
'in_progress': len(in_progress) if count_only else in_progress,
|
||||
'not_started': len(not_started) if count_only else not_started,
|
||||
'grades': grades,
|
||||
})
|
||||
|
||||
return progress
|
||||
@@ -325,7 +335,7 @@ class ProgramProgressMeter(object):
|
||||
|
||||
course_data = {
|
||||
'course_run_id': unicode(certificate['course_key']),
|
||||
'type': certificate_type
|
||||
'type': certificate_type,
|
||||
}
|
||||
|
||||
if certificate_api.is_passing_status(certificate['status']):
|
||||
|
||||
Reference in New Issue
Block a user