From 015aa98a386ca210e36c8aacd500ff01959fa8d8 Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Wed, 1 Jul 2020 23:24:50 +0500 Subject: [PATCH 1/9] PROD-1661 --- .../views/video/transcripts/file_uploader.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cms/static/js/views/video/transcripts/file_uploader.js b/cms/static/js/views/video/transcripts/file_uploader.js index 2acd158c1c..8edab306a5 100644 --- a/cms/static/js/views/video/transcripts/file_uploader.js +++ b/cms/static/js/views/video/transcripts/file_uploader.js @@ -1,9 +1,11 @@ define( [ 'jquery', 'backbone', 'underscore', - 'js/views/video/transcripts/utils' + 'js/views/video/transcripts/utils', + 'edx-ui-toolkit/js/utils/html-utils' ], -function($, Backbone, _, TranscriptUtils) { +function($, Backbone, _, TranscriptUtils, HtmlUtils) { + 'use strict'; var FileUploader = Backbone.View.extend({ invisibleClass: 'is-invisible', @@ -37,9 +39,8 @@ function($, Backbone, _, TranscriptUtils) { return; } - this.template = _.template(tpl); - - tplContainer.html(this.template({ + this.template = HtmlUtils.template(tpl); + HtmlUtils.setHtml(tplContainer, this.template({ ext: this.validFileExtensions, component_locator: this.options.component_locator })); @@ -126,11 +127,12 @@ function($, Backbone, _, TranscriptUtils) { * */ checkExtValidity: function(file) { + var fileExtension; if (!file.name) { return void(0); } - var fileExtension = file.name + fileExtension = file.name .split('.') .pop() .toLowerCase(); @@ -153,7 +155,7 @@ function($, Backbone, _, TranscriptUtils) { this.$progress .width(percentVal) - .html(percentVal) + .text(percentVal) .removeClass(this.invisibleClass); }, @@ -177,7 +179,7 @@ function($, Backbone, _, TranscriptUtils) { this.$progress .width(percentVal) - .html(percentVal); + .text(percentVal); }, /** From 3cbfab378aa8061e9b2974eaa97406ef73a095f6 Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Wed, 1 Jul 2020 23:44:47 +0500 Subject: [PATCH 2/9] PROD-1663 --- lms/templates/split_test_author_view.html | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lms/templates/split_test_author_view.html b/lms/templates/split_test_author_view.html index ede487e199..534777d0b1 100644 --- a/lms/templates/split_test_author_view.html +++ b/lms/templates/split_test_author_view.html @@ -1,4 +1,9 @@ -<%! from django.utils.translation import ugettext as _ %> +<%page expression_filter="h"/> + +<%! + from django.utils.translation import ugettext as _ + from openedx.core.djangolib.markup import HTML, Text +%> <% split_test = context.get('split_test') @@ -11,8 +16,8 @@ show_link = group_configuration_url is not None

- ${_("This content experiment uses group configuration '{group_configuration_name}'.").format( - group_configuration_name="{}".format(group_configuration_url, user_partition.name) if show_link else user_partition.name + ${Text(_("This content experiment uses group configuration '{group_configuration_name}'.")).format( + group_configuration_name=Text(HTML("{}")).format(group_configuration_url, user_partition.name) if show_link else user_partition.name )}

@@ -23,13 +28,13 @@ show_link = group_configuration_url is not None % if is_root:

${_("Active Groups")}

- ${active_groups_preview} + ${HTML(active_groups_preview)}
% if inactive_groups_preview:

${_("Inactive Groups")}

- ${inactive_groups_preview} + ${HTML(inactive_groups_preview)}
% endif % endif From 188aae9402164b64446cbd93dfdcf832dbe178bb Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Thu, 2 Jul 2020 00:05:40 +0500 Subject: [PATCH 3/9] PROD-1665 --- cms/templates/manage_users_lib.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cms/templates/manage_users_lib.html b/cms/templates/manage_users_lib.html index 4d9e4e1aa2..0800be9eb5 100644 --- a/cms/templates/manage_users_lib.html +++ b/cms/templates/manage_users_lib.html @@ -1,3 +1,5 @@ +<%page expression_filter="h"/> + <%inherit file="base.html" /> <%! from django.utils.translation import ugettext as _ @@ -110,7 +112,7 @@ from openedx.core.djangolib.js_utils import ( <%block name="requirejs"> require(["js/factories/manage_users_lib"], function(ManageLibraryUsersFactory) { ManageLibraryUsersFactory( - "${context_library.display_name_with_default | h}", + "${context_library.display_name_with_default | n, js_escaped_string}", ${users | n, dump_js_escaped_json}, "${reverse('course_team_handler', kwargs={'course_key_string': library_key, 'email': '@@EMAIL@@'}) | n, js_escaped_string}", ${request.user.id | n, dump_js_escaped_json}, From f1d99e1d61d8ba44aa153a279d30bf1706a75c34 Mon Sep 17 00:00:00 2001 From: Ali-D-Akbar Date: Thu, 2 Jul 2020 23:43:44 +0500 Subject: [PATCH 4/9] PROD-1795 --- cms/templates/edit-tabs.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cms/templates/edit-tabs.html b/cms/templates/edit-tabs.html index 7ee868aaa5..c9e30c3223 100644 --- a/cms/templates/edit-tabs.html +++ b/cms/templates/edit-tabs.html @@ -21,7 +21,7 @@ <%block name="page_bundle"> <%static:webpack entry="js/factories/edit_tabs"> - EditTabsFactory("${context_course.location | n, js_escaped_string}", "${reverse('tabs_handler', kwargs={'course_key_string': context_course.id})}"); + EditTabsFactory("${context_course.location | n, js_escaped_string}", "${reverse('tabs_handler', kwargs={'course_key_string': context_course.id}) | n, js_escaped_string}"); From ffde1c4bc281088ec1c2e0879c391727046aba6d Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Mon, 6 Jul 2020 16:59:38 +0500 Subject: [PATCH 5/9] PROD-1731 --- lms/static/js/verify_student/views/reverify_view.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lms/static/js/verify_student/views/reverify_view.js b/lms/static/js/verify_student/views/reverify_view.js index 43257138b3..b61ca2f1b5 100644 --- a/lms/static/js/verify_student/views/reverify_view.js +++ b/lms/static/js/verify_student/views/reverify_view.js @@ -83,7 +83,10 @@ // Get or create the step container $stepEl = $('#current-step-container'); if (!$stepEl.length) { - $stepEl = $('
').appendTo(this.el); + $stepEl = edx.HtmlUtils.append( + $(this.el), + edx.HtmlUtils.HTML('
').toString() + ); } // Render the step subview From e7338cd180f45af6070177e2a0d4a84188e290e6 Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Mon, 6 Jul 2020 17:13:11 +0500 Subject: [PATCH 6/9] PROD-1732 --- lms/static/js/verify_student/views/pay_and_verify_view.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lms/static/js/verify_student/views/pay_and_verify_view.js b/lms/static/js/verify_student/views/pay_and_verify_view.js index 452b0cb731..4dd4d4d16f 100644 --- a/lms/static/js/verify_student/views/pay_and_verify_view.js +++ b/lms/static/js/verify_student/views/pay_and_verify_view.js @@ -126,7 +126,10 @@ var edx = edx || {}; // Get or create the step container $stepEl = $('#current-step-container'); if (!$stepEl.length) { - $stepEl = $('
').appendTo(this.el); + $stepEl = edx.HtmlUtils.append( + $(this.el), + edx.HtmlUtils.HTML('
').toString() + ); } // Render the subview From 2db23423149b688f59268480beee53aeb49f7344 Mon Sep 17 00:00:00 2001 From: SaadYousaf Date: Mon, 6 Jul 2020 18:02:10 +0500 Subject: [PATCH 7/9] PROD-1729 --- lms/static/js/views/image_field.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lms/static/js/views/image_field.js b/lms/static/js/views/image_field.js index d568759617..3a4b427c15 100644 --- a/lms/static/js/views/image_field.js +++ b/lms/static/js/views/image_field.js @@ -1,15 +1,16 @@ (function(define) { 'use strict'; define([ - 'gettext', 'jquery', 'underscore', 'backbone', 'js/views/fields', + 'gettext', 'jquery', 'underscore', 'backbone', + 'edx-ui-toolkit/js/utils/html-utils', 'js/views/fields', 'text!templates/fields/field_image.underscore', 'backbone-super', 'jquery.fileupload' - ], function(gettext, $, _, Backbone, FieldViews, field_image_template) { + ], function(gettext, $, _, Backbone, HtmlUtils, FieldViews, FieldImageTemplate) { var ImageFieldView = FieldViews.FieldView.extend({ fieldType: 'image', - fieldTemplate: field_image_template, + fieldTemplate: FieldImageTemplate, uploadButtonSelector: '.upload-button-input', titleAdd: gettext('Upload an image'), @@ -44,7 +45,7 @@ }, render: function() { - this.$el.html(this.template({ + var attributes = { id: this.options.valueAttribute, inputName: (this.options.inputName || 'file'), imageUrl: _.result(this, 'imageUrl'), @@ -54,7 +55,8 @@ removeButtonIcon: _.result(this, 'iconRemove'), removeButtonTitle: _.result(this, 'removeButtonTitle'), screenReaderTitle: _.result(this, 'screenReaderTitle') - })); + }; + this.$el.html(HtmlUtils.HTML(this.template(attributes)).toString()); this.delegateEvents(); this.updateButtonsVisibility(); this.watchForPageUnload(); @@ -184,14 +186,14 @@ showUploadInProgressMessage: function() { this.$('.u-field-upload-button').addClass('in-progress'); - this.$('.upload-button-icon').html(this.iconProgress); - this.$('.upload-button-title').html(this.titleUploading); + HtmlUtils.setHtml(this.$('.upload-button-icon'), HtmlUtils.HTML(this.iconProgress)); + HtmlUtils.setHtml(this.$('.upload-button-title'), HtmlUtils.HTML(this.titleUploading)); }, showRemovalInProgressMessage: function() { this.$('.u-field-remove-button').css('opacity', 1); - this.$('.remove-button-icon').html(this.iconProgress); - this.$('.remove-button-title').html(this.titleRemoving); + HtmlUtils.setHtml(this.$('.remove-button-icon'), HtmlUtils.HTML(this.iconProgress)); + HtmlUtils.setHtml(this.$('.remove-button-title'), HtmlUtils.HTML(this.titleRemoving)); }, setCurrentStatus: function(status) { From a89553f1c3d838aa7a3915b3626d8307fe197991 Mon Sep 17 00:00:00 2001 From: Ali-D-Akbar Date: Mon, 6 Jul 2020 20:00:46 +0500 Subject: [PATCH 8/9] PROD-1727 --- lms/static/js/views/notification.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lms/static/js/views/notification.js b/lms/static/js/views/notification.js index a5cc328f17..1187e8478b 100644 --- a/lms/static/js/views/notification.js +++ b/lms/static/js/views/notification.js @@ -9,7 +9,7 @@ }, render: function() { - this.$el.html(this.template({ + this.$el.html(this.template({ // xss-lint: disable=javascript-jquery-html type: this.model.get('type'), title: this.model.get('title'), message: this.model.get('message'), From fb9ba90efedb4d0ab5d0ae6cc556cc419d85e3e5 Mon Sep 17 00:00:00 2001 From: uzairr Date: Wed, 12 Feb 2020 16:45:58 -0500 Subject: [PATCH 9/9] PROD-1236: Do not expose user id with certificate URL. --- .../contentstore/tests/test_utils.py | 10 +- cms/djangoapps/contentstore/utils.py | 5 +- .../contentstore/views/certificates.py | 1 - .../views/tests/test_certificates.py | 6 +- .../badges/events/course_complete.py | 7 +- .../events/tests/test_course_complete.py | 20 +- lms/djangoapps/certificates/api.py | 23 +- lms/djangoapps/certificates/tests/test_api.py | 15 +- .../certificates/tests/test_support_views.py | 7 +- .../certificates/tests/test_views.py | 9 +- .../certificates/tests/test_webview_views.py | 199 +++++++++--------- lms/djangoapps/certificates/urls.py | 10 +- lms/djangoapps/certificates/views/webview.py | 50 +++-- lms/djangoapps/mobile_api/users/tests.py | 5 +- .../certificates/url_unsupported.html | 18 ++ 15 files changed, 213 insertions(+), 172 deletions(-) create mode 100644 lms/templates/certificates/url_unsupported.html diff --git a/cms/djangoapps/contentstore/tests/test_utils.py b/cms/djangoapps/contentstore/tests/test_utils.py index f326cbfa80..2b424c7e04 100644 --- a/cms/djangoapps/contentstore/tests/test_utils.py +++ b/cms/djangoapps/contentstore/tests/test_utils.py @@ -51,9 +51,8 @@ class LMSLinksTestCase(TestCase): mode = 'professional' self.assertEqual( - utils.get_lms_link_for_certificate_web_view(dummy_user, course_key, mode), - "//localhost:8000/certificates/user/{user_id}/course/{course_key}?preview={mode}".format( - user_id=dummy_user, + utils.get_lms_link_for_certificate_web_view(course_key, mode), + "//localhost:8000/certificates/course/{course_key}?preview={mode}".format( course_key=course_key, mode=mode ) @@ -61,9 +60,8 @@ class LMSLinksTestCase(TestCase): with with_site_configuration_context(configuration={"course_org_filter": "mitX", "LMS_BASE": "dummyhost:8000"}): self.assertEqual( - utils.get_lms_link_for_certificate_web_view(dummy_user, course_key, mode), - "//dummyhost:8000/certificates/user/{user_id}/course/{course_key}?preview={mode}".format( - user_id=dummy_user, + utils.get_lms_link_for_certificate_web_view(course_key, mode), + "//dummyhost:8000/certificates/course/{course_key}?preview={mode}".format( course_key=course_key, mode=mode ) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index 331a67a493..e0d33fd63a 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -139,7 +139,7 @@ def get_lms_link_for_item(location, preview=False): ) -def get_lms_link_for_certificate_web_view(user_id, course_key, mode): +def get_lms_link_for_certificate_web_view(course_key, mode): """ Returns the url to the certificate web view. """ @@ -151,9 +151,8 @@ def get_lms_link_for_certificate_web_view(user_id, course_key, mode): if lms_base is None: return None - return u"//{certificate_web_base}/certificates/user/{user_id}/course/{course_id}?preview={mode}".format( + return u"//{certificate_web_base}/certificates/course/{course_id}?preview={mode}".format( certificate_web_base=lms_base, - user_id=user_id, course_id=six.text_type(course_key), mode=mode ) diff --git a/cms/djangoapps/contentstore/views/certificates.py b/cms/djangoapps/contentstore/views/certificates.py index 3fab55c56d..7ca8381e98 100644 --- a/cms/djangoapps/contentstore/views/certificates.py +++ b/cms/djangoapps/contentstore/views/certificates.py @@ -411,7 +411,6 @@ def certificates_list_handler(request, course_key_string): if has_certificate_modes: certificate_web_view_url = get_lms_link_for_certificate_web_view( - user_id=request.user.id, course_key=course_key, mode=course_modes[0] # CourseMode.modes_for_course returns default mode if doesn't find anyone. ) diff --git a/cms/djangoapps/contentstore/views/tests/test_certificates.py b/cms/djangoapps/contentstore/views/tests/test_certificates.py index 64ae391245..cf60e7817c 100644 --- a/cms/djangoapps/contentstore/views/tests/test_certificates.py +++ b/cms/djangoapps/contentstore/views/tests/test_certificates.py @@ -263,7 +263,6 @@ class CertificatesListHandlerTestCase( @override_settings(LMS_BASE=None) def test_no_lms_base_for_certificate_web_view_link(self): test_link = get_lms_link_for_certificate_web_view( - user_id=self.user.id, course_key=self.course.id, mode='honor' ) @@ -271,10 +270,9 @@ class CertificatesListHandlerTestCase( @override_settings(LMS_BASE="lms_base_url") def test_lms_link_for_certificate_web_view(self): - test_url = "//lms_base_url/certificates/user/" \ - + str(self.user.id) + "/course/" + six.text_type(self.course.id) + '?preview=honor' + test_url = "//lms_base_url/certificates/" \ + "course/" + six.text_type(self.course.id) + '?preview=honor' link = get_lms_link_for_certificate_web_view( - user_id=self.user.id, course_key=self.course.id, mode='honor' ) diff --git a/lms/djangoapps/badges/events/course_complete.py b/lms/djangoapps/badges/events/course_complete.py index dd420b8d25..14f54424a8 100644 --- a/lms/djangoapps/badges/events/course_complete.py +++ b/lms/djangoapps/badges/events/course_complete.py @@ -7,6 +7,7 @@ import hashlib import logging import six + from django.urls import reverse from django.utils.text import slugify from django.utils.translation import ugettext_lazy as _ @@ -15,6 +16,7 @@ from badges.models import BadgeAssertion, BadgeClass, CourseCompleteImageConfigu from badges.utils import requires_badges_enabled, site_prefix from xmodule.modulestore.django import modulestore + LOGGER = logging.getLogger(__name__) @@ -63,8 +65,11 @@ def evidence_url(user_id, course_key): event. """ course_id = six.text_type(course_key) + # avoid circular import problems + from lms.djangoapps.certificates.models import GeneratedCertificate + cert = GeneratedCertificate.eligible_certificates.get(user__id=int(user_id), course_id=course_id) return site_prefix() + reverse( - 'certificates:html_view', kwargs={'user_id': user_id, 'course_id': course_id}) + '?evidence_visit=1' + 'certificates:render_cert_by_uuid', kwargs={'certificate_uuid': cert.verify_uuid}) + '?evidence_visit=1' def criteria(course_key): diff --git a/lms/djangoapps/badges/events/tests/test_course_complete.py b/lms/djangoapps/badges/events/tests/test_course_complete.py index 2755aa2940..ad4514094f 100644 --- a/lms/djangoapps/badges/events/tests/test_course_complete.py +++ b/lms/djangoapps/badges/events/tests/test_course_complete.py @@ -1,11 +1,11 @@ """ Tests for the course completion helper functions. """ - - from datetime import datetime +from uuid import uuid4 from badges.events import course_complete +from lms.djangoapps.certificates.models import GeneratedCertificate from student.tests.factories import UserFactory from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase from xmodule.modulestore.tests.factories import CourseFactory @@ -64,9 +64,19 @@ class CourseCompleteTestCase(ModuleStoreTestCase): Make sure the evidence URL points to the right place. """ user = UserFactory.create() + cert = GeneratedCertificate.eligible_certificates.create( + user=user, + course_id=self.course_key, + download_uuid=uuid4(), + grade="0.95", + key='the_key', + distinction=True, + status='downloadable', + mode='honor', + name=user.profile.name, + verify_uuid=uuid4().hex + ) self.assertEqual( - 'https://edx.org/certificates/user/{user_id}/course/{course_key}?evidence_visit=1'.format( - user_id=user.id, course_key=self.course_key - ), + 'https://edx.org/certificates/{}?evidence_visit=1'.format(cert.verify_uuid), course_complete.evidence_url(user.id, self.course_key) ) diff --git a/lms/djangoapps/certificates/api.py b/lms/djangoapps/certificates/api.py index d0176aa0fc..56fd44bf89 100644 --- a/lms/djangoapps/certificates/api.py +++ b/lms/djangoapps/certificates/api.py @@ -312,7 +312,9 @@ def certificate_downloadable_status(student, course_key): if current_status['status'] == CertificateStatuses.downloadable and may_view_certificate: response_data['is_downloadable'] = True - response_data['download_url'] = current_status['download_url'] or get_certificate_url(student.id, course_key) + response_data['download_url'] = current_status['download_url'] or get_certificate_url( + student.id, course_key, current_status['uuid'] + ) response_data['is_pdf_certificate'] = bool(current_status['download_url']) response_data['uuid'] = current_status['uuid'] @@ -472,13 +474,13 @@ def _course_from_key(course_key): return CourseOverview.get_from_id(_safe_course_key(course_key)) -def _certificate_html_url(user_id, course_id, uuid): - if uuid: - return reverse('certificates:render_cert_by_uuid', kwargs={'certificate_uuid': uuid}) - elif user_id and course_id: - kwargs = {"user_id": str(user_id), "course_id": six.text_type(course_id)} - return reverse('certificates:html_view', kwargs=kwargs) - return '' +def _certificate_html_url(uuid): + """ + Returns uuid based certificate URL. + """ + return reverse( + 'certificates:render_cert_by_uuid', kwargs={'certificate_uuid': uuid} + ) if uuid else '' def _certificate_download_url(user_id, course_id, user_certificate=None): @@ -515,7 +517,7 @@ def get_certificate_url(user_id=None, course_id=None, uuid=None, user_certificat return url if has_html_certificates_enabled(course): - url = _certificate_html_url(user_id, course_id, uuid) + url = _certificate_html_url(uuid) else: url = _certificate_download_url(user_id, course_id, user_certificate=user_certificate) return url @@ -631,10 +633,11 @@ def emit_certificate_event(event_name, user, course_id, course=None, event_data= 'org_id': course.org, 'course_id': six.text_type(course_id) } + data = { 'user_id': user.id, 'course_id': six.text_type(course_id), - 'certificate_url': get_certificate_url(user.id, course_id) + 'certificate_url': get_certificate_url(user.id, course_id, uuid=event_data['certificate_id']) } event_data = event_data or {} event_data.update(data) diff --git a/lms/djangoapps/certificates/tests/test_api.py b/lms/djangoapps/certificates/tests/test_api.py index 783677874c..ff7eb85645 100644 --- a/lms/djangoapps/certificates/tests/test_api.py +++ b/lms/djangoapps/certificates/tests/test_api.py @@ -199,10 +199,7 @@ class CertificateDownloadableStatusTests(WebCertificateTestMixin, ModuleStoreTes 'is_downloadable': True, 'is_generating': False, 'is_unverified': False, - 'download_url': '/certificates/user/{user_id}/course/{course_id}'.format( - user_id=self.student.id, - course_id=self.course.id, - ), + 'download_url': '/certificates/{uuid}'.format(uuid=cert_status['uuid']), 'is_pdf_certificate': False, 'uuid': cert_status['uuid'] } @@ -496,16 +493,14 @@ class CertificateGetTests(SharedModuleStoreTestCase): self.assertEqual(expected_url, cert_url) expected_url = reverse( - 'certificates:html_view', - kwargs={ - "user_id": str(self.student.id), - "course_id": six.text_type(self.web_cert_course.id), - } + 'certificates:render_cert_by_uuid', + kwargs=dict(certificate_uuid=self.uuid) ) cert_url = certs_api.get_certificate_url( user_id=self.student.id, - course_id=self.web_cert_course.id + course_id=self.web_cert_course.id, + uuid=self.uuid ) self.assertEqual(expected_url, cert_url) diff --git a/lms/djangoapps/certificates/tests/test_support_views.py b/lms/djangoapps/certificates/tests/test_support_views.py index cf57059d28..a47df6a8ee 100644 --- a/lms/djangoapps/certificates/tests/test_support_views.py +++ b/lms/djangoapps/certificates/tests/test_support_views.py @@ -4,9 +4,11 @@ Tests for certificate app views used by the support team. import json +from uuid import uuid4 import ddt import six + from django.conf import settings from django.test.utils import override_settings from django.urls import reverse @@ -85,6 +87,7 @@ class CertificateSupportTestCase(ModuleStoreTestCase): status=self.CERT_STATUS, mode=self.CERT_MODE, download_url=self.CERT_DOWNLOAD_URL, + verify_uuid=uuid4().hex ) # Login as support staff @@ -226,8 +229,8 @@ class CertificateSearchTests(CertificateSupportTestCase): self.assertEqual( retrieved_cert["download_url"], reverse( - 'certificates:html_view', - kwargs={"user_id": self.student.id, "course_id": self.course.id} + 'certificates:render_cert_by_uuid', + kwargs={"certificate_uuid": self.cert.verify_uuid} ) ) self.assertTrue(retrieved_cert["regenerate"]) diff --git a/lms/djangoapps/certificates/tests/test_views.py b/lms/djangoapps/certificates/tests/test_views.py index 6e01f8e1f7..a823d1c5d7 100644 --- a/lms/djangoapps/certificates/tests/test_views.py +++ b/lms/djangoapps/certificates/tests/test_views.py @@ -229,13 +229,14 @@ class CertificatesViewsSiteTests(ModuleStoreTestCase): self.cert = GeneratedCertificate.eligible_certificates.create( user=self.user, course_id=self.course_id, - download_uuid=uuid4(), + download_uuid=uuid4().hex, grade="0.95", key='the_key', distinction=True, status='downloadable', mode='honor', name=self.user.profile.name, + verify_uuid=uuid4().hex ) self._setup_configuration() @@ -284,7 +285,8 @@ class CertificatesViewsSiteTests(ModuleStoreTestCase): def test_html_view_for_site(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) @@ -302,7 +304,8 @@ class CertificatesViewsSiteTests(ModuleStoreTestCase): def test_html_view_site_configuration_missing(self): test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) self._add_course_certificates(count=1, signatory_count=2) response = self.client.get(test_url) diff --git a/lms/djangoapps/certificates/tests/test_webview_views.py b/lms/djangoapps/certificates/tests/test_webview_views.py index e92af03b6a..6857a3b03e 100644 --- a/lms/djangoapps/certificates/tests/test_webview_views.py +++ b/lms/djangoapps/certificates/tests/test_webview_views.py @@ -102,7 +102,7 @@ class CommonCertificatesTestCase(ModuleStoreTestCase): self.cert = GeneratedCertificateFactory.create( user=self.user, course_id=self.course_id, - download_uuid=uuid4(), + download_uuid=uuid4().hex, download_url="http://www.example.com/certificates/download", grade="0.95", key='the_key', @@ -409,7 +409,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=1, is_active=True) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) self.assertContains( @@ -489,7 +490,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url, HTTP_HOST='test.localhost') @@ -527,7 +529,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) self.assertContains(response, str(self.cert.verify_uuid)) @@ -553,7 +556,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) # Validate certificate @@ -564,9 +568,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self.cert.status = CertificateStatuses.generating self.cert.save() response = self.client.get(test_url) - self.assertContains(response, "Invalid Certificate") - self.assertContains(response, "Cannot Find Certificate") - self.assertContains(response, "We cannot find a certificate with this URL or ID number.") + self.assertEqual(response.status_code, 404) @ddt.data( (CertificateStatuses.downloadable, True), @@ -588,27 +590,26 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) - if eligible_for_certificate: self.assertContains(response, str(self.cert.verify_uuid)) else: - self.assertContains(response, "Invalid Certificate") - self.assertContains(response, "Cannot Find Certificate") - self.assertContains(response, "We cannot find a certificate with this URL or ID number.") - self.assertNotContains(response, str(self.cert.verify_uuid)) + self.assertEqual(response.status_code, 404) @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) - def test_html_view_for_invalid_certificate(self): + def test_html_view_returns_404_for_invalid_certificate(self): """ - Tests that Certificate HTML Web View returns "Cannot Find Certificate" if certificate has been invalidated. + Tests that Certificate HTML Web View successfully retrieves certificate only + if the certificate is not invalidated otherwise returns 404 """ self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) # Validate certificate @@ -618,32 +619,7 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) # invalidate certificate and verify that "Cannot Find Certificate" is returned self.cert.invalidate() response = self.client.get(test_url) - self.assertContains(response, "Invalid Certificate") - self.assertContains(response, "Cannot Find Certificate") - self.assertContains(response, "We cannot find a certificate with this URL or ID number.") - - @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) - def test_html_lang_attribute_is_dynamic_for_invalid_certificate_html_view(self): - """ - Tests that Certificate HTML Web View's lang attribute is based on user language. - """ - self._add_course_certificates(count=1, signatory_count=2) - test_url = get_certificate_url( - user_id=self.user.id, - course_id=six.text_type(self.course.id) - ) - - self.cert.invalidate() - - user_language = 'fr' - self.client.cookies[settings.LANGUAGE_COOKIE] = user_language - response = self.client.get(test_url) - self.assertContains(response, '') - - user_language = 'ar' - self.client.cookies[settings.LANGUAGE_COOKIE] = user_language - response = self.client.get(test_url) - self.assertContains(response, '') + self.assertEqual(response.status_code, 404) @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) def test_html_lang_attribute_is_dynamic_for_certificate_html_view(self): @@ -653,7 +629,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) user_language = 'fr' @@ -688,7 +665,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) self.assertContains(response, "Invalid Certificate") @@ -700,7 +678,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) @@ -729,7 +708,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self.store.update_item(self.course, self.user.id) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) @@ -747,7 +727,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=2) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) self.course.display_coursenumber = "overridden_number" @@ -776,7 +757,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) # make sure response html has only one organization logo container for edX @@ -787,7 +769,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) self._add_course_certificates(count=1, signatory_count=0) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) self.assertNotContains(response, 'Signatory_Name 0') @@ -815,7 +798,8 @@ class CertificatesViewsTests(CommonCertificatesTestCase, CacheIsolationTestCase) test_url = get_certificate_url( user_id=self.user.id, - course_id=six.text_type(self.course.id) + course_id=six.text_type(self.course.id), + uuid=self.cert.verify_uuid ) response = self.client.get(test_url) self.assertNotContains(response, '