Merge pull request #7315 from edx/db/creative-commons

Allow custom licensing for course content
This commit is contained in:
Sarina Canelake
2015-05-18 15:36:50 -04:00
58 changed files with 1582 additions and 75 deletions

View File

@@ -88,6 +88,16 @@ class CoursewarePage(CoursePage):
return True
@property
def course_license(self):
"""
Returns the course license text, if present. Else returns None.
"""
element = self.q(css="#content .container-footer .course-license")
if element.is_present():
return element.text[0]
return None
def get_active_subsection_url(self):
"""
return the url of the active subsection in the left nav

View File

@@ -487,6 +487,19 @@ class XBlockWrapper(PageObject):
"""
type_in_codemirror(self, index, text, find_prefix='$("{}").find'.format(self.editor_selector))
def set_license(self, license_type):
"""
Uses the UI to set the course's license to the given license_type (str)
"""
css_selector = (
"ul.license-types li[data-license={license_type}] button"
).format(license_type=license_type)
self.wait_for_element_presence(
css_selector,
"{license_type} button is present".format(license_type=license_type)
)
self.q(css=css_selector).click()
def save_settings(self):
"""
Click on settings Save button.

View File

@@ -579,6 +579,13 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
"""
return self.children(CourseOutlineChild)
@property
def license(self):
"""
Returns the course license text, if present. Else returns None.
"""
return self.q(css=".license-value").first.text[0]
class CourseOutlineModal(object):
MODAL_SELECTOR = ".wrapper-modal-window"

View File

@@ -1,6 +1,8 @@
# coding: utf-8
"""
Course Schedule and Details Settings page.
"""
from __future__ import unicode_literals
from bok_choy.promise import EmptyPromise
from .course_page import CoursePage
@@ -17,6 +19,13 @@ class SettingsPage(CoursePage):
def is_browser_on_page(self):
return self.q(css='body.view-settings').present
def refresh_and_wait_for_load(self):
"""
Refresh the page and wait for all resources to load.
"""
self.browser.refresh()
self.wait_for_page()
def get_elements(self, css_selector):
self.wait_for_element_presence(
css_selector,
@@ -70,6 +79,50 @@ class SettingsPage(CoursePage):
'Entrance exam minimum score percent is invisible'
)
@property
def course_license(self):
"""
Property. Returns the text of the license type for the course
("All Rights Reserved" or "Creative Commons")
"""
license_types_css = "section.license ul.license-types li.license-type"
self.wait_for_element_presence(
license_types_css,
"license type buttons are present",
)
selected = self.q(css=license_types_css + " button.is-selected")
if selected.is_present():
return selected.text[0]
# Look for the license text that will be displayed by default,
# if no button is yet explicitly selected
license_text = self.q(css='section.license span.license-text')
if license_text.is_present():
return license_text.text[0]
return None
@course_license.setter
def course_license(self, license_name):
"""
Sets the course license to the given license_name
(str, "All Rights Reserved" or "Creative Commons")
"""
license_types_css = "section.license ul.license-types li.license-type"
self.wait_for_element_presence(
license_types_css,
"license type buttons are present",
)
button_xpath = (
"//section[contains(@class, 'license')]"
"//ul[contains(@class, 'license-types')]"
"//li[contains(@class, 'license-type')]"
"//button[contains(text(),'{license_name}')]"
).format(license_name=license_name)
button = self.q(xpath=button_xpath)
if not button.present:
raise Exception("Invalid license name: {name}".format(name=license_name))
button.click()
def save_changes(self, wait_for_confirmation=True):
"""
Clicks save button, waits for confirmation unless otherwise specified

View File

@@ -1,14 +1,19 @@
# coding: utf-8
"""
Acceptance tests for Studio's Setting pages
"""
from __future__ import unicode_literals
from nose.plugins.attrib import attr
from base_studio_test import StudioCourseTest
from bok_choy.promise import EmptyPromise
from ...fixtures.course import XBlockFixtureDesc
from ..helpers import create_user_partition_json
from ...pages.studio.overview import CourseOutlinePage
from ...pages.studio.settings import SettingsPage
from ...pages.studio.settings_advanced import AdvancedSettingsPage
from ...pages.studio.settings_group_configurations import GroupConfigurationsPage
from ...pages.lms.courseware import CoursewarePage
from unittest import skip
from textwrap import dedent
from xmodule.partitions.partitions import Group
@@ -397,3 +402,77 @@ class AdvancedSettingsValidationTest(StudioCourseTest):
expected_fields = self.advanced_settings.expected_settings_names
displayed_fields = self.advanced_settings.displayed_settings_names
self.assertEquals(set(displayed_fields), set(expected_fields))
@attr('shard_1')
class ContentLicenseTest(StudioCourseTest):
"""
Tests for course-level licensing (that is, setting the license,
for an entire course's content, to All Rights Reserved or Creative Commons)
"""
def setUp(self): # pylint: disable=arguments-differ
super(ContentLicenseTest, self).setUp()
self.outline_page = CourseOutlinePage(
self.browser,
self.course_info['org'],
self.course_info['number'],
self.course_info['run']
)
self.settings_page = SettingsPage(
self.browser,
self.course_info['org'],
self.course_info['number'],
self.course_info['run']
)
self.lms_courseware = CoursewarePage(
self.browser,
self.course_id,
)
self.settings_page.visit()
def test_empty_license(self):
"""
When I visit the Studio settings page,
I see that the course license is "All Rights Reserved" by default.
Then I visit the LMS courseware page,
and I see that the default course license is displayed.
"""
self.assertEqual(self.settings_page.course_license, "All Rights Reserved")
self.lms_courseware.visit()
self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved")
def test_arr_license(self):
"""
When I visit the Studio settings page,
and I set the course license to "All Rights Reserved",
and I refresh the page,
I see that the course license is "All Rights Reserved".
Then I visit the LMS courseware page,
and I see that the course license is "All Rights Reserved".
"""
self.settings_page.course_license = "All Rights Reserved"
self.settings_page.save_changes()
self.settings_page.refresh_and_wait_for_load()
self.assertEqual(self.settings_page.course_license, "All Rights Reserved")
self.lms_courseware.visit()
self.assertEqual(self.lms_courseware.course_license, "© All Rights Reserved")
def test_cc_license(self):
"""
When I visit the Studio settings page,
and I set the course license to "Creative Commons",
and I refresh the page,
I see that the course license is "Creative Commons".
Then I visit the LMS courseware page,
and I see that the course license is "Some Rights Reserved".
"""
self.settings_page.course_license = "Creative Commons"
self.settings_page.save_changes()
self.settings_page.refresh_and_wait_for_load()
self.assertEqual(self.settings_page.course_license, "Creative Commons")
self.lms_courseware.visit()
# The course_license text will include a bunch of screen reader text to explain
# the selected options
self.assertIn("Some Rights Reserved", self.lms_courseware.course_license)

View File

@@ -0,0 +1,116 @@
# coding: utf-8
"""
Acceptance tests for licensing of the Video module
"""
from __future__ import unicode_literals
from nose.plugins.attrib import attr
from ..studio.base_studio_test import StudioCourseTest
#from ..helpers import UniqueCourseTest
from ...pages.studio.overview import CourseOutlinePage
from ...pages.lms.courseware import CoursewarePage
from ...fixtures.course import XBlockFixtureDesc
@attr('shard_1')
class VideoLicenseTest(StudioCourseTest):
"""
Tests for video module-level licensing (that is, setting the license,
for a specific video module, to All Rights Reserved or Creative Commons)
"""
def setUp(self): # pylint: disable=arguments-differ
super(VideoLicenseTest, self).setUp()
self.lms_courseware = CoursewarePage(
self.browser,
self.course_id,
)
self.studio_course_outline = CourseOutlinePage(
self.browser,
self.course_info['org'],
self.course_info['number'],
self.course_info['run']
)
# used by StudioCourseTest.setUp()
def populate_course_fixture(self, course_fixture):
"""
Create a course with a single chapter.
That chapter has a single section.
That section has a single vertical.
That vertical has a single video element.
"""
video_block = XBlockFixtureDesc('video', "Test Video")
vertical = XBlockFixtureDesc('vertical', "Test Vertical")
vertical.add_children(video_block)
sequential = XBlockFixtureDesc('sequential', "Test Section")
sequential.add_children(vertical)
chapter = XBlockFixtureDesc('chapter', "Test Chapter")
chapter.add_children(sequential)
self.course_fixture.add_children(chapter)
def test_empty_license(self):
"""
When I visit the LMS courseware,
I can see that the video is present
but it has no license displayed by default.
"""
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
video_license = self.lms_courseware.q(css=".vert .xblock.xmodule_VideoModule .xblock-license")
self.assertFalse(video_license.is_present())
def test_arr_license(self):
"""
When I edit a video element in Studio,
I can set an "All Rights Reserved" license on that video element.
When I visit the LMS courseware,
I can see that the video is present
and that it has "All Rights Reserved" displayed for the license.
"""
self.studio_course_outline.visit()
subsection = self.studio_course_outline.section_at(0).subsection_at(0)
subsection.expand_subsection()
unit = subsection.unit_at(0)
container_page = unit.go_to()
container_page.edit()
video = [xb for xb in container_page.xblocks if xb.name == "Test Video"][0]
video.edit().open_advanced_tab()
video.set_license('all-rights-reserved')
video.save_settings()
container_page.publish_action.click()
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
video_license = self.lms_courseware.q(css=".vert .xblock.xmodule_VideoModule .xblock-license")
self.assertTrue(video_license.is_present())
self.assertEqual(video_license.text[0], "© All Rights Reserved")
def test_cc_license(self):
"""
When I edit a video element in Studio,
I can set a "Creative Commons" license on that video element.
When I visit the LMS courseware,
I can see that the video is present
and that it has "Some Rights Reserved" displayed for the license.
"""
self.studio_course_outline.visit()
subsection = self.studio_course_outline.section_at(0).subsection_at(0)
subsection.expand_subsection()
unit = subsection.unit_at(0)
container_page = unit.go_to()
container_page.edit()
video = [xb for xb in container_page.xblocks if xb.name == "Test Video"][0]
video.edit().open_advanced_tab()
video.set_license('creative-commons')
video.save_settings()
container_page.publish_action.click()
self.lms_courseware.visit()
video = self.lms_courseware.q(css=".vert .xblock .video")
self.assertTrue(video.is_present())
video_license = self.lms_courseware.q(css=".vert .xblock.xmodule_VideoModule .xblock-license")
self.assertTrue(video_license.is_present())
self.assertIn("Some Rights Reserved", video_license.text[0])

View File

@@ -1,4 +1,4 @@
<course course_image="just_a_test.jpg">
<course course_image="just_a_test.jpg" license="creative-commons: BY">
<textbook title="Textbook" book_url="https://s3.amazonaws.com/edx-textbooks/guttag_computation_v3/"/>
<chapter url_name="Overview">
<videosequence url_name="Toy_Videos">
@@ -10,7 +10,7 @@
<html url_name="badlink"/>
<html url_name="with_styling"/>
<html url_name="just_img"/>
<video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw" display_name="Video Resources"/>
<video url_name="Video_Resources" youtube_id_1_0="1bK-WdDi6Qw" display_name="Video Resources" license="all-rights-reserved"/>
</videosequence>
<video url_name="Welcome" youtube_id_1_0="p2Q6BrNhdh8" display_name="Welcome"/>
<video url_name="video_123456789012" youtube_id_1_0="p2Q6BrNhdh8" display_name='Test Video'/>