Skip to content

Commit

Permalink
Show program certificate on dashboard (#3546)
Browse files Browse the repository at this point in the history
  • Loading branch information
annagav authored Sep 27, 2017
1 parent 293220e commit 619d6bd
Show file tree
Hide file tree
Showing 14 changed files with 125 additions and 7 deletions.
3 changes: 2 additions & 1 deletion dashboard/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def get_info_for_program(mmtrack):
"courses": [],
"pearson_exam_status": mmtrack.get_pearson_exam_status(),
"grade_average": mmtrack.calculate_final_grade_average(),
"certificate": mmtrack.get_program_certificate_url(),
}
if mmtrack.financial_aid_available:
data["financial_aid_user_info"] = FinancialAidDashboardSerializer.serialize(mmtrack.user, mmtrack.program)
Expand Down Expand Up @@ -221,7 +222,7 @@ def get_info_for_course(course, mmtrack):
mmtrack.get_course_proctorate_exam_results(course), many=True
).data,
"has_exam": course.has_exam,
"certificate_url": get_certificate_url(mmtrack, course)
"certificate_url": get_certificate_url(mmtrack, course),
}

def _add_run(run, mmtrack_, status):
Expand Down
6 changes: 6 additions & 0 deletions dashboard/api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1537,6 +1537,7 @@ def test_program(self, mock_info_course):
'financial_aid_available': False,
'get_pearson_exam_status.return_value': ExamProfile.PROFILE_SUCCESS,
'calculate_final_grade_average.return_value': 91,
'get_program_certificate_url.return_value': "",
})
mock_info_course.return_value = {'position_in_program': 1}
res = api.get_info_for_program(self.mmtrack)
Expand All @@ -1550,6 +1551,7 @@ def test_program(self, mock_info_course):
"financial_aid_availability": False,
"pearson_exam_status": ExamProfile.PROFILE_SUCCESS,
"grade_average": 91,
"certificate": "",
}
self.assertEqual(res, expected_data)

Expand All @@ -1561,6 +1563,7 @@ def test_program_no_courses(self, mock_info_course):
'financial_aid_available': False,
'get_pearson_exam_status.return_value': ExamProfile.PROFILE_INVALID,
'calculate_final_grade_average.return_value': 91,
'get_program_certificate_url.return_value': "",
})
res = api.get_info_for_program(self.mmtrack)
assert mock_info_course.called is False
Expand All @@ -1572,6 +1575,7 @@ def test_program_no_courses(self, mock_info_course):
"financial_aid_availability": False,
"pearson_exam_status": ExamProfile.PROFILE_INVALID,
"grade_average": 91,
"certificate": "",
}
self.assertEqual(res, expected_data)

Expand All @@ -1584,6 +1588,7 @@ def test_program_financial_aid(self, mock_fin_aid_serialize, mock_info_course):
'get_pearson_exam_status.return_value': ExamProfile.PROFILE_IN_PROGRESS,
'calculate_final_grade_average.return_value': 91,
'financial_aid_available': True,
'get_program_certificate_url.return_value': "",
})
serialized_fin_aid = {
"id": 123,
Expand All @@ -1608,6 +1613,7 @@ def test_program_financial_aid(self, mock_fin_aid_serialize, mock_info_course):
"financial_aid_user_info": serialized_fin_aid,
"pearson_exam_status": ExamProfile.PROFILE_IN_PROGRESS,
"grade_average": 91,
"certificate": "",
}
self.assertEqual(res, expected_data)

Expand Down
27 changes: 26 additions & 1 deletion dashboard/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from decimal import Decimal

from django.db import transaction
from django.db.models import Q
from django.db.models import Q, Count
from django.urls import reverse

from courses.models import CourseRun
from dashboard.api_edx_cache import CachedEdxUserData
Expand All @@ -14,6 +15,7 @@
from grades.models import (
FinalGrade,
ProctoredExamGrade,
MicromastersProgramCertificate,
)
from exams.models import (
ExamProfile,
Expand Down Expand Up @@ -428,6 +430,29 @@ def get_course_proctorate_exam_results(self, course):
"""
return ProctoredExamGrade.for_user_course(self.user, course)

def program_certificate_qset(self):
"""
Returns the queryset of micromasters program certificate
Returns:
qset: a queryset of grades.models.MicromastersProgramCertificate
"""
return MicromastersProgramCertificate.objects.filter(user=self.user, program=self.program)

def get_program_certificate_url(self):
"""
Returns a string with program certificate url
Returns:
str: a string with url or empty string
"""
certificate = self.program_certificate_qset().annotate(
signatories=Count('program__programpage__program_certificate_signatories')
).filter(signatories__gt=0).first()
if certificate is None:
return ""
return reverse('program-certificate', args=[certificate.hash])


def get_mmtrack(user, program):
"""
Expand Down
23 changes: 22 additions & 1 deletion dashboard/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
patch,
MagicMock,
)
from django.urls import reverse

import pytz
import ddt

from cms.factories import ProgramCertificateSignatoriesFactory
from courses.factories import ProgramFactory, CourseFactory, CourseRunFactory
from dashboard.api_edx_cache import CachedEdxUserData
from dashboard.models import CachedEnrollment, CachedCertificate, CachedCurrentGrade
Expand All @@ -19,7 +21,7 @@
from exams.factories import ExamProfileFactory, ExamAuthorizationFactory, ExamRunFactory
from exams.models import ExamProfile, ExamAuthorization
from grades.factories import FinalGradeFactory
from grades.models import FinalGrade
from grades.models import FinalGrade, MicromastersProgramCertificate
from micromasters.factories import UserFactory
from micromasters.utils import (
load_json_from_file,
Expand Down Expand Up @@ -625,6 +627,25 @@ def test_has_passing_certificate_fa(self):
assert mmtrack.has_passing_certificate(key) is True
assert mmtrack.has_paid(key) is False

def test_get_program_certificate_url(self):
"""
Test get_program_certificate_url
"""
mmtrack = MMTrack(
user=self.user,
program=self.program_financial_aid,
edx_user_data=self.cached_edx_user_data
)
assert mmtrack.get_program_certificate_url() == ""

certificate = MicromastersProgramCertificate.objects.create(
user=self.user, program=self.program_financial_aid
)
assert mmtrack.get_program_certificate_url() == ""

ProgramCertificateSignatoriesFactory.create(program_page__program=certificate.program)
assert mmtrack.get_program_certificate_url() == reverse('program-certificate', args=[certificate.hash])

def test_get_passing_final_grades(self):
"""
Test for get_passing_final_grades_for_course to sort passing grades
Expand Down
Binary file added static/images/diploma_sm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added static/images/mm_watermark2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed static/images/verified-seal-grayscale.png
Binary file not shown.
35 changes: 34 additions & 1 deletion static/js/components/ProgressWidget.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import React from "react"
import { Card, CardTitle } from "react-mdl/lib/Card"
import Button from "react-mdl/lib/Button"

import type { Program } from "../flow/programTypes"
import { programCourseInfo } from "../util/util"
Expand Down Expand Up @@ -65,7 +66,33 @@ export default class ProgressWidget extends React.Component {
program: Program
}

render() {
renderProgramCertificate() {
const { program } = this.props

return (
<Card className="progress-widget" shadow={0}>
<img
className="certificate-thumbnail"
src="/static/images/diploma_sm.png"
alt="Certificate"
/>
<div className="text-course-complete">Congatulations!</div>
<p className="certificate-text">
You completed the MicroMasters Certificate in {program.title}
</p>
<Button
className="dashboard-button"
onClick={() => {
window.open(program.certificate)
}}
>
View Certificate
</Button>
</Card>
)
}

renderProgressIndicator() {
const { program } = this.props
const { totalPassedCourses, totalCourses } = programCourseInfo(program)

Expand All @@ -76,4 +103,10 @@ export default class ProgressWidget extends React.Component {
</Card>
)
}
render() {
const { program } = this.props
return program.certificate
? this.renderProgramCertificate()
: this.renderProgressIndicator()
}
}
18 changes: 18 additions & 0 deletions static/js/components/ProgressWidget_test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react"
import { shallow } from "enzyme"
import { assert } from "chai"
import Button from "react-mdl/lib/Button"

import ProgressWidget from "./ProgressWidget"
import { STATUS_NOT_PASSED, STATUS_PASSED } from "../constants"
Expand Down Expand Up @@ -141,4 +142,21 @@ describe("ProgressWidget", () => {
)
assert.equal(wrapper.find(".circular-progress-widget-txt").text(), "3/5")
})
it("should display program certificate when a certificate link exists", () => {
program["certificate"] = "certificate_url"
const wrapper = shallow(<ProgressWidget program={program} />)

assert.equal(
wrapper
.find(Button)
.children()
.text(),
"View Certificate"
)

assert.equal(
wrapper.find(".text-course-complete").text(),
"Congatulations!"
)
})
})
3 changes: 2 additions & 1 deletion static/js/factories/dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ export const makeProgram = (): Program => {
},
pearson_exam_status:
PEARSON_STATUSES[Math.floor(Math.random() * PEARSON_STATUSES.length)],
grade_average: Math.floor(Math.random() * 100)
grade_average: Math.floor(Math.random() * 100),
certificate: ""
}
}

Expand Down
1 change: 1 addition & 0 deletions static/js/flow/programTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type Program = {
financial_aid_user_info: FinancialAidUserInfo,
pearson_exam_status: string,
grade_average: ?number,
certificate: string,
}

export type ProctoredExamResult = {
Expand Down
2 changes: 1 addition & 1 deletion static/scss/certificate.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
padding: 35px 50px;

&.verified {
background-position: -325px -50px;
background-position: 0 -60px;
background-size: 100% auto;
background-color: #fff;
background-repeat: no-repeat;
Expand Down
12 changes: 12 additions & 0 deletions static/scss/progress-widget.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@
}
}

.certificate-thumbnail {
max-width: 160px;
width: 70%;
margin: 6px auto 20px;
}

p {
padding: 0;
margin: 0 0 10px;
Expand All @@ -58,4 +64,10 @@
font-weight: 400;
}

.certificate-text {
padding-top: 10px;
text-align: center;
color: $font-gray;
}

}
2 changes: 1 addition & 1 deletion ui/templates/background-images.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@
}

.certificate .certificate-body.verified {
background-image: url({% static "images/verified-seal-grayscale.png" %});
background-image: url({% static "images/mm_watermark2.png" %});
}

0 comments on commit 619d6bd

Please sign in to comment.