From ffe30da7a58a330556b76a6e5e1872400b6b1d2b Mon Sep 17 00:00:00 2001 From: Matt Drayer Date: Fri, 3 Apr 2015 10:03:58 -0400 Subject: [PATCH] Add course-specific URL overrides for social sharing icons on student dashboard - sharing enabled for custom URLs only if URL actually specified --- .../models/settings/course_metadata.py | 5 ++ cms/envs/bok_choy.env.json | 3 + cms/envs/common.py | 6 ++ common/lib/xmodule/xmodule/course_module.py | 11 +++ common/test/acceptance/pages/lms/dashboard.py | 8 ++ .../pages/studio/settings_advanced.py | 1 + .../tests/lms/test_lms_dashboard.py | 79 +++++++++++++++++++ lms/envs/bok_choy.env.json | 6 ++ lms/envs/common.py | 2 + .../dashboard/_dashboard_course_listing.html | 23 +++--- 10 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 common/test/acceptance/tests/lms/test_lms_dashboard.py 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')}