The motivation for this change is performance. The forums UI code gets the list of users for each role and renders the staff label based on those lists. The list for the staff role is expensive to compute because there is no index on the is_staff attribute, and we cannot create one because the User model is built into django. Users with is_staff=True are still assigned the Moderator role upon enrolling in a course, so this change will have no practical effect except that a user who is granted staff privileges after enrolling in a course will have to be made a Moderator in order for their posts to be labeled. Additionally, the UI did not use the list of users with the Student role, so that list has been removed as well.
492 lines
20 KiB
Python
492 lines
20 KiB
Python
from datetime import datetime
|
|
from django.core.urlresolvers import reverse
|
|
from django.test import TestCase
|
|
from django.test.utils import override_settings
|
|
from student.tests.factories import UserFactory, CourseEnrollmentFactory
|
|
from django_comment_common.models import Role, Permission
|
|
from factories import RoleFactory
|
|
import django_comment_client.utils as utils
|
|
from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory
|
|
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
|
|
from courseware.tests.tests import TEST_DATA_MONGO_MODULESTORE
|
|
|
|
class DictionaryTestCase(TestCase):
|
|
def test_extract(self):
|
|
d = {'cats': 'meow', 'dogs': 'woof'}
|
|
k = ['cats', 'dogs', 'hamsters']
|
|
expected = {'cats': 'meow', 'dogs': 'woof', 'hamsters': None}
|
|
self.assertEqual(utils.extract(d, k), expected)
|
|
|
|
def test_strip_none(self):
|
|
d = {'cats': 'meow', 'dogs': 'woof', 'hamsters': None}
|
|
expected = {'cats': 'meow', 'dogs': 'woof'}
|
|
self.assertEqual(utils.strip_none(d), expected)
|
|
|
|
def test_strip_blank(self):
|
|
d = {'cats': 'meow', 'dogs': 'woof', 'hamsters': ' ', 'yetis': ''}
|
|
expected = {'cats': 'meow', 'dogs': 'woof'}
|
|
self.assertEqual(utils.strip_blank(d), expected)
|
|
|
|
def test_merge_dict(self):
|
|
d1 = {'cats': 'meow', 'dogs': 'woof'}
|
|
d2 = {'lions': 'roar', 'ducks': 'quack'}
|
|
expected = {'cats': 'meow', 'dogs': 'woof', 'lions': 'roar', 'ducks': 'quack'}
|
|
self.assertEqual(utils.merge_dict(d1, d2), expected)
|
|
|
|
|
|
class AccessUtilsTestCase(TestCase):
|
|
def setUp(self):
|
|
self.course_id = 'edX/toy/2012_Fall'
|
|
self.student_role = RoleFactory(name='Student', course_id=self.course_id)
|
|
self.moderator_role = RoleFactory(name='Moderator', course_id=self.course_id)
|
|
self.community_ta_role = RoleFactory(name='Community TA', course_id=self.course_id)
|
|
self.student1 = UserFactory(username='student', email='student@edx.org')
|
|
self.student1_enrollment = CourseEnrollmentFactory(user=self.student1)
|
|
self.student_role.users.add(self.student1)
|
|
self.student2 = UserFactory(username='student2', email='student2@edx.org')
|
|
self.student2_enrollment = CourseEnrollmentFactory(user=self.student2)
|
|
self.moderator = UserFactory(username='moderator', email='staff@edx.org', is_staff=True)
|
|
self.moderator_enrollment = CourseEnrollmentFactory(user=self.moderator)
|
|
self.moderator_role.users.add(self.moderator)
|
|
self.community_ta1 = UserFactory(username='community_ta1', email='community_ta1@edx.org')
|
|
self.community_ta_role.users.add(self.community_ta1)
|
|
self.community_ta2 = UserFactory(username='community_ta2', email='community_ta2@edx.org')
|
|
self.community_ta_role.users.add(self.community_ta2)
|
|
|
|
def test_get_role_ids(self):
|
|
ret = utils.get_role_ids(self.course_id)
|
|
expected = {u'Moderator': [3], u'Community TA': [4, 5]}
|
|
self.assertEqual(ret, expected)
|
|
|
|
def test_has_forum_access(self):
|
|
ret = utils.has_forum_access('student', self.course_id, 'Student')
|
|
self.assertTrue(ret)
|
|
|
|
ret = utils.has_forum_access('not_a_student', self.course_id, 'Student')
|
|
self.assertFalse(ret)
|
|
|
|
ret = utils.has_forum_access('student', self.course_id, 'NotARole')
|
|
self.assertFalse(ret)
|
|
|
|
|
|
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
|
class CoursewareContextTestCase(ModuleStoreTestCase):
|
|
def setUp(self):
|
|
self.course = CourseFactory.create(org="TestX", number="101", display_name="Test Course")
|
|
self.discussion1 = ItemFactory.create(
|
|
parent_location=self.course.location,
|
|
category="discussion",
|
|
discussion_id="discussion1",
|
|
discussion_category="Chapter",
|
|
discussion_target="Discussion 1"
|
|
)
|
|
self.discussion2 = ItemFactory.create(
|
|
parent_location=self.course.location,
|
|
category="discussion",
|
|
discussion_id="discussion2",
|
|
discussion_category="Chapter / Section / Subsection",
|
|
discussion_target="Discussion 2"
|
|
)
|
|
|
|
def test_empty(self):
|
|
utils.add_courseware_context([], self.course)
|
|
|
|
def test_missing_commentable_id(self):
|
|
orig = {"commentable_id": "non-inline"}
|
|
modified = dict(orig)
|
|
utils.add_courseware_context([modified], self.course)
|
|
self.assertEqual(modified, orig)
|
|
|
|
def test_basic(self):
|
|
threads = [
|
|
{"commentable_id": self.discussion1.discussion_id},
|
|
{"commentable_id": self.discussion2.discussion_id}
|
|
]
|
|
utils.add_courseware_context(threads, self.course)
|
|
|
|
def assertThreadCorrect(thread, discussion, expected_title): #pylint: disable=C0103
|
|
self.assertEqual(
|
|
set(thread.keys()),
|
|
set(["commentable_id", "courseware_url", "courseware_title"])
|
|
)
|
|
self.assertEqual(
|
|
thread.get("courseware_url"),
|
|
reverse(
|
|
"jump_to",
|
|
kwargs={
|
|
"course_id": self.course.location.course_id,
|
|
"location": discussion.location
|
|
}
|
|
)
|
|
)
|
|
self.assertEqual(thread.get("courseware_title"), expected_title)
|
|
|
|
assertThreadCorrect(threads[0], self.discussion1, "Chapter / Discussion 1")
|
|
assertThreadCorrect(threads[1], self.discussion2, "Subsection / Discussion 2")
|
|
|
|
|
|
@override_settings(MODULESTORE=TEST_DATA_MONGO_MODULESTORE)
|
|
class CategoryMapTestCase(ModuleStoreTestCase):
|
|
def setUp(self):
|
|
self.course = CourseFactory.create(org="TestX", number="101", display_name="Test Course")
|
|
# Courses get a default discussion topic on creation, so remove it
|
|
self.course.discussion_topics = {}
|
|
self.course.save()
|
|
self.discussion_num = 0
|
|
self.maxDiff = None #pylint: disable=C0103
|
|
|
|
def create_discussion(self, discussion_category, discussion_target, **kwargs):
|
|
self.discussion_num += 1
|
|
ItemFactory.create(
|
|
parent_location=self.course.location,
|
|
category="discussion",
|
|
discussion_id="discussion{}".format(self.discussion_num),
|
|
discussion_category=discussion_category,
|
|
discussion_target=discussion_target,
|
|
**kwargs
|
|
)
|
|
|
|
def assertCategoryMapEquals(self, expected):
|
|
self.assertEqual(
|
|
utils.get_discussion_category_map(self.course),
|
|
expected
|
|
)
|
|
|
|
def test_empty(self):
|
|
self.assertEqual(
|
|
utils.get_discussion_category_map(self.course),
|
|
{"entries": {}, "subcategories": {}, "children": []}
|
|
)
|
|
|
|
def test_configured_topics(self):
|
|
self.course.discussion_topics = {
|
|
"Topic A": {"id": "Topic_A"},
|
|
"Topic B": {"id": "Topic_B"},
|
|
"Topic C": {"id": "Topic_C"}
|
|
}
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {
|
|
"Topic A": {"id": "Topic_A", "sort_key": "Topic A"},
|
|
"Topic B": {"id": "Topic_B", "sort_key": "Topic B"},
|
|
"Topic C": {"id": "Topic_C", "sort_key": "Topic C"},
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Topic A", "Topic B", "Topic C"]
|
|
}
|
|
)
|
|
|
|
def test_single_inline(self):
|
|
self.create_discussion("Chapter", "Discussion")
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion1",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
}
|
|
},
|
|
"children": ["Chapter"]
|
|
}
|
|
)
|
|
|
|
def test_tree(self):
|
|
self.create_discussion("Chapter 1", "Discussion 1")
|
|
self.create_discussion("Chapter 1", "Discussion 2")
|
|
self.create_discussion("Chapter 2", "Discussion")
|
|
self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion")
|
|
self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion")
|
|
self.create_discussion("Chapter 3 / Section 1", "Discussion")
|
|
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter 1": {
|
|
"entries": {
|
|
"Discussion 1": {
|
|
"id": "discussion1",
|
|
"sort_key": None
|
|
},
|
|
"Discussion 2": {
|
|
"id": "discussion2",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion 1", "Discussion 2"]
|
|
},
|
|
"Chapter 2": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion3",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {
|
|
"Section 1": {
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Subsection 1": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion4",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
},
|
|
"Subsection 2": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion5",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
}
|
|
},
|
|
"children": ["Subsection 1", "Subsection 2"]
|
|
}
|
|
},
|
|
"children": ["Discussion", "Section 1"]
|
|
},
|
|
"Chapter 3": {
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Section 1": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion6",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
}
|
|
},
|
|
"children": ["Section 1"]
|
|
}
|
|
},
|
|
"children": ["Chapter 1", "Chapter 2", "Chapter 3"]
|
|
}
|
|
)
|
|
|
|
def test_start_date_filter(self):
|
|
now = datetime.now()
|
|
later = datetime.max
|
|
self.create_discussion("Chapter 1", "Discussion 1", start=now)
|
|
self.create_discussion("Chapter 1", "Discussion 2", start=later)
|
|
self.create_discussion("Chapter 2", "Discussion", start=now)
|
|
self.create_discussion("Chapter 2 / Section 1 / Subsection 1", "Discussion", start=later)
|
|
self.create_discussion("Chapter 2 / Section 1 / Subsection 2", "Discussion", start=later)
|
|
self.create_discussion("Chapter 3 / Section 1", "Discussion", start=later)
|
|
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter 1": {
|
|
"entries": {
|
|
"Discussion 1": {
|
|
"id": "discussion1",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion 1"]
|
|
},
|
|
"Chapter 2": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion3",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
}
|
|
},
|
|
"children": ["Chapter 1", "Chapter 2"]
|
|
}
|
|
)
|
|
|
|
def test_sort_inline_explicit(self):
|
|
self.create_discussion("Chapter", "Discussion 1", sort_key="D")
|
|
self.create_discussion("Chapter", "Discussion 2", sort_key="A")
|
|
self.create_discussion("Chapter", "Discussion 3", sort_key="E")
|
|
self.create_discussion("Chapter", "Discussion 4", sort_key="C")
|
|
self.create_discussion("Chapter", "Discussion 5", sort_key="B")
|
|
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter": {
|
|
"entries": {
|
|
"Discussion 1": {
|
|
"id": "discussion1",
|
|
"sort_key": "D"
|
|
},
|
|
"Discussion 2": {
|
|
"id": "discussion2",
|
|
"sort_key": "A"
|
|
},
|
|
"Discussion 3": {
|
|
"id": "discussion3",
|
|
"sort_key": "E"
|
|
},
|
|
"Discussion 4": {
|
|
"id": "discussion4",
|
|
"sort_key": "C"
|
|
},
|
|
"Discussion 5": {
|
|
"id": "discussion5",
|
|
"sort_key": "B"
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": [
|
|
"Discussion 2",
|
|
"Discussion 5",
|
|
"Discussion 4",
|
|
"Discussion 1",
|
|
"Discussion 3"
|
|
]
|
|
}
|
|
},
|
|
"children": ["Chapter"]
|
|
}
|
|
)
|
|
|
|
def test_sort_configured_topics_explicit(self):
|
|
self.course.discussion_topics = {
|
|
"Topic A": {"id": "Topic_A", "sort_key": "B"},
|
|
"Topic B": {"id": "Topic_B", "sort_key": "C"},
|
|
"Topic C": {"id": "Topic_C", "sort_key": "A"}
|
|
}
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {
|
|
"Topic A": {"id": "Topic_A", "sort_key": "B"},
|
|
"Topic B": {"id": "Topic_B", "sort_key": "C"},
|
|
"Topic C": {"id": "Topic_C", "sort_key": "A"},
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Topic C", "Topic A", "Topic B"]
|
|
}
|
|
)
|
|
|
|
def test_sort_alpha(self):
|
|
self.course.discussion_sort_alpha = True
|
|
self.course.save()
|
|
self.create_discussion("Chapter", "Discussion D")
|
|
self.create_discussion("Chapter", "Discussion A")
|
|
self.create_discussion("Chapter", "Discussion E")
|
|
self.create_discussion("Chapter", "Discussion C")
|
|
self.create_discussion("Chapter", "Discussion B")
|
|
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter": {
|
|
"entries": {
|
|
"Discussion D": {
|
|
"id": "discussion1",
|
|
"sort_key": "Discussion D"
|
|
},
|
|
"Discussion A": {
|
|
"id": "discussion2",
|
|
"sort_key": "Discussion A"
|
|
},
|
|
"Discussion E": {
|
|
"id": "discussion3",
|
|
"sort_key": "Discussion E"
|
|
},
|
|
"Discussion C": {
|
|
"id": "discussion4",
|
|
"sort_key": "Discussion C"
|
|
},
|
|
"Discussion B": {
|
|
"id": "discussion5",
|
|
"sort_key": "Discussion B"
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": [
|
|
"Discussion A",
|
|
"Discussion B",
|
|
"Discussion C",
|
|
"Discussion D",
|
|
"Discussion E"
|
|
]
|
|
}
|
|
},
|
|
"children": ["Chapter"]
|
|
}
|
|
)
|
|
|
|
def test_sort_intermediates(self):
|
|
self.create_discussion("Chapter B", "Discussion 2")
|
|
self.create_discussion("Chapter C", "Discussion")
|
|
self.create_discussion("Chapter A", "Discussion 1")
|
|
self.create_discussion("Chapter B", "Discussion 1")
|
|
self.create_discussion("Chapter A", "Discussion 2")
|
|
|
|
self.assertCategoryMapEquals(
|
|
{
|
|
"entries": {},
|
|
"subcategories": {
|
|
"Chapter A": {
|
|
"entries": {
|
|
"Discussion 1": {
|
|
"id": "discussion3",
|
|
"sort_key": None
|
|
},
|
|
"Discussion 2": {
|
|
"id": "discussion5",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion 1", "Discussion 2"]
|
|
},
|
|
"Chapter B": {
|
|
"entries": {
|
|
"Discussion 1": {
|
|
"id": "discussion4",
|
|
"sort_key": None
|
|
},
|
|
"Discussion 2": {
|
|
"id": "discussion1",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion 1", "Discussion 2"]
|
|
},
|
|
"Chapter C": {
|
|
"entries": {
|
|
"Discussion": {
|
|
"id": "discussion2",
|
|
"sort_key": None
|
|
}
|
|
},
|
|
"subcategories": {},
|
|
"children": ["Discussion"]
|
|
}
|
|
},
|
|
"children": ["Chapter A", "Chapter B", "Chapter C"]
|
|
}
|
|
)
|