Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
"""
Expand All @@ -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=unicode(course_key),
mode=mode
)
Expand Down
1 change: 0 additions & 1 deletion cms/djangoapps/contentstore/views/certificates.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,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.
)
Expand Down
4 changes: 2 additions & 2 deletions cms/static/js/views/uploads.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ define(['jquery', 'underscore', 'gettext', 'js/views/modals/base_modal', 'edx-ui
renderContents: function() {
var isValid = this.model.isValid(),
selectedFile = this.model.get('selectedFile'),
oldInput = this.$('input[type=file]').get(0);
oldInput = this.$('input[type=file]');
BaseModal.prototype.renderContents.call(this);
// Ideally, we'd like to tell the browser to pre-populate the
// <input type="file"> with the selectedFile if we have one -- but
Expand All @@ -44,7 +44,7 @@ define(['jquery', 'underscore', 'gettext', 'js/views/modals/base_modal', 'edx-ui
// a blank input to prompt the user to upload a different (valid) file.
if (selectedFile && isValid) {
$(oldInput).removeClass('error');
this.$('input[type=file]').replaceWith(HtmlUtils.ensureHtml(oldInput).toString());
this.$('input[type=file]').replaceWith(HtmlUtils.HTML(oldInput).toString());
this.$('.action-upload').removeClass('disabled');
} else {
this.$('.action-upload').addClass('disabled');
Expand Down
4 changes: 2 additions & 2 deletions cms/templates/js/group-configuration-details.underscore
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@

<% if(showGroups) { %>
<% allocation = Math.floor(100 / groups.length) %>
<ol class="collection-items groups groups-<%= index %>">
<ol class="collection-items groups groups-<%- index %>">
<% groups.each(function(group, groupIndex) { %>
<li class="item group group-<%= groupIndex %>">
<li class="item group group-<%- groupIndex %>">
<span class="name group-name"><%- group.get('name') %></span>
<span class="meta group-allocation"><%- allocation %>%</span>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<%- gettext('You have done a dry run of force publishing the course. Nothing has changed. Had you run it, the following course versions would have been change.') %>
</div>
<div class="main-output">
<%= StringUtils.interpolate(
<%- StringUtils.interpolate(
gettext('The published branch version, {published}, was reset to the draft branch version, {draft}.'),
{
published: current_versions['published-branch'],
Expand Down
6 changes: 3 additions & 3 deletions cms/templates/js/mock/mock-xmodule-editor.underscore
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

<script id="metadata-string-entry" type="text/template">
<div class="wrapper-comp-setting">
\t<label class="label setting-label" for="<%= uniqueId %>"><%= model.get('display_name') %></label>
\t<input class="input setting-input" type="text" id="<%= uniqueId %>" value='<%= model.get("value") %>'/>
\t<label class="label setting-label" for="<%- uniqueId %>"><%- model.get('display_name') %></label>
\t<input class="input setting-input" type="text" id="<%- uniqueId %>" value='<%- model.get("value") %>'/>
\t<button class="action setting-clear inactive" type="button" name="setting-clear" value="Clear" data-tooltip="Clear">
<span class="icon fa fa-undo" aria-hidden="true"></span><span class="sr">"Clear Value"</span>
</button>
</div>
<span class="tip setting-help"><%= model.get('help') %></span>
<span class="tip setting-help"><%- model.get('help') %></span>

</script>

Expand Down
6 changes: 3 additions & 3 deletions cms/templates/js/publish-editor.underscore
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<% _.each(xblockInfo.get('child_info').children, function(subsection) { %>
<% if (subsection.isPublishable()) { %>
<li class="outline-item outline-subsection">
<h4 class="subsection-title item-title"><%= subsection.get('display_name') %></h4>
<h4 class="subsection-title item-title"><%- subsection.get('display_name') %></h4>
<div class="subsection-content">
<ol class="list-units">
<% _.each(subsection.get('child_info').children, function(unit) { %>
<% if (unit.isPublishable()) { %>
<li class="outline-item outline-unit">
<span class="unit-title item-title"><%= unit.get('display_name') %></span>
<span class="unit-title item-title"><%- unit.get('display_name') %></span>
</li>
<% } %>
<% }); %>
Expand All @@ -27,7 +27,7 @@
<% _.each(xblockInfo.get('child_info').children, function(unit) { %>
<% if (unit.isPublishable()) { %>
<li class="outline-item outline-unit">
<span class="unit-title item-title"><%= unit.get('display_name') %></span>
<span class="unit-title item-title"><%- unit.get('display_name') %></span>
</li>
<% } %>
<% }); %>
Expand Down
24 changes: 12 additions & 12 deletions cms/templates/js/unit-outline.underscore
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
<% if (parentInfo) { %>
<li class="outline-item outline-<%= xblockType %> <%= visibilityClass %> <%= xblockInfo.get('id') === currentUnitId ? 'is-current' : '' %>"
data-parent="<%= parentInfo.get('id') %>" data-locator="<%= xblockInfo.get('id') %>">
<div class="<%= xblockType %>-header">
<h3 class="<%= xblockType %>-header-details">
<span class="<%= xblockType %>-title item-title">
<a href="<%= xblockInfo.get('studio_url') %>"><%- xblockInfo.get('display_name') %></a>
<li class="outline-item outline-<%- xblockType %> <%- visibilityClass %> <%- xblockInfo.get('id') === currentUnitId ? 'is-current' : '' %>"
data-parent="<%- parentInfo.get('id') %>" data-locator="<%- xblockInfo.get('id') %>">
<div class="<%- xblockType %>-header">
<h3 class="<%- xblockType %>-header-details">
<span class="<%- xblockType %>-title item-title">
<a href="<%- xblockInfo.get('studio_url') %>"><%- xblockInfo.get('display_name') %></a>
</span>
</h3>
</div>
<% } %>

<div class="<%= xblockType %>-content outline-content">
<ol class="<%= typeListClass %>">
<div class="<%- xblockType %>-content outline-content">
<ol class="<%- typeListClass %>">
</ol>
<% if (childType) { %>
<div class="add-<%= childType %> add-item">
<a href="#" class="button button-new" data-category="<%= childCategory %>"
data-parent="<%= xblockInfo.get('id') %>" data-default-name="<%= defaultNewChildName %>">
<span class="icon fa fa-plus" aria-hidden="true"></span><%= addChildLabel %>
<div class="add-<%- childType %> add-item">
<a href="#" class="button button-new" data-category="<%- childCategory %>"
data-parent="<%- xblockInfo.get('id') %>" data-default-name="<%- defaultNewChildName %>">
<span class="icon fa fa-plus" aria-hidden="true"></span><%- addChildLabel %>
</a>
</div>
<% } %>
Expand Down
4 changes: 2 additions & 2 deletions cms/templates/js/video/transcripts/file-upload.underscore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<form class="file-chooser" action="/transcripts/upload"
method="post" enctype="multipart/form-data">
<input type="file" class="file-input" name="transcript-file"
accept="<%= _.map(ext, function(val){ return '.' + val; }).join(', ') %>">
<input type="hidden" name="locator" value="<%= component_locator %>">
accept="<%- _.map(ext, function(val){ return '.' + val; }).join(', ') %>">
<input type="hidden" name="locator" value="<%- component_locator %>">
</form>
4 changes: 2 additions & 2 deletions cms/templates/js/xblock-validation-messages.underscore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var summaryMessage = validation.get("summary");
var aggregateMessageType = summaryMessage.type;
var aggregateValidationClass = aggregateMessageType === "error"? "has-errors" : "has-warnings";
%>
<div class="xblock-message validation <%= aggregateValidationClass %> <%= additionalClasses %>">
<div class="xblock-message validation <%- aggregateValidationClass %> <%- additionalClasses %>">
<p class="<%- aggregateMessageType %>"><span class="icon fa <%- getIcon(aggregateMessageType) %>" aria-hidden="true"></span>
<%- summaryMessage.text %>
<% if (summaryMessage.action_class) { %>
Expand All @@ -25,7 +25,7 @@ var aggregateValidationClass = aggregateMessageType === "error"? "has-errors" :
var messageType = message.type
var messageTypeDisplayName = getDisplayName(messageType)
%>
<li class="xblock-message-item <%= messageType %>">
<li class="xblock-message-item <%- messageType %>">
<span class="message-text">
<% if (messageTypeDisplayName) { %>
<span class="sr"><%- messageTypeDisplayName %>:</span>
Expand Down
6 changes: 5 additions & 1 deletion lms/djangoapps/badges/events/course_complete.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,12 @@ def evidence_url(user_id, course_key):
Generates a URL to the user's Certificate HTML view, along with a GET variable that will signal the evidence visit
event.
"""
course_id = unicode(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': unicode(course_key)}) + '?evidence_visit=1'
'certificates:render_cert_by_uuid', kwargs={'certificate_uuid': cert.verify_uuid}) + '?evidence_visit=1'


def criteria(course_key):
Expand Down
19 changes: 10 additions & 9 deletions lms/djangoapps/certificates/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,13 +416,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": unicode(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):
Expand Down Expand Up @@ -455,7 +455,7 @@ def get_certificate_url(user_id=None, course_id=None, uuid=None):
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)
return url
Expand Down Expand Up @@ -568,10 +568,11 @@ def emit_certificate_event(event_name, user, course_id, course=None, event_data=
'org_id': course.org,
'course_id': unicode(course_id)
}

data = {
'user_id': user.id,
'course_id': unicode(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)
Expand Down
10 changes: 8 additions & 2 deletions lms/djangoapps/certificates/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@
# Certificates HTML view end point to render web certs by user and course
url(
r'^user/(?P<user_id>[^/]*)/course/{course_id}'.format(course_id=settings.COURSE_ID_PATTERN),
views.render_html_view,
name='html_view'
views.unsupported_url,
name='unsupported_url'
),

url(
r'^course/{course_id}'.format(course_id=settings.COURSE_ID_PATTERN),
views.render_preview_certificate,
name='preview_cert'
),

# Certificates HTML view end point to render web certs by certificate_uuid
Expand Down
63 changes: 31 additions & 32 deletions lms/djangoapps/certificates/views/webview.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import pytz
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.http import Http404, HttpResponse
from django.template import RequestContext
Expand Down Expand Up @@ -43,7 +42,6 @@
from openedx.core.djangoapps.catalog.utils import get_course_run_details
from openedx.core.djangoapps.lang_pref.api import get_closest_released_language
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag, WaffleFlagNamespace
from openedx.core.lib.courses import course_image_url
from openedx.core.djangoapps.certificates.api import display_date_for_certificate, certificates_viewable_for_course
from student.models import LinkedInAddToProfileConfiguration
Expand All @@ -57,21 +55,6 @@


INVALID_CERTIFICATE_TEMPLATE_PATH = 'certificates/invalid.html'
WAFFLE_FLAG_NAMESPACE = WaffleFlagNamespace(name='certificates')
LOGIN_REQUIRED_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'require_login')


def certs_login_required(view):
"""
Require login when the 'certificates.require_login' is enabled
"""
def wrap(request, user_id, course_id, *args, **kwargs):
course_key = CourseKey.from_string(course_id)
if LOGIN_REQUIRED_FLAG.is_enabled(course_key):
return login_required(view)(request, user_id, course_id, *args, **kwargs)
else:
return view(request, user_id, course_id, *args, **kwargs)
return wrap


def get_certificate_description(mode, certificate_type, platform_name):
Expand Down Expand Up @@ -481,6 +464,26 @@ def _update_organization_context(context, course):
context['organization_logo'] = organization_logo


def unsupported_url(request, user_id, course_id):
"""
This view returns the un-supported url page aimed to let the user aware that
url is no longer supported
"""
platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)
configuration = CertificateHtmlViewConfiguration.get_config()
return _render_invalid_certificate(
course_id, platform_name, configuration, cert_path='certificates/url_unsupported.html'
)


@login_required
def render_preview_certificate(request, course_id):
"""
This view renders the course certificate in preview mode
"""
return render_html_view(request, unicode(course_id))


def render_cert_by_uuid(request, certificate_uuid):
"""
This public view generates an HTML representation of the specified certificate
Expand All @@ -490,7 +493,7 @@ def render_cert_by_uuid(request, certificate_uuid):
verify_uuid=certificate_uuid,
status=CertificateStatuses.downloadable
)
return render_html_view(request, certificate.user.id, unicode(certificate.course_id))
return render_html_view(request, unicode(certificate.course_id), certificate)
except GeneratedCertificate.DoesNotExist:
raise Http404

Expand All @@ -499,17 +502,13 @@ def render_cert_by_uuid(request, certificate_uuid):
template_path="certificates/server-error.html",
test_func=lambda request: request.GET.get('preview', None)
)
@certs_login_required
def render_html_view(request, user_id, course_id):
def render_html_view(request, course_id, certificate=None):
"""
This public view generates an HTML representation of the specified user and course
If a certificate is not available, we display a "Sorry!" screen instead
"""
try:
user_id = int(user_id)
except ValueError:
raise Http404

user = certificate.user if certificate else request.user
user_id = user.id
preview_mode = request.GET.get('preview', None)
platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)
configuration = CertificateHtmlViewConfiguration.get_config()
Expand All @@ -521,16 +520,15 @@ def render_html_view(request, user_id, course_id):
# Load the course and user objects
try:
course_key = CourseKey.from_string(course_id)
user = User.objects.get(id=user_id)
course = get_course_by_id(course_key)

# For any course or user exceptions, kick the user back to the "Invalid" screen
except (InvalidKeyError, User.DoesNotExist, Http404) as exception:
except (InvalidKeyError, Http404) as exception:
error_str = (
"Invalid cert: error finding course %s or user with id "
"%d. Specific error: %s"
"Invalid cert: error finding course %s "
"Specific error: %s"
)
log.info(error_str, course_id, user_id, str(exception))
log.info(error_str, course_id, str(exception))
return _render_invalid_certificate(course_id, platform_name, configuration)

# Kick the user back to the "Invalid" screen if the feature is disabled for the course
Expand Down Expand Up @@ -677,10 +675,11 @@ def _get_custom_template_and_language(course_id, course_mode, course_language):
return (None, None)


def _render_invalid_certificate(course_id, platform_name, configuration):
def _render_invalid_certificate(course_id, platform_name, configuration,
cert_path=INVALID_CERTIFICATE_TEMPLATE_PATH):
context = {}
_update_context_with_basic_info(context, course_id, platform_name, configuration)
return render_to_response(INVALID_CERTIFICATE_TEMPLATE_PATH, context)
return render_to_response(cert_path, context)


def _render_valid_certificate(request, context, custom_template=None):
Expand Down
18 changes: 18 additions & 0 deletions lms/templates/certificates/url_unsupported.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<%page expression_filter="h"/>
<%inherit file="accomplishment-base.html" />
<%! from django.utils.translation import gettext as _ %>

<div class="wrapper-content status status-invalid">
<div class="wrapper-content-grid">
<main class="content content-main">
<section class="">
<h2 class="title">${_("URL Not Supported")}</h2>
<div class="copy">
<p>${_("This link is no longer valid. But don’t worry—this Verified Certificate is still valid and available to share. If this is your certificate, please visit your dashboard to get a new shareable link. If you're viewing someone else's certificate, please contact them to get an updated link.")}</p>
</div>
</section>
</main>
<aside role="complementary" class="content-secondary about" aria-label="${_('About {platform_name} Certificates').format(platform_name=platform_name)}">
</aside>
</div>
</div>