From 88192fd4448d1ee3eb35b57ccf838dca464a61a2 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 19 Apr 2016 16:17:26 -0400 Subject: [PATCH] Revert "Revert "Adding background image for xseries certificates on dashboard side bar panel"" --- .../learner_dashboard/tests/test_programs.py | 61 +++++++++++++++- lms/djangoapps/learner_dashboard/views.py | 5 +- .../images/xseries-certificate-visual.png | Bin 0 -> 14323 bytes .../views/certificate_view.js | 31 +++++++++ .../learner_dashboard/views/sidebar_view.js | 6 ++ .../certificate_view_spec.js | 65 ++++++++++++++++++ .../learner_dashboard/sidebar_view_spec.js | 17 ++++- lms/static/js/spec/main.js | 3 +- lms/static/sass/_build-lms-v1.scss | 1 + lms/static/sass/_xseries_certificates.scss | 17 +++++ lms/static/sass/views/_program-list.scss | 5 ++ .../learner_dashboard/certificate.underscore | 7 ++ lms/templates/learner_dashboard/programs.html | 4 +- .../learner_dashboard/sidebar.underscore | 2 +- 14 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 lms/static/images/xseries-certificate-visual.png create mode 100644 lms/static/js/learner_dashboard/views/certificate_view.js create mode 100644 lms/static/js/spec/learner_dashboard/certificate_view_spec.js create mode 100644 lms/static/sass/_xseries_certificates.scss create mode 100644 lms/templates/learner_dashboard/certificate.underscore diff --git a/lms/djangoapps/learner_dashboard/tests/test_programs.py b/lms/djangoapps/learner_dashboard/tests/test_programs.py index ae42b4a45e..42271d5f8e 100644 --- a/lms/djangoapps/learner_dashboard/tests/test_programs.py +++ b/lms/djangoapps/learner_dashboard/tests/test_programs.py @@ -14,6 +14,8 @@ from edx_oauth2_provider.tests.factories import ClientFactory from opaque_keys.edx import locator from provider.constants import CONFIDENTIAL +from openedx.core.djangoapps.credentials.models import CredentialsApiConfig +from openedx.core.djangoapps.credentials.tests.mixins import CredentialsDataMixin, CredentialsApiConfigMixin from openedx.core.djangoapps.programs.tests.mixins import ( ProgramsApiConfigMixin, ProgramsDataMixin) @@ -29,7 +31,9 @@ from xmodule.modulestore.tests.factories import CourseFactory class TestProgramListing( ModuleStoreTestCase, ProgramsApiConfigMixin, - ProgramsDataMixin): + ProgramsDataMixin, + CredentialsDataMixin, + CredentialsApiConfigMixin): """ Unit tests for getting the list of programs enrolled by a logged in user @@ -41,6 +45,7 @@ class TestProgramListing( Add a student """ super(TestProgramListing, self).setUp() + ClientFactory(name=CredentialsApiConfig.OAUTH2_CLIENT_NAME, client_type=CONFIDENTIAL) ClientFactory(name=ProgramsApiConfig.OAUTH2_CLIENT_NAME, client_type=CONFIDENTIAL) self.student = UserFactory() self.create_programs_config(xseries_ad_enabled=True, program_listing_enabled=True) @@ -139,3 +144,57 @@ class TestProgramListing( self.assertEqual(response.status_code, 302) self.assertIsInstance(response, HttpResponseRedirect) self.assertIn('login', response.url) # pylint: disable=no-member + + def _expected_credetials_data(self): + """ Dry method for getting expected credentials.""" + + return [ + { + "display_name": "Test Program A", + "credential_url": "http://credentials.edx.org/credentials/dummy-uuid-1/" + }, + { + "display_name": "Test Program B", + "credential_url": "http://credentials.edx.org/credentials/dummy-uuid-2/" + } + ] + + @httpretty.activate + def test_get_xseries_certificates_with_data(self): + + self.create_programs_config(program_listing_enabled=True) + self.create_credentials_config(is_learner_issuance_enabled=True) + + self.client.login(username=self.student.username, password=self.PASSWORD) + + # mock programs and credentials apis + self.mock_programs_api() + self.mock_credentials_api(self.student, data=self.CREDENTIALS_API_RESPONSE, reset_url=False) + + response = self.client.get(reverse("program_listing_view")) + self.assertEqual(response.status_code, 200) + + for certificate in self._expected_credetials_data(): + self.assertIn(certificate['display_name'], response.content) + self.assertIn(certificate['credential_url'], response.content) + + self.assertIn('images/xseries-certificate-visual.png', response.content) + + @httpretty.activate + def test_get_xseries_certificates_without_data(self): + + self.create_programs_config(program_listing_enabled=True) + self.create_credentials_config(is_learner_issuance_enabled=True) + + self.client.login(username=self.student.username, password=self.PASSWORD) + + # mock programs and credentials apis + self.mock_programs_api() + self.mock_credentials_api(self.student, data={"results": []}, reset_url=False) + + response = self.client.get(reverse("program_listing_view")) + self.assertEqual(response.status_code, 200) + + for certificate in self._expected_credetials_data(): + self.assertNotIn(certificate['display_name'], response.content) + self.assertNotIn(certificate['credential_url'], response.content) diff --git a/lms/djangoapps/learner_dashboard/views.py b/lms/djangoapps/learner_dashboard/views.py index 503d4bfcc3..427bfa6ed3 100644 --- a/lms/djangoapps/learner_dashboard/views.py +++ b/lms/djangoapps/learner_dashboard/views.py @@ -9,7 +9,7 @@ from django.http import Http404 from edxmako.shortcuts import render_to_response from openedx.core.djangoapps.programs.utils import get_engaged_programs from openedx.core.djangoapps.programs.models import ProgramsApiConfig -from student.views import get_course_enrollments +from student.views import get_course_enrollments, _get_xseries_credentials @login_required @@ -35,5 +35,6 @@ def view_programs(request): 'programs': programs, 'xseries_url': marketing_root if ProgramsApiConfig.current().show_xseries_ad else None, 'nav_hidden': True, - 'show_program_listing': show_program_listing + 'show_program_listing': show_program_listing, + 'credentials': _get_xseries_credentials(request.user) }) diff --git a/lms/static/images/xseries-certificate-visual.png b/lms/static/images/xseries-certificate-visual.png new file mode 100644 index 0000000000000000000000000000000000000000..122a485a5a28eaf3350ab7e1fca23912c9b860c8 GIT binary patch literal 14323 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 0) { + this.$el.html(this.tpl(this.context)); + } + } + }); + } + ); +}).call(this, define || RequireJS.define); diff --git a/lms/static/js/learner_dashboard/views/sidebar_view.js b/lms/static/js/learner_dashboard/views/sidebar_view.js index 3534eb3e02..e2c9502556 100644 --- a/lms/static/js/learner_dashboard/views/sidebar_view.js +++ b/lms/static/js/learner_dashboard/views/sidebar_view.js @@ -6,6 +6,7 @@ 'underscore', 'gettext', 'js/learner_dashboard/views/explore_new_programs_view', + 'js/learner_dashboard/views/certificate_view', 'text!../../../templates/learner_dashboard/sidebar.underscore' ], function( @@ -14,6 +15,7 @@ _, gettext, NewProgramsView, + CertificateView, sidebarTpl ) { return Backbone.View.extend({ @@ -34,6 +36,10 @@ this.newProgramsView = new NewProgramsView({ context: this.context }); + + this.newCertificateView = new CertificateView({ + context: this.context + }); } }); } diff --git a/lms/static/js/spec/learner_dashboard/certificate_view_spec.js b/lms/static/js/spec/learner_dashboard/certificate_view_spec.js new file mode 100644 index 0000000000..92e61daa07 --- /dev/null +++ b/lms/static/js/spec/learner_dashboard/certificate_view_spec.js @@ -0,0 +1,65 @@ +define([ + 'backbone', + 'jquery', + 'js/learner_dashboard/views/certificate_view' + ], function (Backbone, $, CertificateView) { + + 'use strict'; + describe('Certificate View', function () { + var view = null, + data = { + context: { + certificatesData: [ + { + "display_name": "Testing", + "credential_url": "https://credentials.stage.edx.org/credentials/dummy-uuid-1/" + }, + { + "display_name": "Testing2", + "credential_url": "https://credentials.stage.edx.org/credentials/dummy-uuid-2/" + } + ], + xseriesImage: "/images/testing.png" + } + }; + + beforeEach(function() { + setFixtures('
'); + view = new CertificateView(data); + view.render(); + }); + + afterEach(function() { + view.remove(); + }); + + it('should exist', function() { + expect(view).toBeDefined(); + }); + + it('should load the certificates based on passed in certificates list', function() { + var $certificates = view.$el.find('.certificate-box'); + expect($certificates.length).toBe(2); + + $certificates.each(function(index, el){ + expect($(el).html().trim()).toEqual(data.context.certificatesData[index].display_name); + expect($(el).attr('href')).toEqual(data.context.certificatesData[index].credential_url); + }); + expect(view.$el.find('.title').html().trim()).toEqual('XSeries Program Certificates:'); + expect(view.$el.find('img').attr('src')).toEqual('/images/testing.png'); + }); + + it('should display no certificate box if certificates list is empty', function() { + var $certificate; + view.remove(); + setFixtures('
'); + view = new CertificateView({ + context: {certificatesData: []} + }); + view.render(); + $certificate = view.$el.find('.certificate-box'); + expect($certificate.length).toBe(0); + }); + }); + } +); diff --git a/lms/static/js/spec/learner_dashboard/sidebar_view_spec.js b/lms/static/js/spec/learner_dashboard/sidebar_view_spec.js index 295d25c3be..14f57bd91f 100644 --- a/lms/static/js/spec/learner_dashboard/sidebar_view_spec.js +++ b/lms/static/js/spec/learner_dashboard/sidebar_view_spec.js @@ -10,7 +10,14 @@ define([ describe('Sidebar View', function () { var view = null, context = { - xseriesUrl: 'http://www.edx.org/xseries' + xseriesUrl: 'http://www.edx.org/xseries', + certificatesData: [ + { + "display_name": "Testing", + "credential_url": "https://credentials.stage.edx.org/credentials/dummy-uuid-1/" + } + ], + xseriesImage: '/image/test.png' }; beforeEach(function() { @@ -38,17 +45,23 @@ define([ expect($sidebar.find('.program-advertise .ad-link a').attr('href')).toEqual(context.xseriesUrl); }); + it('should load the certificates based on passed in certificates list', function() { + expect(view.$('.certificate-box').length).toBe(1); + }); + it('should not load the xseries advertising if no xseriesUrl passed in', function(){ var $ad; view.remove(); view = new SidebarView({ el: '.sidebar', - context: {} + context: {certificatesData: []} }); view.render(); $ad = view.$el.find('.program-advertise'); expect($ad.length).toBe(0); + expect(view.$('.certificate-box').length).toBe(0); }); + }); } ); diff --git a/lms/static/js/spec/main.js b/lms/static/js/spec/main.js index 0287a265e7..f25edd870b 100644 --- a/lms/static/js/spec/main.js +++ b/lms/static/js/spec/main.js @@ -754,7 +754,8 @@ 'lms/include/js/spec/markdown_editor_spec.js', 'lms/include/js/spec/learner_dashboard/collection_list_view_spec.js', 'lms/include/js/spec/learner_dashboard/sidebar_view_spec.js', - 'lms/include/js/spec/learner_dashboard/program_card_view_spec.js' + 'lms/include/js/spec/learner_dashboard/program_card_view_spec.js', + 'lms/include/js/spec/learner_dashboard/certificate_view_spec.js' ]); }).call(this, requirejs, define); diff --git a/lms/static/sass/_build-lms-v1.scss b/lms/static/sass/_build-lms-v1.scss index ae3dbb281f..bfa3ea5859 100644 --- a/lms/static/sass/_build-lms-v1.scss +++ b/lms/static/sass/_build-lms-v1.scss @@ -59,6 +59,7 @@ @import "views/financial-assistance"; @import 'views/bookmarks'; @import 'course/auto-cert'; +@import 'xseries_certificates'; @import 'views/program-list'; @import 'views/api-access'; diff --git a/lms/static/sass/_xseries_certificates.scss b/lms/static/sass/_xseries_certificates.scss new file mode 100644 index 0000000000..7cc9dab924 --- /dev/null +++ b/lms/static/sass/_xseries_certificates.scss @@ -0,0 +1,17 @@ +@mixin xseries-certificate-container { + border: 1px solid $gray-l3; + box-sizing: border-box; + padding: $baseline; + background: $gray-l6; + margin-top: $baseline; + .title{ + @extend %t-title6; + @extend %t-weight3; + margin-bottom:$baseline; + color: $gray; + } + .certificate-box{ + padding-top: $baseline; + display: block; + } +} diff --git a/lms/static/sass/views/_program-list.scss b/lms/static/sass/views/_program-list.scss index f20dee0a73..f098e435bb 100644 --- a/lms/static/sass/views/_program-list.scss +++ b/lms/static/sass/views/_program-list.scss @@ -19,6 +19,11 @@ $pl-button-color: #0079bc; .sidebar{ @include outer-container; @include span-columns(12); + @include float(right); + margin-bottom: $baseline; + .certificate-container{ + @include xseries-certificate-container(); + } .program-advertise{ padding: $baseline; background-color: $body-bg; diff --git a/lms/templates/learner_dashboard/certificate.underscore b/lms/templates/learner_dashboard/certificate.underscore new file mode 100644 index 0000000000..b1b6a9c3fc --- /dev/null +++ b/lms/templates/learner_dashboard/certificate.underscore @@ -0,0 +1,7 @@ +
+

<%- gettext('XSeries Program Certificates') %>:

+ + <% _.each(certificatesData, function(certificate){ %> + <%- gettext(certificate.display_name) %> + <% }); %> +
diff --git a/lms/templates/learner_dashboard/programs.html b/lms/templates/learner_dashboard/programs.html index d563522aa2..3a7221e95d 100644 --- a/lms/templates/learner_dashboard/programs.html +++ b/lms/templates/learner_dashboard/programs.html @@ -12,7 +12,9 @@ from openedx.core.djangolib.js_utils import ( <%static:require_module module_name="js/learner_dashboard/program_list_factory" class_name="ProgramListFactory"> ProgramListFactory({ programsData: ${programs | n, dump_js_escaped_json}, - xseriesUrl: '${xseries_url | n, js_escaped_string}' + certificatesData: ${credentials | n, dump_js_escaped_json}, + xseriesUrl: '${xseries_url | n, js_escaped_string}', + xseriesImage: '${static.url('images/xseries-certificate-visual.png')}' }); diff --git a/lms/templates/learner_dashboard/sidebar.underscore b/lms/templates/learner_dashboard/sidebar.underscore index 6ddfcc18a5..c93b1b2f32 100644 --- a/lms/templates/learner_dashboard/sidebar.underscore +++ b/lms/templates/learner_dashboard/sidebar.underscore @@ -1,2 +1,2 @@
-
+