Skip to content

Commit

Permalink
Merge pull request #11606 from edx/rc/2016-02-23
Browse files Browse the repository at this point in the history
Release Candidate rc/2016-02-23
  • Loading branch information
mikekatz committed Feb 24, 2016
2 parents 5f0d969 + 67b128d commit 44c27bb
Show file tree
Hide file tree
Showing 170 changed files with 3,275 additions and 1,580 deletions.
29 changes: 28 additions & 1 deletion cms/djangoapps/contentstore/tests/test_course_listing.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import ddt

from django.test import RequestFactory
from django.test.client import Client

from common.test.utils import XssTestMixin
from xmodule.course_module import CourseSummary

from contentstore.views.course import (_accessible_courses_list, _accessible_courses_list_from_groups,
Expand All @@ -30,7 +33,7 @@


@ddt.ddt
class TestCourseListing(ModuleStoreTestCase):
class TestCourseListing(ModuleStoreTestCase, XssTestMixin):
"""
Unit tests for getting the list of courses for a logged in user
"""
Expand Down Expand Up @@ -72,6 +75,30 @@ def tearDown(self):
self.client.logout()
ModuleStoreTestCase.tearDown(self)

def test_course_listing_is_escaped(self):
"""
Tests course listing returns escaped data.
"""
escaping_content = "<script>alert('ESCAPE')</script>"

# Make user staff to access course listing
self.user.is_staff = True
self.user.save() # pylint: disable=no-member

self.client = Client()
self.client.login(username=self.user.username, password='test')

# Change 'display_coursenumber' field and update the course.
course = CourseFactory.create()
course.display_coursenumber = escaping_content
course = self.store.update_item(course, self.user.id) # pylint: disable=no-member
self.assertEqual(course.display_coursenumber, escaping_content)

# Check if response is escaped
response = self.client.get('/home')
self.assertEqual(response.status_code, 200)
self.assert_no_xss(response, escaping_content)

def test_get_course_list(self):
"""
Test getting courses with new access group format e.g. 'instructor_edx.course.run'
Expand Down
41 changes: 20 additions & 21 deletions cms/djangoapps/contentstore/tests/test_courseware_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import SignalHandler, modulestore
from xmodule.modulestore.edit_info import EditInfoMixin
from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.inheritance import InheritanceMixin
from xmodule.modulestore.mixed import MixedModuleStore
from xmodule.modulestore.tests.django_utils import (
ModuleStoreTestCase,
TEST_DATA_MONGO_MODULESTORE,
TEST_DATA_SPLIT_MODULESTORE
)
TEST_DATA_SPLIT_MODULESTORE,
SharedModuleStoreTestCase)
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, LibraryFactory
from xmodule.modulestore.tests.mongo_connection import MONGO_PORT_NUM, MONGO_HOST
from xmodule.modulestore.tests.utils import (
Expand Down Expand Up @@ -692,60 +690,61 @@ def test_large_course_deletion(self, store_type):
self._perform_test_using_store(store_type, self._test_large_course_deletion)


class TestTaskExecution(ModuleStoreTestCase):
class TestTaskExecution(SharedModuleStoreTestCase):
"""
Set of tests to ensure that the task code will do the right thing when
executed directly. The test course and library gets created without the listeners
being present, which allows us to ensure that when the listener is
executed, it is done as expected.
"""

def setUp(self):
super(TestTaskExecution, self).setUp()
@classmethod
def setUpClass(cls):
super(TestTaskExecution, cls).setUpClass()
SignalHandler.course_published.disconnect(listen_for_course_publish)
SignalHandler.library_updated.disconnect(listen_for_library_update)
self.course = CourseFactory.create(start=datetime(2015, 3, 1, tzinfo=UTC))
cls.course = CourseFactory.create(start=datetime(2015, 3, 1, tzinfo=UTC))

self.chapter = ItemFactory.create(
parent_location=self.course.location,
cls.chapter = ItemFactory.create(
parent_location=cls.course.location,
category='chapter',
display_name="Week 1",
publish_item=True,
start=datetime(2015, 3, 1, tzinfo=UTC),
)
self.sequential = ItemFactory.create(
parent_location=self.chapter.location,
cls.sequential = ItemFactory.create(
parent_location=cls.chapter.location,
category='sequential',
display_name="Lesson 1",
publish_item=True,
start=datetime(2015, 3, 1, tzinfo=UTC),
)
self.vertical = ItemFactory.create(
parent_location=self.sequential.location,
cls.vertical = ItemFactory.create(
parent_location=cls.sequential.location,
category='vertical',
display_name='Subsection 1',
publish_item=True,
start=datetime(2015, 4, 1, tzinfo=UTC),
)
# unspecified start - should inherit from container
self.html_unit = ItemFactory.create(
parent_location=self.vertical.location,
cls.html_unit = ItemFactory.create(
parent_location=cls.vertical.location,
category="html",
display_name="Html Content",
publish_item=False,
)

self.library = LibraryFactory.create()
cls.library = LibraryFactory.create()

self.library_block1 = ItemFactory.create(
parent_location=self.library.location,
cls.library_block1 = ItemFactory.create(
parent_location=cls.library.location,
category="html",
display_name="Html Content",
publish_item=False,
)

self.library_block2 = ItemFactory.create(
parent_location=self.library.location,
cls.library_block2 = ItemFactory.create(
parent_location=cls.library.location,
category="html",
display_name="Html Content 2",
publish_item=False,
Expand Down
45 changes: 24 additions & 21 deletions cms/djangoapps/contentstore/tests/test_transcripts_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from xmodule.modulestore.tests.factories import CourseFactory
from xmodule.contentstore.content import StaticContent
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
from xmodule.exceptions import NotFoundError
from xmodule.contentstore.django import contentstore
from xmodule.video_module import transcripts_utils
Expand Down Expand Up @@ -77,7 +77,7 @@ def test_generate_subs_decrease_speed_2(self):


@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE)
class TestSaveSubsToStore(ModuleStoreTestCase):
class TestSaveSubsToStore(SharedModuleStoreTestCase):
"""Tests for `save_subs_to_store` function."""

org = 'MITx'
Expand All @@ -92,13 +92,13 @@ def clear_subs_content(self):
except NotFoundError:
pass

def setUp(self):

super(TestSaveSubsToStore, self).setUp()
self.course = CourseFactory.create(
org=self.org, number=self.number, display_name=self.display_name)
@classmethod
def setUpClass(cls):
super(TestSaveSubsToStore, cls).setUpClass()
cls.course = CourseFactory.create(
org=cls.org, number=cls.number, display_name=cls.display_name)

self.subs = {
cls.subs = {
'start': [100, 200, 240, 390, 1000],
'end': [200, 240, 380, 1000, 1500],
'text': [
Expand All @@ -110,18 +110,20 @@ def setUp(self):
]
}

self.subs_id = str(uuid4())
filename = 'subs_{0}.srt.sjson'.format(self.subs_id)
self.content_location = StaticContent.compute_location(self.course.id, filename)
self.addCleanup(self.clear_subs_content)
cls.subs_id = str(uuid4())
filename = 'subs_{0}.srt.sjson'.format(cls.subs_id)
cls.content_location = StaticContent.compute_location(cls.course.id, filename)

# incorrect subs
self.unjsonable_subs = set([1]) # set can't be serialized
cls.unjsonable_subs = {1} # set can't be serialized

self.unjsonable_subs_id = str(uuid4())
filename_unjsonable = 'subs_{0}.srt.sjson'.format(self.unjsonable_subs_id)
self.content_location_unjsonable = StaticContent.compute_location(self.course.id, filename_unjsonable)
cls.unjsonable_subs_id = str(uuid4())
filename_unjsonable = 'subs_{0}.srt.sjson'.format(cls.unjsonable_subs_id)
cls.content_location_unjsonable = StaticContent.compute_location(cls.course.id, filename_unjsonable)

def setUp(self):
super(TestSaveSubsToStore, self).setUp()
self.addCleanup(self.clear_subs_content)
self.clear_subs_content()

def test_save_subs_to_store(self):
Expand Down Expand Up @@ -154,7 +156,7 @@ def test_save_unjsonable_subs_to_store(self):


@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE)
class TestDownloadYoutubeSubs(ModuleStoreTestCase):
class TestDownloadYoutubeSubs(SharedModuleStoreTestCase):
"""Tests for `download_youtube_subs` function."""

org = 'MITx'
Expand Down Expand Up @@ -182,10 +184,11 @@ def clear_subs_content(self, youtube_subs):
for subs_id in youtube_subs.values():
self.clear_sub_content(subs_id)

def setUp(self):
super(TestDownloadYoutubeSubs, self).setUp()
self.course = CourseFactory.create(
org=self.org, number=self.number, display_name=self.display_name)
@classmethod
def setUpClass(cls):
super(TestDownloadYoutubeSubs, cls).setUpClass()
cls.course = CourseFactory.create(
org=cls.org, number=cls.number, display_name=cls.display_name)

def test_success_downloading_subs(self):

Expand Down
31 changes: 16 additions & 15 deletions cms/djangoapps/contentstore/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.test.utils import override_settings
from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase, SharedModuleStoreTestCase
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from xmodule.modulestore.django import modulestore
from xmodule.partitions.partitions import UserPartition, Group
Expand Down Expand Up @@ -110,16 +110,17 @@ def get_course_with_tabs(self, tabs=None):
return course


class XBlockVisibilityTestCase(ModuleStoreTestCase):
class XBlockVisibilityTestCase(SharedModuleStoreTestCase):
"""Tests for xblock visibility for students."""

def setUp(self):
super(XBlockVisibilityTestCase, self).setUp()
@classmethod
def setUpClass(cls):
super(XBlockVisibilityTestCase, cls).setUpClass()

self.dummy_user = ModuleStoreEnum.UserID.test
self.past = datetime(1970, 1, 1, tzinfo=UTC)
self.future = datetime.now(UTC) + timedelta(days=1)
self.course = CourseFactory.create()
cls.dummy_user = ModuleStoreEnum.UserID.test
cls.past = datetime(1970, 1, 1, tzinfo=UTC)
cls.future = datetime.now(UTC) + timedelta(days=1)
cls.course = CourseFactory.create()

def test_private_unreleased_xblock(self):
"""Verifies that a private unreleased xblock is not visible"""
Expand Down Expand Up @@ -484,31 +485,31 @@ def test_retrieves_partition_info_with_selected_groups(self):
expected = [
{
"id": 0,
"name": "Cohort user partition",
"scheme": "cohort",
"name": u"Cohort user partition",
"scheme": u"cohort",
"groups": [
{
"id": 0,
"name": "Group A",
"name": u"Group A",
"selected": False,
"deleted": False,
},
{
"id": 1,
"name": "Group B",
"name": u"Group B",
"selected": False,
"deleted": False,
},
]
},
{
"id": 1,
"name": "Random user partition",
"scheme": "random",
"name": u"Random user partition",
"scheme": u"random",
"groups": [
{
"id": 0,
"name": "Group C",
"name": u"Group C",
"selected": False,
"deleted": False,
},
Expand Down
9 changes: 9 additions & 0 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from django_comment_common.models import assign_default_role
from django_comment_common.utils import seed_permissions_roles

from openedx.core.djangoapps.self_paced.models import SelfPacedConfiguration

from xmodule.modulestore import ModuleStoreEnum
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
Expand Down Expand Up @@ -455,3 +457,10 @@ def get_visibility_partition_info(xblock):
"has_selected_groups": has_selected_groups,
"selected_verified_partition_id": selected_verified_partition_id,
}


def is_self_paced(course):
"""
Returns True if course is self-paced, False otherwise.
"""
return course and course.self_paced and SelfPacedConfiguration.current().enabled
14 changes: 9 additions & 5 deletions cms/djangoapps/contentstore/views/item.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
from contentstore.views.helpers import is_unit, xblock_studio_url, xblock_primary_child_category, \
xblock_type_display_name, get_parent_xblock, create_xblock, usage_key_with_run
from contentstore.views.preview import get_preview_fragment
from contentstore.utils import is_self_paced

from openedx.core.lib.gating import api as gating_api
from edxmako.shortcuts import render_to_string
from models.settings.course_grading import CourseGradingModel
Expand Down Expand Up @@ -855,7 +857,9 @@ def create_xblock_info(xblock, data=None, metadata=None, include_ancestor_info=F
release_date = _get_release_date(xblock, user)

if xblock.category != 'course':
visibility_state = _compute_visibility_state(xblock, child_info, is_xblock_unit and has_changes)
visibility_state = _compute_visibility_state(
xblock, child_info, is_xblock_unit and has_changes, is_self_paced(course)
)
else:
visibility_state = None
published = modulestore().has_published_version(xblock) if not is_library_block else None
Expand Down Expand Up @@ -1017,7 +1021,7 @@ class VisibilityState(object):
gated = 'gated'


def _compute_visibility_state(xblock, child_info, is_unit_with_changes):
def _compute_visibility_state(xblock, child_info, is_unit_with_changes, is_course_self_paced=False):
"""
Returns the current publish state for the specified xblock and its children
"""
Expand All @@ -1027,10 +1031,10 @@ def _compute_visibility_state(xblock, child_info, is_unit_with_changes):
# Note that a unit that has never been published will fall into this category,
# as well as previously published units with draft content.
return VisibilityState.needs_attention

is_unscheduled = xblock.start == DEFAULT_START_DATE
is_live = datetime.now(UTC) > xblock.start
children = child_info and child_info.get('children', [])
if children and len(children) > 0:
is_live = is_course_self_paced or datetime.now(UTC) > xblock.start
if child_info and child_info.get('children', []):
all_staff_only = True
all_unscheduled = True
all_live = True
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#-*- coding: utf-8 -*-

"""
Group Configuration Tests.
Certificates Tests.
"""
import json
import mock
Expand Down
Loading

0 comments on commit 44c27bb

Please sign in to comment.