Commit e1ee5ac6 by Matt Drayer

mattdrayer/SOL-981: Integrate edx-organizations application

* asadiqbal08/SOL-1058: Add edx-organizations to certificate web view
  * Support organization logo asset management
  * Remove organization fields from Studio certificate configuration model

* SOL-981 pull request feedback fixes
parent 4e9b7ea9
...@@ -1033,7 +1033,6 @@ class CourseMetadataEditingTest(CourseTestCase): ...@@ -1033,7 +1033,6 @@ class CourseMetadataEditingTest(CourseTestCase):
'id': 1, 'id': 1,
'name': 'Certificate Config Name', 'name': 'Certificate Config Name',
'course_title': 'Title override', 'course_title': 'Title override',
'org_logo_path': '/c4x/test/CSS101/asset/org_logo.png',
'signatories': [], 'signatories': [],
'is_active': True 'is_active': True
} }
......
...@@ -177,8 +177,6 @@ class CertificateManager(object): ...@@ -177,8 +177,6 @@ class CertificateManager(object):
"name": certificate_data['name'], "name": certificate_data['name'],
"description": certificate_data['description'], "description": certificate_data['description'],
"version": CERTIFICATE_SCHEMA_VERSION, "version": CERTIFICATE_SCHEMA_VERSION,
"org_logo_path": certificate_data.get('org_logo_path', ''),
"is_active": certificate_data.get('is_active', False),
"signatories": certificate_data['signatories'] "signatories": certificate_data['signatories']
} }
...@@ -231,7 +229,6 @@ class CertificateManager(object): ...@@ -231,7 +229,6 @@ class CertificateManager(object):
if int(cert['id']) == int(certificate_id): if int(cert['id']) == int(certificate_id):
certificate = course.certificates['certificates'][index] certificate = course.certificates['certificates'][index]
# Remove any signatory assets prior to dropping the entire cert record from the course # Remove any signatory assets prior to dropping the entire cert record from the course
_delete_asset(course.id, certificate['org_logo_path'])
for sig_index, signatory in enumerate(certificate.get('signatories')): # pylint: disable=unused-variable for sig_index, signatory in enumerate(certificate.get('signatories')): # pylint: disable=unused-variable
_delete_asset(course.id, signatory['signature_image_path']) _delete_asset(course.id, signatory['signature_image_path'])
# Now drop the certificate record # Now drop the certificate record
......
...@@ -93,13 +93,11 @@ class HelperMethods(object): ...@@ -93,13 +93,11 @@ class HelperMethods(object):
'id': i, 'id': i,
'name': 'Name ' + str(i), 'name': 'Name ' + str(i),
'description': 'Description ' + str(i), 'description': 'Description ' + str(i),
'org_logo_path': '/c4x/test/CSS101/asset/org_logo{}.png'.format(i),
'signatories': signatories, 'signatories': signatories,
'version': CERTIFICATE_SCHEMA_VERSION, 'version': CERTIFICATE_SCHEMA_VERSION,
'is_active': is_active 'is_active': is_active
} for i in xrange(0, count) } for i in xrange(0, count)
] ]
self._create_fake_images([certificate['org_logo_path'] for certificate in certificates])
self.course.certificates = {'certificates': certificates} self.course.certificates = {'certificates': certificates}
self.save_course() self.save_course()
...@@ -219,8 +217,6 @@ class CertificatesListHandlerTestCase(EventTestMixin, CourseTestCase, Certificat ...@@ -219,8 +217,6 @@ class CertificatesListHandlerTestCase(EventTestMixin, CourseTestCase, Certificat
u'version': CERTIFICATE_SCHEMA_VERSION, u'version': CERTIFICATE_SCHEMA_VERSION,
u'name': u'Test certificate', u'name': u'Test certificate',
u'description': u'Test description', u'description': u'Test description',
u'org_logo_path': '',
u'is_active': False,
u'signatories': [] u'signatories': []
} }
response = self.client.ajax_post( response = self.client.ajax_post(
...@@ -388,8 +384,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific ...@@ -388,8 +384,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific
u'name': u'Test certificate', u'name': u'Test certificate',
u'description': u'Test description', u'description': u'Test description',
u'course_title': u'Course Title Override', u'course_title': u'Course Title Override',
u'org_logo_path': '',
u'is_active': False,
u'signatories': [] u'signatories': []
} }
...@@ -420,8 +414,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific ...@@ -420,8 +414,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific
u'name': u'New test certificate', u'name': u'New test certificate',
u'description': u'New test description', u'description': u'New test description',
u'course_title': u'Course Title Override', u'course_title': u'Course Title Override',
u'org_logo_path': '',
u'is_active': False,
u'signatories': [] u'signatories': []
} }
...@@ -453,11 +445,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific ...@@ -453,11 +445,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific
Delete certificate Delete certificate
""" """
self._add_course_certificates(count=2, signatory_count=1) self._add_course_certificates(count=2, signatory_count=1)
certificates = self.course.certificates['certificates']
org_logo_url = certificates[1]['org_logo_path']
image_asset_location = AssetLocation.from_deprecated_string(org_logo_url)
content = contentstore().find(image_asset_location)
self.assertIsNotNone(content)
response = self.client.delete( response = self.client.delete(
self._url(cid=1), self._url(cid=1),
content_type="application/json", content_type="application/json",
...@@ -474,8 +461,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific ...@@ -474,8 +461,6 @@ class CertificatesDetailHandlerTestCase(EventTestMixin, CourseTestCase, Certific
# Verify that certificates are properly updated in the course. # Verify that certificates are properly updated in the course.
certificates = self.course.certificates['certificates'] certificates = self.course.certificates['certificates']
self.assertEqual(len(certificates), 1) self.assertEqual(len(certificates), 1)
# make sure certificate org logo is deleted too
self.assertRaises(NotFoundError, contentstore().find, image_asset_location)
self.assertEqual(certificates[0].get('name'), 'Name 0') self.assertEqual(certificates[0].get('name'), 'Name 0')
self.assertEqual(certificates[0].get('description'), 'Description 0') self.assertEqual(certificates[0].get('description'), 'Description 0')
......
...@@ -20,7 +20,6 @@ function (_, str, Backbone, BackboneRelational, BackboneAssociations, gettext, C ...@@ -20,7 +20,6 @@ function (_, str, Backbone, BackboneRelational, BackboneAssociations, gettext, C
defaults: { defaults: {
// Metadata fields currently displayed in web forms // Metadata fields currently displayed in web forms
course_title: '', course_title: '',
org_logo_path: '',
// Metadata fields not currently displayed in web forms // Metadata fields not currently displayed in web forms
name: 'Name of the certificate', name: 'Name of the certificate',
......
...@@ -41,7 +41,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce ...@@ -41,7 +41,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
uploadDialog: 'form.upload-dialog', uploadDialog: 'form.upload-dialog',
uploadDialogButton: '.action-upload', uploadDialogButton: '.action-upload',
uploadDialogFileInput: 'form.upload-dialog input[type=file]', uploadDialogFileInput: 'form.upload-dialog input[type=file]',
uploadOrgLogoButton: '.action-upload-org-logo',
saveCertificateButton: 'button.action-primary' saveCertificateButton: 'button.action-primary'
}; };
...@@ -311,9 +310,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce ...@@ -311,9 +310,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
setValuesToInputs(this.view, { setValuesToInputs(this.view, {
inputCertificateDescription: 'New Test Description' inputCertificateDescription: 'New Test Description'
}); });
this.view.$(SELECTORS.uploadOrgLogoButton).click();
var org_logo_path = '/c4x/edX/DemoX/asset/org-logo.png';
uploadFile(org_logo_path, requests);
setValuesToInputs(this.view, { setValuesToInputs(this.view, {
inputSignatoryName: 'New Signatory Name' inputSignatoryName: 'New Signatory Name'
...@@ -334,8 +330,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce ...@@ -334,8 +330,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce
ViewHelpers.submitAndVerifyFormSuccess(this.view, requests, notificationSpy); ViewHelpers.submitAndVerifyFormSuccess(this.view, requests, notificationSpy);
expect(this.model).toBeCorrectValuesInModel({ expect(this.model).toBeCorrectValuesInModel({
name: 'New Test Name', name: 'New Test Name',
description: 'New Test Description', description: 'New Test Description'
org_logo_path: org_logo_path
}); });
// get the first signatory from the signatories collection. // get the first signatory from the signatories collection.
......
...@@ -7,12 +7,10 @@ define([ // jshint ignore:line ...@@ -7,12 +7,10 @@ define([ // jshint ignore:line
'gettext', 'gettext',
'js/views/list_item_editor', 'js/views/list_item_editor',
'js/certificates/models/signatory', 'js/certificates/models/signatory',
'js/certificates/views/signatory_editor', 'js/certificates/views/signatory_editor'
'js/models/uploads',
'js/views/uploads'
], ],
function($, _, Backbone, gettext, function($, _, Backbone, gettext,
ListItemEditorView, SignatoryModel, SignatoryEditorView, FileUploadModel, FileUploadDialog) { ListItemEditorView, SignatoryModel, SignatoryEditorView) {
'use strict'; 'use strict';
var MAX_SIGNATORIES_LIMIT = 4; var MAX_SIGNATORIES_LIMIT = 4;
var CertificateEditorView = ListItemEditorView.extend({ var CertificateEditorView = ListItemEditorView.extend({
...@@ -21,13 +19,11 @@ function($, _, Backbone, gettext, ...@@ -21,13 +19,11 @@ function($, _, Backbone, gettext,
'change .collection-name-input': 'setName', 'change .collection-name-input': 'setName',
'change .certificate-description-input': 'setDescription', 'change .certificate-description-input': 'setDescription',
'change .certificate-course-title-input': 'setCourseTitle', 'change .certificate-course-title-input': 'setCourseTitle',
'change .org-logo-input': 'setOrgLogoPath',
'focus .input-text': 'onFocus', 'focus .input-text': 'onFocus',
'blur .input-text': 'onBlur', 'blur .input-text': 'onBlur',
'submit': 'setAndClose', 'submit': 'setAndClose',
'click .action-cancel': 'cancel', 'click .action-cancel': 'cancel',
'click .action-add-signatory': 'addSignatory', 'click .action-add-signatory': 'addSignatory'
'click .action-upload-org-logo': 'uploadLogoImage'
}, },
className: function () { className: function () {
...@@ -141,45 +137,12 @@ function($, _, Backbone, gettext, ...@@ -141,45 +137,12 @@ function($, _, Backbone, gettext,
); );
}, },
setOrgLogoPath: function(event) {
// Updates the indicated model field (still requires persistence on server)
if (event && event.preventDefault) { event.preventDefault(); }
var org_logo_path = this.$('.org-logo-input').val();
this.model.set(
'org_logo_path', org_logo_path,
{ silent: true }
);
this.$('.current-org-logo img.org-logo').attr('src', org_logo_path);
},
setValues: function() { setValues: function() {
// Update the specified values in the local model instance // Update the specified values in the local model instance
this.setName(); this.setName();
this.setDescription(); this.setDescription();
this.setCourseTitle(); this.setCourseTitle();
this.setOrgLogoPath();
return this; return this;
},
uploadLogoImage: function(event) {
event.preventDefault();
var upload = new FileUploadModel({
title: gettext("Upload organization logo."),
message: gettext("Maximum logo height should be 125px."),
mimeTypes: ['image/png', 'image/jpeg']
});
var self = this;
var modal = new FileUploadDialog({
model: upload,
onSuccess: function(response) {
var org_logo_path = response.asset.url;
self.model.set('org_logo_path', org_logo_path);
self.$('.current-org-logo img.org-logo').attr('src', org_logo_path);
self.$('.current-org-logo').show();
self.$('input.org-logo-input').attr('value', org_logo_path);
}
});
modal.show();
} }
}); });
return CertificateEditorView; return CertificateEditorView;
......
...@@ -313,49 +313,6 @@ ...@@ -313,49 +313,6 @@
border-color: $red; border-color: $red;
} }
} }
.org-logo-upload-wrapper {
@include clearfix();
width: flex-grid(12,12);
.org-logo-upload-input-wrapper {
float: left;
width: flex-grid(7,12);
margin-right: flex-gutter();
}
.action-upload-org-logo {
@extend %ui-btn-flat-outline;
float: right;
width: flex-grid(4,12);
margin-top: ($baseline/4);
padding: ($baseline/2) $baseline;
}
}
.current-org-logo {
margin-bottom: ($baseline/2);
padding: ($baseline/2) $baseline;
background: $gray-l5;
text-align: center;
.wrapper-org-logo {
display: block;
width: 375px;
height: 200px;
overflow: hidden;
margin: 0 auto;
border: 1px solid $gray-l4;
box-shadow: 0 1px 1px $shadow-l1;
padding: ($baseline/2);
background: $white;
}
.org-logo {
display: block;
width: 100%;
min-height: 100%;
}
}
} }
label.required { label.required {
......
...@@ -24,17 +24,6 @@ ...@@ -24,17 +24,6 @@
<input id="certificate-course-title-<%= uniqueId %>" class="certificate-course-title-input input-text" name="certificate-course-title" type="text" placeholder="<%= gettext("Course title") %>" value="<%= course_title %>" aria-describedby="certificate-course-title-<%=uniqueId %>-tip" /> <input id="certificate-course-title-<%= uniqueId %>" class="certificate-course-title-input input-text" name="certificate-course-title" type="text" placeholder="<%= gettext("Course title") %>" value="<%= course_title %>" aria-describedby="certificate-course-title-<%=uniqueId %>-tip" />
<span id="certificate-course-title-<%= uniqueId %>-tip" class="tip tip-stacked"><%= gettext("Specify an alternative to the official course title to display on certificates. Leave blank to use the official course title.") %></span> <span id="certificate-course-title-<%= uniqueId %>-tip" class="tip tip-stacked"><%= gettext("Specify an alternative to the official course title to display on certificates. Leave blank to use the official course title.") %></span>
</div> </div>
<div class="input-wrap field text add-org-logo">
<label for="certificate-org-logo-<%= uniqueId %>"><%= gettext("Organization Logo") %></label>
<div class="current-org-logo" <% if (org_logo_path == "") { print('style="display:none"'); } %>><span class="wrapper-org-logo"><img class="org-logo" src="<%= org_logo_path %>" alt="Organization Logo"></span></div>
<div class="org-logo-upload-wrapper">
<div class="org-logo-upload-input-wrapper">
<input id="certificate-org-logo-<%= uniqueId %>" class="collection-name-input input-text org-logo-input" name="org-logo-path" type="text" placeholder="<%= gettext("Path to organization logo") %>" value="<%= org_logo_path %>" aria-describedby="certificate-org-logo-<%=uniqueId %>-tip" readonly />
<span id="certificate-org-logo-<%=uniqueId %>-tip" class="tip tip-stacked"><%= gettext("Maximum logo height 125px, width variable") %></span>
</div>
<button type="button" class="action action-upload-org-logo">Upload Organization Logo</button>
</div>
</div>
</fieldset> </fieldset>
<header> <header>
<span class="title"><%= gettext("Certificate Signatories") %></legend> <span class="title"><%= gettext("Certificate Signatories") %></legend>
......
# pylint: disable=invalid-name
"""
Utility library for working with the edx-organizations app
"""
from django.conf import settings
def add_organization(organization_data):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return None
from organizations import api as organizations_api
return organizations_api.add_organization(organization_data=organization_data)
def add_organization_course(organization_data, course_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return None
from organizations import api as organizations_api
return organizations_api.add_organization_course(organization_data=organization_data, course_key=course_id)
def get_organization(organization_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return []
from organizations import api as organizations_api
return organizations_api.get_organization(organization_id)
def get_organizations():
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return []
from organizations import api as organizations_api
return organizations_api.get_organizations()
def get_organization_courses(organization_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return []
from organizations import api as organizations_api
return organizations_api.get_organization_courses(organization_id)
def get_course_organizations(course_id):
"""
Client API operation adapter/wrapper
"""
if not settings.FEATURES.get('ORGANIZATIONS_APP', False):
return []
from organizations import api as organizations_api
return organizations_api.get_course_organizations(course_id)
"""
Tests for the organizations helpers library, which is the integration point for the edx-organizations API
"""
from mock import patch
from util import organizations_helpers
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.factories import CourseFactory
@patch.dict('django.conf.settings.FEATURES', {'ORGANIZATIONS_APP': False})
class OrganizationsHelpersTestCase(ModuleStoreTestCase):
"""
Main test suite for Organizations API client library
"""
def setUp(self):
"""
Test case scaffolding
"""
super(OrganizationsHelpersTestCase, self).setUp(create_user=False)
self.course = CourseFactory.create()
self.organization = {
'name': 'Test Organization',
'description': 'Testing Organization Helpers Library',
}
def test_get_organization_returns_none_when_app_disabled(self):
response = organizations_helpers.get_organization(1)
self.assertEqual(len(response), 0)
def test_get_organizations_returns_none_when_app_disabled(self):
response = organizations_helpers.get_organizations()
self.assertEqual(len(response), 0)
def test_get_organization_courses_returns_none_when_app_disabled(self):
response = organizations_helpers.get_organization_courses(1)
self.assertEqual(len(response), 0)
def test_get_course_organizations_returns_none_when_app_disabled(self):
response = organizations_helpers.get_course_organizations(unicode(self.course.id))
self.assertEqual(len(response), 0)
def test_add_organization_returns_none_when_app_disabled(self):
response = organizations_helpers.add_organization(organization_data=self.organization)
self.assertIsNone(response)
def test_add_organization_course_returns_none_when_app_disabled(self):
response = organizations_helpers.add_organization_course(self.organization, self.course.id)
self.assertIsNone(response)
...@@ -215,7 +215,6 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase): ...@@ -215,7 +215,6 @@ class GenerateUserCertificatesTest(EventTestMixin, ModuleStoreTestCase):
'name': 'Test Certificate Name', 'name': 'Test Certificate Name',
'description': 'Test Certificate Description', 'description': 'Test Certificate Description',
'course_title': 'tes_course_title', 'course_title': 'tes_course_title',
'org_logo_path': '/t4x/orgX/testX/asset/org-logo.png',
'signatories': [], 'signatories': [],
'version': 1, 'version': 1,
'is_active': True 'is_active': True
......
...@@ -37,6 +37,7 @@ from certificates.tests.factories import ( ...@@ -37,6 +37,7 @@ from certificates.tests.factories import (
BadgeAssertionFactory, BadgeAssertionFactory,
) )
from lms import urls from lms import urls
from util import organizations_helpers as organizations_api
FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy() FEATURES_WITH_CERTS_ENABLED = settings.FEATURES.copy()
FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True FEATURES_WITH_CERTS_ENABLED['CERTIFICATES_HTML_VIEW'] = True
...@@ -259,7 +260,6 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase): ...@@ -259,7 +260,6 @@ class MicrositeCertificatesViewsTests(ModuleStoreTestCase):
'name': 'Name ' + str(i), 'name': 'Name ' + str(i),
'description': 'Description ' + str(i), 'description': 'Description ' + str(i),
'course_title': 'course_title_' + str(i), 'course_title': 'course_title_' + str(i),
'org_logo_path': '/t4x/orgX/testX/asset/org-logo-{}.png'.format(i),
'signatories': signatories, 'signatories': signatories,
'version': 1, 'version': 1,
'is_active': is_active 'is_active': is_active
...@@ -428,6 +428,39 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): ...@@ -428,6 +428,39 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
self.store.update_item(self.course, self.user.id) self.store.update_item(self.course, self.user.id)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED) @override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_rendering_course_organization_data(self):
"""
Test: organization data should render on certificate web view if course has organization.
"""
test_organization_data = {
'name': 'test_organization',
'description': 'Test Organization Description',
'active': True,
'logo': '/logo_test1.png/'
}
test_org = organizations_api.add_organization(organization_data=test_organization_data)
organizations_api.add_organization_course(organization_data=test_org, course_id=unicode(self.course.id))
self._add_course_certificates(count=1, signatory_count=1, is_active=True)
test_url = get_certificate_url(
user_id=self.user.id,
course_id=unicode(self.course.id)
)
response = self.client.get(test_url)
self.assertIn(
'a course of study offered by test_organization',
response.content
)
self.assertNotIn(
'a course of study offered by testorg',
response.content
)
self.assertIn(
'<title>test_organization {} Certificate |'.format(self.course.number, ),
response.content
)
self.assertIn('logo_test1.png', response.content)
@override_settings(FEATURES=FEATURES_WITH_CERTS_ENABLED)
def test_render_html_view_valid_certificate(self): def test_render_html_view_valid_certificate(self):
test_url = get_certificate_url( test_url = get_certificate_url(
user_id=self.user.id, user_id=self.user.id,
...@@ -458,7 +491,6 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase): ...@@ -458,7 +491,6 @@ class CertificatesViewsTests(ModuleStoreTestCase, EventTrackingTestCase):
self._add_course_certificates(count=1, signatory_count=2) self._add_course_certificates(count=1, signatory_count=2)
response = self.client.get(test_url) response = self.client.get(test_url)
self.assertIn('course_title_0', response.content) self.assertIn('course_title_0', response.content)
self.assertIn('/t4x/orgX/testX/asset/org-logo-0.png', response.content)
self.assertIn('Signatory_Name 0', response.content) self.assertIn('Signatory_Name 0', response.content)
self.assertIn('Signatory_Title 0', response.content) self.assertIn('Signatory_Title 0', response.content)
self.assertIn('Signatory_Organization 0', response.content) self.assertIn('Signatory_Organization 0', response.content)
......
...@@ -43,6 +43,7 @@ from student.models import LinkedInAddToProfileConfiguration ...@@ -43,6 +43,7 @@ from student.models import LinkedInAddToProfileConfiguration
from util.json_request import JsonResponse, JsonResponseBadRequest from util.json_request import JsonResponse, JsonResponseBadRequest
from util.bad_request_rate_limiter import BadRequestRateLimiter from util.bad_request_rate_limiter import BadRequestRateLimiter
from courseware.courses import course_image_url from courseware.courses import course_image_url
from util import organizations_helpers as organization_api
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -299,13 +300,20 @@ def _update_certificate_context(context, course, user, user_certificate): ...@@ -299,13 +300,20 @@ def _update_certificate_context(context, course, user, user_certificate):
user_fullname = user.profile.name user_fullname = user.profile.name
platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME) platform_name = microsite.get_value("platform_name", settings.PLATFORM_NAME)
certificate_type = context.get('certificate_type') certificate_type = context.get('certificate_type')
partner_name = course.org
organizations = organization_api.get_course_organizations(course_id=course.id)
if organizations:
#TODO Need to add support for multiple organizations, Currently we are interested in the first one.
organization = organizations[0]
partner_name = organization.get('name', course.org)
context['organization_logo'] = organization.get('logo', None)
context['username'] = user.username context['username'] = user.username
context['course_mode'] = user_certificate.mode context['course_mode'] = user_certificate.mode
context['accomplishment_user_id'] = user.id context['accomplishment_user_id'] = user.id
context['accomplishment_copy_name'] = user_fullname context['accomplishment_copy_name'] = user_fullname
context['accomplishment_copy_username'] = user.username context['accomplishment_copy_username'] = user.username
context['accomplishment_copy_course_org'] = course.org context['accomplishment_copy_course_org'] = partner_name
context['accomplishment_copy_course_name'] = course.display_name context['accomplishment_copy_course_name'] = course.display_name
context['course_image_url'] = course_image_url(course) context['course_image_url'] = course_image_url(course)
context['share_settings'] = settings.FEATURES.get('SOCIAL_SHARING_SETTINGS', {}) context['share_settings'] = settings.FEATURES.get('SOCIAL_SHARING_SETTINGS', {})
...@@ -330,14 +338,10 @@ def _update_certificate_context(context, course, user, user_certificate): ...@@ -330,14 +338,10 @@ def _update_certificate_context(context, course, user, user_certificate):
year=user_certificate.modified_date.year year=user_certificate.modified_date.year
) )
accd_course_org_html = '<span class="detail--xuniversity">{partner_name}</span>'.format(partner_name=course.org)
accd_platform_name_html = '<span class="detail--company">{platform_name}</span>'.format(platform_name=platform_name)
# Translators: This line appears on the certificate after the name of a course, and provides more
# information about the organizations providing the course material to platform users
context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_name}, ' context['accomplishment_copy_course_description'] = _('a course of study offered by {partner_name}, '
'through {platform_name}.').format( 'through {platform_name}.').format(
partner_name=accd_course_org_html, partner_name=partner_name,
platform_name=accd_platform_name_html platform_name=platform_name
) )
# Translators: Accomplishments describe the awards/certifications obtained by students on this platform # Translators: Accomplishments describe the awards/certifications obtained by students on this platform
...@@ -412,13 +416,13 @@ def _update_certificate_context(context, course, user, user_certificate): ...@@ -412,13 +416,13 @@ def _update_certificate_context(context, course, user, user_certificate):
'who participated in {partner_name} {course_number}').format( 'who participated in {partner_name} {course_number}').format(
platform_name=platform_name, platform_name=platform_name,
user_name=user_fullname, user_name=user_fullname,
partner_name=course.org, partner_name=partner_name,
course_number=course.number course_number=course.number
) )
# Translators: This text is bound to the HTML 'title' element of the page and appears in the browser title bar # Translators: This text is bound to the HTML 'title' element of the page and appears in the browser title bar
context['document_title'] = _("{partner_name} {course_number} Certificate | {platform_name}").format( context['document_title'] = _("{partner_name} {course_number} Certificate | {platform_name}").format(
partner_name=course.org, partner_name=partner_name,
course_number=course.number, course_number=course.number,
platform_name=platform_name platform_name=platform_name
) )
......
...@@ -897,7 +897,6 @@ class ProgressPageTests(ModuleStoreTestCase): ...@@ -897,7 +897,6 @@ class ProgressPageTests(ModuleStoreTestCase):
'name': 'Name 1', 'name': 'Name 1',
'description': 'Description 1', 'description': 'Description 1',
'course_title': 'course_title_1', 'course_title': 'course_title_1',
'org_logo_path': '/t4x/orgX/testX/asset/org-logo-1.png',
'signatories': [], 'signatories': [],
'version': 1, 'version': 1,
'is_active': True 'is_active': True
......
...@@ -346,6 +346,9 @@ FEATURES = { ...@@ -346,6 +346,9 @@ FEATURES = {
# Milestones application flag # Milestones application flag
'MILESTONES_APP': False, 'MILESTONES_APP': False,
# Organizations application flag
'ORGANIZATIONS_APP': False,
# Prerequisite courses feature flag # Prerequisite courses feature flag
'ENABLE_PREREQUISITE_COURSES': False, 'ENABLE_PREREQUISITE_COURSES': False,
...@@ -2402,6 +2405,9 @@ OPTIONAL_APPS = ( ...@@ -2402,6 +2405,9 @@ OPTIONAL_APPS = (
# edX Proctoring # edX Proctoring
'edx_proctoring', 'edx_proctoring',
# Organizations App (http://github.com/edx/edx-organizations)
'organizations',
) )
for app_name in OPTIONAL_APPS: for app_name in OPTIONAL_APPS:
......
...@@ -121,6 +121,8 @@ PASSWORD_COMPLEXITY = {} ...@@ -121,6 +121,8 @@ PASSWORD_COMPLEXITY = {}
########################### Milestones ################################# ########################### Milestones #################################
FEATURES['MILESTONES_APP'] = True FEATURES['MILESTONES_APP'] = True
########################### Milestones #################################
FEATURES['ORGANIZATIONS_APP'] = True
########################### Entrance Exams ################################# ########################### Entrance Exams #################################
FEATURES['ENTRANCE_EXAMS'] = True FEATURES['ENTRANCE_EXAMS'] = True
......
...@@ -520,3 +520,6 @@ PROFILE_IMAGE_MIN_BYTES = 100 ...@@ -520,3 +520,6 @@ PROFILE_IMAGE_MIN_BYTES = 100
FEATURES['ENABLE_LTI_PROVIDER'] = True FEATURES['ENABLE_LTI_PROVIDER'] = True
INSTALLED_APPS += ('lti_provider',) INSTALLED_APPS += ('lti_provider',)
AUTHENTICATION_BACKENDS += ('lti_provider.users.LtiBackend',) AUTHENTICATION_BACKENDS += ('lti_provider.users.LtiBackend',)
# ORGANIZATIONS
FEATURES['ORGANIZATIONS_APP'] = True
...@@ -75,10 +75,10 @@ course_mode_class = course_mode if course_mode else '' ...@@ -75,10 +75,10 @@ course_mode_class = course_mode if course_mode else ''
</div> </div>
</li> </li>
% if certificate_data and certificate_data.get('org_logo_path', ''): % if organization_logo:
<li class="wrapper-organization"> <li class="wrapper-organization">
<div class="organization"> <div class="organization">
<img class="organization-logo" src="${static.url(certificate_data['org_logo_path'])}" alt="${platform_name}"> <img class="organization-logo" src="${organization_logo.url}" alt="${platform_name}">
</div> </div>
</li> </li>
% endif % endif
......
...@@ -57,6 +57,7 @@ git+https://github.com/edx/edx-lint.git@ed8c8d2a0267d4d42f43642d193e25f8bd575d9b ...@@ -57,6 +57,7 @@ git+https://github.com/edx/edx-lint.git@ed8c8d2a0267d4d42f43642d193e25f8bd575d9b
git+https://github.com/edx/ecommerce-api-client.git@1.1.0#egg=ecommerce-api-client==1.1.0 git+https://github.com/edx/ecommerce-api-client.git@1.1.0#egg=ecommerce-api-client==1.1.0
-e git+https://github.com/edx/edx-user-state-client.git@30c0ad4b9f57f8d48d6943eb585ec8a9205f4469#egg=edx-user-state-client -e git+https://github.com/edx/edx-user-state-client.git@30c0ad4b9f57f8d48d6943eb585ec8a9205f4469#egg=edx-user-state-client
-e git+https://github.com/edx/edx-proctoring.git@release-2015-07-29#egg=edx-proctoring -e git+https://github.com/edx/edx-proctoring.git@release-2015-07-29#egg=edx-proctoring
-e git+https://github.com/edx/edx-organizations.git@release-2015-08-03#egg=edx-organizations
# Third Party XBlocks # Third Party XBlocks
-e git+https://github.com/mitodl/edx-sga@172a90fd2738f8142c10478356b2d9ed3e55334a#egg=edx-sga -e git+https://github.com/mitodl/edx-sga@172a90fd2738f8142c10478356b2d9ed3e55334a#egg=edx-sga
......
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