diff --git a/cms/djangoapps/models/settings/course_metadata.py b/cms/djangoapps/models/settings/course_metadata.py
index 3356531b84..fadc3d5a87 100644
--- a/cms/djangoapps/models/settings/course_metadata.py
+++ b/cms/djangoapps/models/settings/course_metadata.py
@@ -69,6 +69,11 @@ class CourseMetadata(object):
if not settings.FEATURES.get('ENABLE_MOBILE_SOCIAL_FACEBOOK_FEATURES'):
filtered_list.append('facebook_url')
+ # Do not show social sharing url field if the feature is disabled.
+ if (not settings.FEATURES.get('DASHBOARD_SHARE_SETTINGS') or
+ not settings.FEATURES.get("DASHBOARD_SHARE_SETTINGS").get("CUSTOM_COURSE_URLS")):
+ filtered_list.append('social_sharing_url')
+
return filtered_list
@classmethod
diff --git a/cms/envs/bok_choy.env.json b/cms/envs/bok_choy.env.json
index 2be0a45e66..af6f6002d8 100644
--- a/cms/envs/bok_choy.env.json
+++ b/cms/envs/bok_choy.env.json
@@ -65,6 +65,9 @@
"FEATURES": {
"AUTH_USE_OPENID_PROVIDER": true,
"CERTIFICATES_ENABLED": true,
+ "DASHBOARD_SHARE_SETTINGS": {
+ "CUSTOM_COURSE_URLS": true
+ },
"ENABLE_DISCUSSION_SERVICE": true,
"ENABLE_INSTRUCTOR_ANALYTICS": true,
"ENABLE_S3_GRADE_DOWNLOADS": true,
diff --git a/cms/envs/common.py b/cms/envs/common.py
index 999413ea2a..f3278b0a8b 100644
--- a/cms/envs/common.py
+++ b/cms/envs/common.py
@@ -142,6 +142,12 @@ FEATURES = {
# Enable course reruns, which will always use the split modulestore
'ALLOW_COURSE_RERUNS': True,
+
+ # Social Media Sharing on Student Dashboard
+ 'DASHBOARD_SHARE_SETTINGS': {
+ # Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in lms/envs/common.py
+ 'CUSTOM_COURSE_URLS': False
+ }
}
ENABLE_JASMINE = False
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index e71fa5fdb8..e304606595 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -834,6 +834,17 @@ class CourseFields(object):
scope=Scope.settings,
)
+ social_sharing_url = String(
+ display_name=_("Social Media Sharing URL"),
+ help=_(
+ "If dashboard social sharing and custom course URLs are enabled, you can provide a URL "
+ "(such as the URL to a course About page) that social media sites can link to. URLs must "
+ "be fully qualified. For example: http://www.edx.org/course/Introduction-to-MOOCs-ITM001"
+ ),
+ default=None,
+ scope=Scope.settings,
+ )
+
class CourseModule(CourseFields, SequenceModule): # pylint: disable=abstract-method
"""
diff --git a/common/test/acceptance/pages/lms/dashboard.py b/common/test/acceptance/pages/lms/dashboard.py
index 7736ab3e0a..e1954d13f2 100644
--- a/common/test/acceptance/pages/lms/dashboard.py
+++ b/common/test/acceptance/pages/lms/dashboard.py
@@ -175,3 +175,11 @@ class DashboardPage(PageObject):
Verify if pre-requisite course messages are being displayed.
"""
return self.q(css='li.prerequisites > .tip').visible
+
+ def get_course_listings(self):
+ """Retrieve the list of course DOM elements"""
+ return self.q(css='ul.listing-courses')
+
+ def get_course_social_sharing_widget(self, widget_name):
+ """ Retrieves the specified social sharing widget by its classification """
+ return self.q(css='a.action-{}'.format(widget_name))
diff --git a/common/test/acceptance/pages/studio/settings_advanced.py b/common/test/acceptance/pages/studio/settings_advanced.py
index d556e4b72c..8658e4f5f0 100644
--- a/common/test/acceptance/pages/studio/settings_advanced.py
+++ b/common/test/acceptance/pages/studio/settings_advanced.py
@@ -196,4 +196,5 @@ class AdvancedSettingsPage(CoursePage):
'static_asset_path',
'text_customization',
'annotation_storage_url',
+ 'social_sharing_url',
]
diff --git a/common/test/acceptance/tests/lms/test_lms_dashboard.py b/common/test/acceptance/tests/lms/test_lms_dashboard.py
new file mode 100644
index 0000000000..df5a64412b
--- /dev/null
+++ b/common/test/acceptance/tests/lms/test_lms_dashboard.py
@@ -0,0 +1,79 @@
+# -*- coding: utf-8 -*-
+"""
+End-to-end tests for the main LMS Dashboard (aka, Student Dashboard).
+"""
+from ..helpers import UniqueCourseTest
+from ...fixtures.course import CourseFixture
+from ...pages.lms.auto_auth import AutoAuthPage
+from ...pages.lms.dashboard import DashboardPage
+
+
+class LmsDashboardPageTest(UniqueCourseTest):
+ """ Test suite for the LMS Student Dashboard page """
+
+ def setUp(self):
+ """
+ Initializes the components (page objects, courses, users) for this test suite
+ """
+ # Some parameters are provided by the parent setUp() routine, such as the following:
+ # self.course_id, self.course_info, self.unique_id
+ super(LmsDashboardPageTest, self).setUp()
+
+ # Load page objects for use by the tests
+ self.dashboard_page = DashboardPage(self.browser)
+
+ # Configure some aspects of the test course and install the settings into the course
+ self.course_fixture = CourseFixture(
+ self.course_info["org"],
+ self.course_info["number"],
+ self.course_info["run"],
+ self.course_info["display_name"],
+ )
+ self.course_fixture.add_advanced_settings({
+ u"social_sharing_url": {u"value": "http://custom/course/url"}
+ })
+ self.course_fixture.install()
+
+ # Create the test user, register them for the course, and authenticate
+ self.username = "test_{uuid}".format(uuid=self.unique_id[0:6])
+ self.email = "{user}@example.com".format(user=self.username)
+ AutoAuthPage(
+ self.browser,
+ username=self.username,
+ email=self.email,
+ course_id=self.course_id
+ ).visit()
+
+ # Navigate the authenticated, enrolled user to the dashboard page and get testing!
+ self.dashboard_page.visit()
+
+ def test_dashboard_course_listings(self):
+ """
+ Perform a general validation of the course listings section
+ """
+ course_listings = self.dashboard_page.get_course_listings()
+ self.assertEqual(len(course_listings), 1)
+
+ def test_dashboard_social_sharing_feature(self):
+ """
+ Validate the behavior of the social sharing feature
+ """
+ twitter_widget = self.dashboard_page.get_course_social_sharing_widget('twitter')
+ twitter_url = "https://twitter.com/intent/tweet?text=Testing+feature%3A%20http%3A%2F%2Fcustom%2Fcourse%2Furl" # pylint: disable=line-too-long
+ self.assertEqual(twitter_widget.attrs('title')[0], 'Share on Twitter')
+ self.assertEqual(twitter_widget.attrs('data-tooltip')[0], 'Share on Twitter')
+ self.assertEqual(twitter_widget.attrs('aria-haspopup')[0], 'true')
+ self.assertEqual(twitter_widget.attrs('aria-expanded')[0], 'false')
+ self.assertEqual(twitter_widget.attrs('target')[0], '_blank')
+ self.assertIn(twitter_url, twitter_widget.attrs('href')[0])
+ self.assertIn(twitter_url, twitter_widget.attrs('onclick')[0])
+
+ facebook_widget = self.dashboard_page.get_course_social_sharing_widget('facebook')
+ facebook_url = "https://www.facebook.com/sharer/sharer.php?u=http%3A%2F%2Fcustom%2Fcourse%2Furl"
+ self.assertEqual(facebook_widget.attrs('title')[0], 'Share on Facebook')
+ self.assertEqual(facebook_widget.attrs('data-tooltip')[0], 'Share on Facebook')
+ self.assertEqual(facebook_widget.attrs('aria-haspopup')[0], 'true')
+ self.assertEqual(facebook_widget.attrs('aria-expanded')[0], 'false')
+ self.assertEqual(facebook_widget.attrs('target')[0], '_blank')
+ self.assertIn(facebook_url, facebook_widget.attrs('href')[0])
+ self.assertIn(facebook_url, facebook_widget.attrs('onclick')[0])
diff --git a/lms/envs/bok_choy.env.json b/lms/envs/bok_choy.env.json
index e95aeffe13..9ec30bf3fa 100644
--- a/lms/envs/bok_choy.env.json
+++ b/lms/envs/bok_choy.env.json
@@ -67,6 +67,12 @@
"CERTIFICATES_ENABLED": true,
"CERTIFICATES_HTML_VIEW": true,
"MULTIPLE_ENROLLMENT_ROLES": true,
+ "DASHBOARD_SHARE_SETTINGS": {
+ "CUSTOM_COURSE_URLS": true,
+ "FACEBOOK_SHARING": true,
+ "TWITTER_SHARING": true,
+ "TWITTER_SHARING_TEXT": "Testing feature:"
+ },
"ENABLE_PAYMENT_FAKE": true,
"ENABLE_VERIFIED_CERTIFICATES": true,
"ENABLE_DISCUSSION_SERVICE": true,
diff --git a/lms/envs/common.py b/lms/envs/common.py
index daef8e9282..6f8c69d5be 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -374,6 +374,8 @@ FEATURES = {
# Social Media Sharing on Student Dashboard
'DASHBOARD_SHARE_SETTINGS': {
+ # Note: Ensure 'CUSTOM_COURSE_URLS' has a matching value in cms/envs/common.py
+ 'CUSTOM_COURSE_URLS': False,
'FACEBOOK_SHARING': False,
'TWITTER_SHARING': False,
'TWITTER_SHARING_TEXT': None
diff --git a/lms/templates/dashboard/_dashboard_course_listing.html b/lms/templates/dashboard/_dashboard_course_listing.html
index dd380061aa..3e4174cdaa 100644
--- a/lms/templates/dashboard/_dashboard_course_listing.html
+++ b/lms/templates/dashboard/_dashboard_course_listing.html
@@ -117,10 +117,18 @@ from student.helpers import (
% endif
% if share_settings:
- <% share_url = urllib.quote_plus(request.build_absolute_uri(reverse('about_course', args=[unicode(course.id)]))) %>
- <% share_window_name = 'shareWindow' %>
- <% share_window_config = 'toolbar=no, location=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=640, height=480' %>
- % if share_settings.get('FACEBOOK_SHARING', False):
+ <%
+ if share_settings.get("CUSTOM_COURSE_URLS", False):
+ if course.social_sharing_url:
+ share_url = urllib.quote_plus(course.social_sharing_url)
+ else:
+ share_url = ''
+ else:
+ share_url = urllib.quote_plus(request.build_absolute_uri(reverse('about_course', args=[unicode(course.id)])))
+ share_window_name = 'shareWindow'
+ share_window_config = 'toolbar=no, location=no, status=no, menubar=no, scrollbars=yes, resizable=yes, width=640, height=480'
+ %>
+ % if share_url and share_settings.get('FACEBOOK_SHARING', False):
<% facebook_url = 'https://www.facebook.com/sharer/sharer.php?u=' + share_url %>
% endif
- % if share_settings.get('TWITTER_SHARING', False):
+ % if share_url and share_settings.get('TWITTER_SHARING', False):
<% share_text_default = _("I'm learning on {platform_name}:").format(platform_name=settings.PLATFORM_NAME) %>
- <% share_text = share_settings.get('TWITTER_SHARING_TEXT', share_text_default) %>
+ <% share_text = urllib.quote_plus(share_settings.get('TWITTER_SHARING_TEXT', share_text_default)) %>
<% twitter_url = 'https://twitter.com/intent/tweet?text=' + share_text + '%20' + share_url %>
${_('Twitter')}