Merge pull request #2559 from edx/usman/lms2136-wiki-access
Refactor of permissions checking for wiki pages.
This commit is contained in:
@@ -1761,8 +1761,27 @@ class ContentStoreTest(ModuleStoreTestCase):
|
||||
self.assertEquals(course_module.pdf_textbooks[0]["chapters"][0]["url"], '/c4x/MITx/999/asset/Chapter1.pdf')
|
||||
self.assertEquals(course_module.pdf_textbooks[0]["chapters"][1]["url"], '/c4x/MITx/999/asset/Chapter2.pdf')
|
||||
|
||||
# check that URL slug got updated to new course slug
|
||||
self.assertEquals(course_module.wiki_slug, '999')
|
||||
def test_import_into_new_course_id_wiki_slug_renamespacing(self):
|
||||
module_store = modulestore('direct')
|
||||
target_location = Location('i4x', 'MITx', '999', 'course', '2013_Spring')
|
||||
course_data = {
|
||||
'org': target_location.org,
|
||||
'number': target_location.course,
|
||||
'display_name': 'Robot Super Course',
|
||||
'run': target_location.name
|
||||
}
|
||||
target_course_id = '{0}/{1}/{2}'.format(target_location.org, target_location.course, target_location.name)
|
||||
_create_course(self, course_data)
|
||||
|
||||
# Import a course with wiki_slug == location.course
|
||||
import_from_xml(module_store, 'common/test/data/', ['toy'], target_location_namespace=target_location)
|
||||
course_module = module_store.get_instance(target_location.course_id, target_location)
|
||||
self.assertEquals(course_module.wiki_slug, 'MITx.999.2013_Spring')
|
||||
|
||||
# Now try importing a course with wiki_slug == '{0}{1}{2}'.format(location.org, location.course, location.name)
|
||||
import_from_xml(module_store, 'common/test/data/', ['two_toys'], target_location_namespace=target_location)
|
||||
course_module = module_store.get_instance(target_course_id, target_location)
|
||||
self.assertEquals(course_module.wiki_slug, 'MITx.999.2013_Spring')
|
||||
|
||||
def test_import_metadata_with_attempts_empty_string(self):
|
||||
module_store = modulestore('direct')
|
||||
@@ -1915,6 +1934,14 @@ class ContentStoreTest(ModuleStoreTestCase):
|
||||
_test_no_locations(self, resp)
|
||||
return resp
|
||||
|
||||
def test_wiki_slug(self):
|
||||
"""When creating a course a unique wiki_slug should be set."""
|
||||
|
||||
course_location = Location(['i4x', 'MITx', '999', 'course', '2013_Spring'])
|
||||
_create_course(self, self.course_data)
|
||||
course_module = modulestore('direct').get_item(course_location)
|
||||
self.assertEquals(course_module.wiki_slug, 'MITx.999.2013_Spring')
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_MODULESTORE)
|
||||
class MetadataSaveTestCase(ModuleStoreTestCase):
|
||||
|
||||
@@ -376,8 +376,15 @@ def create_new_course(request):
|
||||
metadata = {}
|
||||
else:
|
||||
metadata = {'display_name': display_name}
|
||||
|
||||
# Set a unique wiki_slug for newly created courses. To maintain active wiki_slugs for existing xml courses this
|
||||
# cannot be changed in CourseDescriptor.
|
||||
wiki_slug = "{0}.{1}.{2}".format(dest_location.org, dest_location.course, dest_location.name)
|
||||
definition_data = {'wiki_slug': wiki_slug}
|
||||
|
||||
modulestore('direct').create_and_save_xmodule(
|
||||
dest_location,
|
||||
definition_data=definition_data,
|
||||
metadata=metadata
|
||||
)
|
||||
new_course = modulestore('direct').get_item(dest_location)
|
||||
|
||||
@@ -603,6 +603,11 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
|
||||
|
||||
xml_object.append(textbook_xml_object)
|
||||
|
||||
if self.wiki_slug is not None:
|
||||
wiki_xml_object = etree.Element('wiki')
|
||||
wiki_xml_object.set('slug', self.wiki_slug)
|
||||
xml_object.append(wiki_xml_object)
|
||||
|
||||
return xml_object
|
||||
|
||||
def has_ended(self):
|
||||
|
||||
@@ -417,6 +417,17 @@ class MixedModuleStore(ModuleStoreWriteBase):
|
||||
for course in store.get_courses():
|
||||
loc_mapper().translate_location(course.location.course_id, course.location)
|
||||
|
||||
def get_courses_for_wiki(self, wiki_slug):
|
||||
"""
|
||||
Return the list of courses which use this wiki_slug
|
||||
:param wiki_slug: the course wiki root slug
|
||||
:return: list of course locations
|
||||
"""
|
||||
courses = []
|
||||
for modulestore in self.modulestores.values():
|
||||
courses.extend(modulestore.get_courses_for_wiki(wiki_slug))
|
||||
return courses
|
||||
|
||||
|
||||
def _compare_stores(left, right):
|
||||
"""
|
||||
|
||||
@@ -878,6 +878,15 @@ class MongoModuleStore(ModuleStoreWriteBase):
|
||||
item_locs -= all_reachable
|
||||
return list(item_locs)
|
||||
|
||||
def get_courses_for_wiki(self, wiki_slug):
|
||||
"""
|
||||
Return the list of courses which use this wiki_slug
|
||||
:param wiki_slug: the course wiki root slug
|
||||
:return: list of course locations
|
||||
"""
|
||||
courses = self.collection.find({'definition.data.wiki_slug': wiki_slug})
|
||||
return [Location(course['_id']) for course in courses]
|
||||
|
||||
def _create_new_field_data(self, _category, _location, definition_data, metadata):
|
||||
"""
|
||||
To instantiate a new xmodule which will be saved latter, set up the dbModel and kvs
|
||||
|
||||
@@ -1645,3 +1645,14 @@ class SplitMongoModuleStore(ModuleStoreWriteBase):
|
||||
be a json dict key.
|
||||
"""
|
||||
structure['blocks'][LocMapperStore.encode_key_for_mongo(block_id)] = content
|
||||
|
||||
def get_courses_for_wiki(self, wiki_slug):
|
||||
"""
|
||||
Return the list of courses which use this wiki_slug
|
||||
:param wiki_slug: the course wiki root slug
|
||||
:return: list of course locations
|
||||
|
||||
Todo: Needs to be implemented.
|
||||
"""
|
||||
courses = []
|
||||
return courses
|
||||
@@ -368,6 +368,24 @@ class TestMixedModuleStore(LocMapperSetupSansDjango):
|
||||
orphans = self.store.get_orphans(self.course_locations[self.MONGO_COURSEID], None)
|
||||
self.assertEqual(len(orphans), 0, "unexpected orphans: {}".format(orphans))
|
||||
|
||||
@ddt.data('direct')
|
||||
def test_get_courses_for_wiki(self, default_ms):
|
||||
"""
|
||||
Test the get_courses_for_wiki method
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
course_locations = self.store.get_courses_for_wiki('toy')
|
||||
self.assertEqual(len(course_locations), 1)
|
||||
self.assertIn(Location('i4x', 'edX', 'toy', 'course', '2012_Fall'), course_locations)
|
||||
|
||||
course_locations = self.store.get_courses_for_wiki('simple')
|
||||
self.assertEqual(len(course_locations), 1)
|
||||
self.assertIn(Location('i4x', 'edX', 'simple', 'course', '2012_Fall'), course_locations)
|
||||
|
||||
self.assertEqual(len(self.store.get_courses_for_wiki('edX.simple.2012_Fall')), 0)
|
||||
self.assertEqual(len(self.store.get_courses_for_wiki('no_such_wiki')), 0)
|
||||
|
||||
|
||||
#=============================================================================================================
|
||||
# General utils for not using django settings
|
||||
#=============================================================================================================
|
||||
|
||||
@@ -37,6 +37,9 @@ RENDER_TEMPLATE = lambda t_n, d, ctx = None, nsp = 'main': ''
|
||||
|
||||
class TestMongoModuleStore(object):
|
||||
'''Tests!'''
|
||||
# Explicitly list the courses to load (don't want the big one)
|
||||
courses = ['toy', 'simple', 'simple_with_draft', 'test_unicode']
|
||||
|
||||
@classmethod
|
||||
def setupClass(cls):
|
||||
cls.connection = pymongo.MongoClient(
|
||||
@@ -74,9 +77,7 @@ class TestMongoModuleStore(object):
|
||||
# Also test draft store imports
|
||||
#
|
||||
draft_store = DraftModuleStore(doc_store_config, FS_ROOT, RENDER_TEMPLATE, default_class=DEFAULT_CLASS)
|
||||
# Explicitly list the courses to load (don't want the big one)
|
||||
courses = ['toy', 'simple', 'simple_with_draft', 'test_unicode']
|
||||
import_from_xml(store, DATA_DIR, courses, draft_store=draft_store, static_content_store=content_store)
|
||||
import_from_xml(store, DATA_DIR, TestMongoModuleStore.courses, draft_store=draft_store, static_content_store=content_store)
|
||||
|
||||
# also test a course with no importing of static content
|
||||
import_from_xml(
|
||||
@@ -273,6 +274,42 @@ class TestMongoModuleStore(object):
|
||||
{'displayname': 'hello'}
|
||||
)
|
||||
|
||||
def test_get_courses_for_wiki(self):
|
||||
"""
|
||||
Test the get_courses_for_wiki method
|
||||
"""
|
||||
for course_number in self.courses:
|
||||
course_locations = self.store.get_courses_for_wiki(course_number)
|
||||
assert_equals(len(course_locations), 1)
|
||||
assert_equals(Location('i4x', 'edX', course_number, 'course', '2012_Fall'), course_locations[0])
|
||||
|
||||
course_locations = self.store.get_courses_for_wiki('no_such_wiki')
|
||||
assert_equals(len(course_locations), 0)
|
||||
|
||||
# set toy course to share the wiki with simple course
|
||||
toy_course = self.store.get_course('edX/toy/2012_Fall')
|
||||
toy_course.wiki_slug = 'simple'
|
||||
self.store.update_item(toy_course)
|
||||
|
||||
# now toy_course should not be retrievable with old wiki_slug
|
||||
course_locations = self.store.get_courses_for_wiki('toy')
|
||||
assert_equals(len(course_locations), 0)
|
||||
|
||||
# but there should be two courses with wiki_slug 'simple'
|
||||
course_locations = self.store.get_courses_for_wiki('simple')
|
||||
assert_equals(len(course_locations), 2)
|
||||
for course_number in ['toy', 'simple']:
|
||||
assert_in(Location('i4x', 'edX', course_number, 'course', '2012_Fall'), course_locations)
|
||||
|
||||
# configure simple course to use unique wiki_slug.
|
||||
simple_course = self.store.get_course('edX/simple/2012_Fall')
|
||||
simple_course.wiki_slug = 'edX.simple.2012_Fall'
|
||||
self.store.update_item(simple_course)
|
||||
# it should be retrievable with its new wiki_slug
|
||||
course_locations = self.store.get_courses_for_wiki('edX.simple.2012_Fall')
|
||||
assert_equals(len(course_locations), 1)
|
||||
assert_in(Location('i4x', 'edX', 'simple', 'course', '2012_Fall'), course_locations)
|
||||
|
||||
|
||||
class TestMongoKeyValueStore(object):
|
||||
"""
|
||||
|
||||
@@ -7,8 +7,6 @@ import unittest
|
||||
from glob import glob
|
||||
from mock import patch
|
||||
|
||||
from nose.tools import assert_raises, assert_equals # pylint: disable=E0611
|
||||
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.xml import XMLModuleStore
|
||||
from xmodule.modulestore import Location, XML_MODULESTORE_TYPE
|
||||
@@ -43,7 +41,7 @@ class TestXMLModuleStore(unittest.TestCase):
|
||||
|
||||
def test_xml_modulestore_type(self):
|
||||
store = XMLModuleStore(DATA_DIR, course_dirs=['toy', 'simple'])
|
||||
assert_equals(store.get_modulestore_type('foo/bar/baz'), XML_MODULESTORE_TYPE)
|
||||
self.assertEqual(store.get_modulestore_type('foo/bar/baz'), XML_MODULESTORE_TYPE)
|
||||
|
||||
def test_unicode_chars_in_xml_content(self):
|
||||
# edX/full/6.002_Spring_2012 has non-ASCII chars, and during
|
||||
@@ -52,7 +50,7 @@ class TestXMLModuleStore(unittest.TestCase):
|
||||
# Ensure that there really is a non-ASCII character in the course.
|
||||
with open(os.path.join(DATA_DIR, "toy/sequential/vertical_sequential.xml")) as xmlf:
|
||||
xml = xmlf.read()
|
||||
with assert_raises(UnicodeDecodeError):
|
||||
with self.assertRaises(UnicodeDecodeError):
|
||||
xml.decode('ascii')
|
||||
|
||||
# Load the course, but don't make error modules. This will succeed,
|
||||
@@ -78,3 +76,28 @@ class TestXMLModuleStore(unittest.TestCase):
|
||||
about_module = course_module[about_location]
|
||||
self.assertIn("GREEN", about_module.data)
|
||||
self.assertNotIn("RED", about_module.data)
|
||||
|
||||
def test_get_courses_for_wiki(self):
|
||||
"""
|
||||
Test the get_courses_for_wiki method
|
||||
"""
|
||||
store = XMLModuleStore(DATA_DIR, course_dirs=['toy', 'simple'])
|
||||
for course in store.get_courses():
|
||||
course_locations = store.get_courses_for_wiki(course.wiki_slug)
|
||||
self.assertEqual(len(course_locations), 1)
|
||||
self.assertIn(Location('i4x', 'edX', course.location.course, 'course', '2012_Fall'), course_locations)
|
||||
|
||||
course_locations = store.get_courses_for_wiki('no_such_wiki')
|
||||
self.assertEqual(len(course_locations), 0)
|
||||
|
||||
# now set toy course to share the wiki with simple course
|
||||
toy_course = store.get_course('edX/toy/2012_Fall')
|
||||
toy_course.wiki_slug = 'simple'
|
||||
|
||||
course_locations = store.get_courses_for_wiki('toy')
|
||||
self.assertEqual(len(course_locations), 0)
|
||||
|
||||
course_locations = store.get_courses_for_wiki('simple')
|
||||
self.assertEqual(len(course_locations), 2)
|
||||
for course_number in ['toy', 'simple']:
|
||||
self.assertIn(Location('i4x', 'edX', course_number, 'course', '2012_Fall'), course_locations)
|
||||
|
||||
@@ -790,3 +790,12 @@ class XMLModuleStore(ModuleStoreReadBase):
|
||||
"split" for new-style split MongoDB backed courses.
|
||||
"""
|
||||
return XML_MODULESTORE_TYPE
|
||||
|
||||
def get_courses_for_wiki(self, wiki_slug):
|
||||
"""
|
||||
Return the list of courses which use this wiki_slug
|
||||
:param wiki_slug: the course wiki root slug
|
||||
:return: list of course locations
|
||||
"""
|
||||
courses = self.get_courses()
|
||||
return [course.location for course in courses if (course.wiki_slug == wiki_slug)]
|
||||
|
||||
@@ -514,11 +514,20 @@ def remap_namespace(module, target_location_namespace):
|
||||
chapter['url'], target_location_namespace
|
||||
)
|
||||
|
||||
# if there is a wiki_slug which is the same as the original location
|
||||
# (aka default value), then remap that so the wiki doesn't point to
|
||||
# the old Wiki.
|
||||
if module.wiki_slug == original_location.course:
|
||||
module.wiki_slug = target_location_namespace.course
|
||||
# Original wiki_slugs had value location.course. To make them unique this was changed to 'org.course.name'.
|
||||
# If the wiki_slug is equal to either of these default values then remap that so that the wiki does not point
|
||||
# to the old wiki.
|
||||
original_unique_wiki_slug = '{0}.{1}.{2}'.format(
|
||||
original_location.org,
|
||||
original_location.course,
|
||||
original_location.name
|
||||
)
|
||||
if module.wiki_slug == original_unique_wiki_slug or module.wiki_slug == original_location.course:
|
||||
module.wiki_slug = '{0}.{1}.{2}'.format(
|
||||
target_location_namespace.org,
|
||||
target_location_namespace.course,
|
||||
target_location_namespace.name,
|
||||
)
|
||||
|
||||
module.save()
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<course display_name="Toy Course" graceperiod="2 days 5 hours 59 minutes 59 seconds" start="2015-07-17T12:00">
|
||||
<chapter url_name="Overview"/>
|
||||
<wiki slug="edX.toy.TT_2012_Fall"/>
|
||||
</course>
|
||||
|
||||
@@ -4,6 +4,7 @@ Tests for wiki permissions
|
||||
|
||||
from django.contrib.auth.models import Group
|
||||
from student.tests.factories import UserFactory
|
||||
from xmodule.modulestore.django import loc_mapper
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
||||
|
||||
@@ -24,21 +25,37 @@ class TestWikiAccessBase(ModuleStoreTestCase):
|
||||
|
||||
self.wiki = get_or_create_root()
|
||||
|
||||
self.course_math101 = CourseFactory.create(org='org', number='math101', display_name='Course')
|
||||
self.course_math101_staff = [
|
||||
InstructorFactory(course=self.course_math101.location),
|
||||
StaffFactory(course=self.course_math101.location)
|
||||
]
|
||||
self.course_math101 = CourseFactory.create(org='org', number='math101', display_name='Course', metadata={'use_unique_wiki_id': 'false'})
|
||||
self.course_math101_staff = self.create_staff_for_course(self.course_math101)
|
||||
|
||||
wiki_math101 = self.create_urlpath(self.wiki, course_wiki_slug(self.course_math101))
|
||||
wiki_math101_page = self.create_urlpath(wiki_math101, 'Child')
|
||||
wiki_math101_page_page = self.create_urlpath(wiki_math101_page, 'Grandchild')
|
||||
self.wiki_math101_pages = [wiki_math101, wiki_math101_page, wiki_math101_page_page]
|
||||
|
||||
self.course_math101b = CourseFactory.create(org='org', number='math101b', display_name='Course', metadata={'use_unique_wiki_id': 'true'})
|
||||
self.course_math101b_staff = self.create_staff_for_course(self.course_math101b)
|
||||
|
||||
wiki_math101b = self.create_urlpath(self.wiki, course_wiki_slug(self.course_math101b))
|
||||
wiki_math101b_page = self.create_urlpath(wiki_math101b, 'Child')
|
||||
wiki_math101b_page_page = self.create_urlpath(wiki_math101b_page, 'Grandchild')
|
||||
self.wiki_math101b_pages = [wiki_math101b, wiki_math101b_page, wiki_math101b_page_page]
|
||||
|
||||
def create_urlpath(self, parent, slug):
|
||||
"""Creates an article at /parent/slug and returns its URLPath"""
|
||||
return URLPath.create_article(parent, slug, title=slug)
|
||||
|
||||
def create_staff_for_course(self, course):
|
||||
"""Creates and returns users with instructor and staff access to course."""
|
||||
|
||||
course_locator = loc_mapper().translate_location(course.id, course.location)
|
||||
return [
|
||||
InstructorFactory(course=course.location), # Creates instructor_org/number/run role name
|
||||
StaffFactory(course=course.location), # Creates staff_org/number/run role name
|
||||
InstructorFactory(course=course_locator), # Creates instructor_org.number.run role name
|
||||
StaffFactory(course=course_locator), # Creates staff_org.number.run role name
|
||||
]
|
||||
|
||||
|
||||
@override_settings(MODULESTORE=TEST_DATA_MIXED_MODULESTORE)
|
||||
class TestWikiAccess(TestWikiAccessBase):
|
||||
@@ -47,21 +64,15 @@ class TestWikiAccess(TestWikiAccessBase):
|
||||
super(TestWikiAccess, self).setUp()
|
||||
|
||||
self.course_310b = CourseFactory.create(org='org', number='310b', display_name='Course')
|
||||
self.course_310b_staff = [
|
||||
InstructorFactory(course=self.course_310b.location),
|
||||
StaffFactory(course=self.course_310b.location)
|
||||
]
|
||||
self.course_310b_ = CourseFactory.create(org='org', number='310b_', display_name='Course')
|
||||
self.course_310b__staff = [
|
||||
InstructorFactory(course=self.course_310b_.location),
|
||||
StaffFactory(course=self.course_310b_.location)
|
||||
]
|
||||
self.course_310b_staff = self.create_staff_for_course(self.course_310b)
|
||||
self.course_310b2 = CourseFactory.create(org='org', number='310b_', display_name='Course')
|
||||
self.course_310b2_staff = self.create_staff_for_course(self.course_310b2)
|
||||
|
||||
self.wiki_310b = self.create_urlpath(self.wiki, course_wiki_slug(self.course_310b))
|
||||
self.wiki_310b_ = self.create_urlpath(self.wiki, course_wiki_slug(self.course_310b_))
|
||||
self.wiki_310b2 = self.create_urlpath(self.wiki, course_wiki_slug(self.course_310b2))
|
||||
|
||||
def test_no_one_is_root_wiki_staff(self):
|
||||
all_course_staff = self.course_math101_staff + self.course_310b_staff + self.course_310b__staff
|
||||
all_course_staff = self.course_math101_staff + self.course_310b_staff + self.course_310b2_staff
|
||||
for course_staff in all_course_staff:
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, self.wiki.article))
|
||||
|
||||
@@ -70,6 +81,10 @@ class TestWikiAccess(TestWikiAccessBase):
|
||||
for course_staff in self.course_math101_staff:
|
||||
self.assertTrue(user_is_article_course_staff(course_staff, page.article))
|
||||
|
||||
for page in self.wiki_math101b_pages:
|
||||
for course_staff in self.course_math101b_staff:
|
||||
self.assertTrue(user_is_article_course_staff(course_staff, page.article))
|
||||
|
||||
def test_settings(self):
|
||||
for page in self.wiki_math101_pages:
|
||||
for course_staff in self.course_math101_staff:
|
||||
@@ -79,15 +94,27 @@ class TestWikiAccess(TestWikiAccessBase):
|
||||
self.assertTrue(settings.CAN_ASSIGN(page.article, course_staff))
|
||||
self.assertTrue(settings.CAN_ASSIGN_OWNER(page.article, course_staff))
|
||||
|
||||
for page in self.wiki_math101b_pages:
|
||||
for course_staff in self.course_math101b_staff:
|
||||
self.assertTrue(settings.CAN_DELETE(page.article, course_staff))
|
||||
self.assertTrue(settings.CAN_MODERATE(page.article, course_staff))
|
||||
self.assertTrue(settings.CAN_CHANGE_PERMISSIONS(page.article, course_staff))
|
||||
self.assertTrue(settings.CAN_ASSIGN(page.article, course_staff))
|
||||
self.assertTrue(settings.CAN_ASSIGN_OWNER(page.article, course_staff))
|
||||
|
||||
def test_other_course_staff_is_not_course_wiki_staff(self):
|
||||
for page in self.wiki_math101_pages:
|
||||
for course_staff in self.course_math101b_staff:
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, page.article))
|
||||
|
||||
for page in self.wiki_math101_pages:
|
||||
for course_staff in self.course_310b_staff:
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, page.article))
|
||||
|
||||
for course_staff in self.course_310b_staff:
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, self.wiki_310b_.article))
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, self.wiki_310b2.article))
|
||||
|
||||
for course_staff in self.course_310b__staff:
|
||||
for course_staff in self.course_310b2_staff:
|
||||
self.assertFalse(user_is_article_course_staff(course_staff, self.wiki_310b.article))
|
||||
|
||||
|
||||
@@ -114,10 +141,7 @@ class TestWikiAccessForNumericalCourseNumber(TestWikiAccessBase):
|
||||
super(TestWikiAccessForNumericalCourseNumber, self).setUp()
|
||||
|
||||
self.course_200 = CourseFactory.create(org='org', number='200', display_name='Course')
|
||||
self.course_200_staff = [
|
||||
InstructorFactory(course=self.course_200.location),
|
||||
StaffFactory(course=self.course_200.location)
|
||||
]
|
||||
self.course_200_staff = self.create_staff_for_course(self.course_200)
|
||||
|
||||
wiki_200 = self.create_urlpath(self.wiki, course_wiki_slug(self.course_200))
|
||||
wiki_200_page = self.create_urlpath(wiki_200, 'Child')
|
||||
@@ -138,10 +162,7 @@ class TestWikiAccessForOldFormatCourseStaffGroups(TestWikiAccessBase):
|
||||
|
||||
self.course_math101c = CourseFactory.create(org='org', number='math101c', display_name='Course')
|
||||
Group.objects.get_or_create(name='instructor_math101c')
|
||||
self.course_math101c_staff = [
|
||||
InstructorFactory(course=self.course_math101c.location),
|
||||
StaffFactory(course=self.course_math101c.location)
|
||||
]
|
||||
self.course_math101c_staff = self.create_staff_for_course(self.course_math101c)
|
||||
|
||||
wiki_math101c = self.create_urlpath(self.wiki, course_wiki_slug(self.course_math101c))
|
||||
wiki_math101c_page = self.create_urlpath(wiki_math101c, 'Child')
|
||||
|
||||
@@ -3,7 +3,8 @@ Utility functions for course_wiki.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from xmodule import modulestore
|
||||
import courseware
|
||||
|
||||
def user_is_article_course_staff(user, article):
|
||||
"""
|
||||
@@ -20,24 +21,24 @@ def user_is_article_course_staff(user, article):
|
||||
so this will return True.
|
||||
"""
|
||||
|
||||
course_slug = article_course_wiki_root_slug(article)
|
||||
wiki_slug = article_course_wiki_root_slug(article)
|
||||
|
||||
if course_slug is None:
|
||||
if wiki_slug is None:
|
||||
return False
|
||||
|
||||
user_groups = user.groups.all()
|
||||
|
||||
# The wiki expects article slugs to contain at least one non-digit so if
|
||||
# the course number is just a number the course wiki root slug is set to
|
||||
# be '<course_number>_'. This means slug '202_' can belong to either
|
||||
# course numbered '202_' or '202' and so we need to consider both.
|
||||
|
||||
if user_is_staff_on_course_number(user_groups, course_slug):
|
||||
courses = modulestore.django.modulestore().get_courses_for_wiki(wiki_slug)
|
||||
if any(courseware.access.has_access(user, course, 'staff', course.course_id) for course in courses):
|
||||
return True
|
||||
|
||||
if (course_slug.endswith('_') and slug_is_numerical(course_slug[:-1]) and
|
||||
user_is_staff_on_course_number(user_groups, course_slug[:-1])):
|
||||
return True
|
||||
if (wiki_slug.endswith('_') and slug_is_numerical(wiki_slug[:-1])):
|
||||
courses = modulestore.django.modulestore().get_courses_for_wiki(wiki_slug[:-1])
|
||||
if any(courseware.access.has_access(user, course, 'staff', course.course_id) for course in courses):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -64,28 +65,6 @@ def course_wiki_slug(course):
|
||||
return slug
|
||||
|
||||
|
||||
def user_is_staff_on_course_number(user_groups, course_number):
|
||||
"""Returns whether the groups contain a staff group for the course number"""
|
||||
|
||||
# Course groups have format 'instructor_<course_id>' and 'staff_<course_id>' where
|
||||
# course_id = org/course_number/run. So check if user's groups contain a group
|
||||
# whose name starts with 'instructor_' or 'staff_' and contains '/course_number/'.
|
||||
course_number_fragment = '/{0}/'.format(course_number)
|
||||
if [group for group in user_groups if (group.name.startswith(('instructor_', 'staff_')) and
|
||||
course_number_fragment in group.name)]:
|
||||
return True
|
||||
|
||||
# Old course groups had format 'instructor_<course_number>' and 'staff_<course_number>'
|
||||
# Check if user's groups contain either of these.
|
||||
old_instructor_group_name = 'instructor_{0}'.format(course_number)
|
||||
old_staff_group_name = 'staff_{0}'.format(course_number)
|
||||
if [group for group in user_groups if (group.name == old_instructor_group_name or
|
||||
group.name == old_staff_group_name)]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def article_course_wiki_root_slug(article):
|
||||
"""
|
||||
We assume the second level ancestor is the course wiki root. Examples:
|
||||
|
||||
Reference in New Issue
Block a user