Commit 020094b8 by cahrens

Create auto cohorts when list_cohorts is called and return number of users per cohort.

TNL-186
parent 3a0dea20
...@@ -160,19 +160,30 @@ def get_cohort(user, course_key): ...@@ -160,19 +160,30 @@ def get_cohort(user, course_key):
return group return group
def get_course_cohorts(course_key): def get_course_cohorts(course):
""" """
Get a list of all the cohorts in the given course. Get a list of all the cohorts in the given course. This will include auto cohorts,
regardless of whether or not the auto cohorts include any users.
Arguments: Arguments:
course_key: CourseKey course: the course for which cohorts should be returned
Returns: Returns:
A list of CourseUserGroup objects. Empty if there are no cohorts. Does A list of CourseUserGroup objects. Empty if there are no cohorts. Does
not check whether the course is cohorted. not check whether the course is cohorted.
""" """
# TODO: remove auto_cohort check with TNL-160
if course.auto_cohort:
# Ensure all auto cohorts are created.
for group_name in course.auto_cohort_groups:
CourseUserGroup.objects.get_or_create(
course_id=course.location.course_key,
group_type=CourseUserGroup.COHORT,
name=group_name
)
return list(CourseUserGroup.objects.filter( return list(CourseUserGroup.objects.filter(
course_id=course_key, course_id=course.location.course_key,
group_type=CourseUserGroup.COHORT group_type=CourseUserGroup.COHORT
)) ))
...@@ -269,13 +280,6 @@ def add_user_to_cohort(cohort, username_or_email): ...@@ -269,13 +280,6 @@ def add_user_to_cohort(cohort, username_or_email):
return (user, previous_cohort) return (user, previous_cohort)
def get_course_cohort_names(course_key):
"""
Return a list of the cohort names in a course.
"""
return [c.name for c in get_course_cohorts(course_key)]
def delete_empty_cohort(course_key, name): def delete_empty_cohort(course_key, name):
""" """
Remove an empty cohort. Raise ValueError if cohort is not empty. Remove an empty cohort. Raise ValueError if cohort is not empty.
......
"""
Helper methods for testing cohorts.
"""
from xmodule.modulestore.django import modulestore
from xmodule.modulestore import ModuleStoreEnum
def topic_name_to_id(course, name):
"""
Given a discussion topic name, return an id for that name (includes
course and url_name).
"""
return "{course}_{run}_{name}".format(
course=course.location.course,
run=course.url_name,
name=name
)
def config_course_cohorts(course, discussions,
cohorted,
cohorted_discussions=None,
auto_cohort=None,
auto_cohort_groups=None):
"""
Given a course with no discussion set up, add the discussions and set
the cohort config appropriately.
Arguments:
course: CourseDescriptor
discussions: list of topic names strings. Picks ids and sort_keys
automatically.
cohorted: bool.
cohorted_discussions: optional list of topic names. If specified,
converts them to use the same ids as topic names.
auto_cohort: optional bool.
auto_cohort_groups: optional list of strings
(names of groups to put students into).
Returns:
Nothing -- modifies course in place.
"""
def to_id(name):
return topic_name_to_id(course, name)
topics = dict((name, {"sort_key": "A",
"id": to_id(name)})
for name in discussions)
course.discussion_topics = topics
d = {"cohorted": cohorted}
if cohorted_discussions is not None:
d["cohorted_discussions"] = [to_id(name)
for name in cohorted_discussions]
if auto_cohort is not None:
d["auto_cohort"] = auto_cohort
if auto_cohort_groups is not None:
d["auto_cohort_groups"] = auto_cohort_groups
course.cohort_config = d
try:
# Not implemented for XMLModulestore, which is used by test_cohorts.
modulestore().update_item(course, ModuleStoreEnum.UserID.test)
except NotImplementedError:
pass
...@@ -4,6 +4,8 @@ from django.test.client import RequestFactory ...@@ -4,6 +4,8 @@ from django.test.client import RequestFactory
from django.test.utils import override_settings from django.test.utils import override_settings
from factory import post_generation, Sequence from factory import post_generation, Sequence
from factory.django import DjangoModelFactory from factory.django import DjangoModelFactory
from course_groups.tests.helpers import config_course_cohorts
from collections import namedtuple
from django.http import Http404 from django.http import Http404
from django.contrib.auth.models import User from django.contrib.auth.models import User
...@@ -123,11 +125,19 @@ class ListCohortsTestCase(CohortViewsTestCase): ...@@ -123,11 +125,19 @@ class ListCohortsTestCase(CohortViewsTestCase):
self.assertItemsEqual( self.assertItemsEqual(
response_dict.get("cohorts"), response_dict.get("cohorts"),
[ [
{"name": cohort.name, "id": cohort.id} {"name": cohort.name, "id": cohort.id, "user_count": cohort.user_count}
for cohort in expected_cohorts for cohort in expected_cohorts
] ]
) )
@staticmethod
def create_expected_cohort(cohort, user_count):
"""
Create a tuple storing the expected cohort information.
"""
cohort_tuple = namedtuple("Cohort", "name id user_count")
return cohort_tuple(name=cohort.name, id=cohort.id, user_count=user_count)
def test_non_staff(self): def test_non_staff(self):
""" """
Verify that we cannot access list_cohorts if we're a non-staff user. Verify that we cannot access list_cohorts if we're a non-staff user.
...@@ -145,12 +155,44 @@ class ListCohortsTestCase(CohortViewsTestCase): ...@@ -145,12 +155,44 @@ class ListCohortsTestCase(CohortViewsTestCase):
Verify that cohorts are in response for a course with some cohorts. Verify that cohorts are in response for a course with some cohorts.
""" """
self._create_cohorts() self._create_cohorts()
expected_cohorts = CourseUserGroup.objects.filter( expected_cohorts = [
course_id=self.course.id, ListCohortsTestCase.create_expected_cohort(self.cohort1, 3),
group_type=CourseUserGroup.COHORT ListCohortsTestCase.create_expected_cohort(self.cohort2, 2),
) ListCohortsTestCase.create_expected_cohort(self.cohort3, 2),
]
self.verify_lists_expected_cohorts(self.request_list_cohorts(self.course), expected_cohorts) self.verify_lists_expected_cohorts(self.request_list_cohorts(self.course), expected_cohorts)
def test_auto_cohorts(self):
"""
Verify that auto cohorts are included in the response.
"""
config_course_cohorts(self.course, [], cohorted=True, auto_cohort=True,
auto_cohort_groups=["AutoGroup1", "AutoGroup2"])
# Will create cohort1, cohort2, and cohort3. Auto cohorts remain uncreated.
self._create_cohorts()
# Get the cohorts from the course, which will cause auto cohorts to be created.
actual_cohorts = self.request_list_cohorts(self.course)
# Get references to the created auto cohorts.
auto_cohort_1 = CourseUserGroup.objects.get(
course_id=self.course.location.course_key,
group_type=CourseUserGroup.COHORT,
name="AutoGroup1"
)
auto_cohort_2 = CourseUserGroup.objects.get(
course_id=self.course.location.course_key,
group_type=CourseUserGroup.COHORT,
name="AutoGroup2"
)
expected_cohorts = [
ListCohortsTestCase.create_expected_cohort(self.cohort1, 3),
ListCohortsTestCase.create_expected_cohort(self.cohort2, 2),
ListCohortsTestCase.create_expected_cohort(self.cohort3, 2),
ListCohortsTestCase.create_expected_cohort(auto_cohort_1, 0),
ListCohortsTestCase.create_expected_cohort(auto_cohort_2, 0),
]
self.verify_lists_expected_cohorts(actual_cohorts, expected_cohorts)
class AddCohortTestCase(CohortViewsTestCase): class AddCohortTestCase(CohortViewsTestCase):
""" """
......
...@@ -46,10 +46,10 @@ def list_cohorts(request, course_key_string): ...@@ -46,10 +46,10 @@ def list_cohorts(request, course_key_string):
# this is a string when we get it here # this is a string when we get it here
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_key_string) course_key = SlashSeparatedCourseKey.from_deprecated_string(course_key_string)
get_course_with_access(request.user, 'staff', course_key) course = get_course_with_access(request.user, 'staff', course_key)
all_cohorts = [{'name': c.name, 'id': c.id} all_cohorts = [{'name': c.name, 'id': c.id, 'user_count': c.users.count()}
for c in cohorts.get_course_cohorts(course_key)] for c in cohorts.get_course_cohorts(course)]
return json_http_response({'success': True, return json_http_response({'success': True,
'cohorts': all_cohorts}) 'cohorts': all_cohorts})
......
...@@ -11,8 +11,7 @@ import newrelic.agent ...@@ -11,8 +11,7 @@ import newrelic.agent
from edxmako.shortcuts import render_to_response from edxmako.shortcuts import render_to_response
from courseware.courses import get_course_with_access from courseware.courses import get_course_with_access
from course_groups.cohorts import (is_course_cohorted, get_cohort_id, is_commentable_cohorted, from course_groups.cohorts import is_course_cohorted, get_cohort_id, get_course_cohorts, is_commentable_cohorted
get_cohorted_commentables, get_course_cohorts, get_cohort_by_id)
from courseware.access import has_access from courseware.access import has_access
from django_comment_client.permissions import cached_has_permission from django_comment_client.permissions import cached_has_permission
...@@ -52,7 +51,7 @@ def make_course_settings(course, include_category_map=False): ...@@ -52,7 +51,7 @@ def make_course_settings(course, include_category_map=False):
'is_cohorted': is_course_cohorted(course.id), 'is_cohorted': is_course_cohorted(course.id),
'allow_anonymous': course.allow_anonymous, 'allow_anonymous': course.allow_anonymous,
'allow_anonymous_to_peers': course.allow_anonymous_to_peers, 'allow_anonymous_to_peers': course.allow_anonymous_to_peers,
'cohorts': [{"id": str(g.id), "name": g.name} for g in get_course_cohorts(course.id)], 'cohorts': [{"id": str(g.id), "name": g.name} for g in get_course_cohorts(course)],
} }
if include_category_map: if include_category_map:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment