Commit df89a1d2 by Diana Huang Committed by GitHub

Merge pull request #16314 from edx/diana/programs-dashboard-grades

ECOM-7387 - Add grade display to the programs dashboard
parents 3dee61ec b0877270
......@@ -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;
......
<% 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']):
......
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