Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
3bb1ab08
Commit
3bb1ab08
authored
Sep 11, 2014
by
Nimisha Asthagiri
Committed by
cahrens
Oct 01, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TNL-160 Default cohorts, automatically created.
parent
267e8c97
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
100 additions
and
68 deletions
+100
-68
common/djangoapps/course_groups/cohorts.py
+24
-24
common/djangoapps/course_groups/tests/helpers.py
+32
-8
common/djangoapps/course_groups/tests/test_cohorts.py
+0
-0
common/djangoapps/course_groups/tests/test_views.py
+44
-36
No files found.
common/djangoapps/course_groups/cohorts.py
View file @
3bb1ab08
...
...
@@ -15,11 +15,21 @@ from .models import CourseUserGroup
log
=
logging
.
getLogger
(
__name__
)
# A 'default cohort' is an auto-cohort that is automatically created for a course if no auto-cohorts have been
# specified. It is intended to be used in a cohorted-course for users who have yet to be assigned to a cohort.
# If an administrator chooses to configure a cohort with the same name, the said cohort will also be used as
# the "default cohort".
# Translation Note: We are NOT translating this string since it is the constant identifier for the "default group"
# and needed across product boundaries.
DEFAULT_COHORT_NAME
=
"Default Cohort Group"
# tl;dr: global state is bad. capa reseeds random every time a problem is loaded. Even
# if and when that's fixed, it's a good idea to have a local generator to avoid any other
# code that messes with the global random module.
_local_random
=
None
def
local_random
():
"""
Get the local random number generator. In a function so that we don't run
...
...
@@ -135,27 +145,19 @@ def get_cohort(user, course_key):
# Didn't find the group. We'll go on to create one if needed.
pass
if
not
course
.
auto_cohort
:
return
None
choices
=
course
.
auto_cohort_groups
n
=
len
(
choices
)
if
n
==
0
:
# Nowhere to put user
log
.
warning
(
"Course
%
s is auto-cohorted, but there are no"
" auto_cohort_groups specified"
,
course_key
)
return
None
# Put user in a random group, creating it if needed
group_name
=
local_random
()
.
choice
(
choices
)
if
len
(
choices
)
>
0
:
# Randomly choose one of the auto_cohort_groups, creating it if needed.
group_name
=
local_random
()
.
choice
(
choices
)
else
:
# Use the "default cohort".
group_name
=
DEFAULT_COHORT_NAME
group
,
created
=
CourseUserGroup
.
objects
.
get_or_create
(
group
,
_
=
CourseUserGroup
.
objects
.
get_or_create
(
course_id
=
course_key
,
group_type
=
CourseUserGroup
.
COHORT
,
name
=
group_name
)
user
.
course_groups
.
add
(
group
)
return
group
...
...
@@ -172,15 +174,13 @@ def get_course_cohorts(course):
A list of CourseUserGroup objects. Empty if there are no cohorts. Does
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
)
# 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
(
course_id
=
course
.
location
.
course_key
,
...
...
common/djangoapps/course_groups/tests/helpers.py
View file @
3bb1ab08
...
...
@@ -3,6 +3,8 @@ Helper methods for testing cohorts.
"""
from
xmodule.modulestore.django
import
modulestore
from
xmodule.modulestore
import
ModuleStoreEnum
from
course_groups.models
import
CourseUserGroup
from
course_groups.cohorts
import
DEFAULT_COHORT_NAME
def
topic_name_to_id
(
course
,
name
):
...
...
@@ -17,11 +19,36 @@ def topic_name_to_id(course, name):
)
def
config_course_cohorts
(
course
,
discussions
,
cohorted
,
cohorted_discussions
=
None
,
auto_cohort
=
None
,
auto_cohort_groups
=
None
):
def
get_default_cohort
(
course
):
"""
Returns the default cohort for a course.
Returns None if the default cohort hasn't yet been created.
"""
return
get_cohort_in_course
(
DEFAULT_COHORT_NAME
,
course
)
def
get_cohort_in_course
(
cohort_name
,
course
):
"""
Returns the cohort with the name `cohort_name` in the given `course`.
Returns None if it doesn't exist.
"""
try
:
return
CourseUserGroup
.
objects
.
get
(
course_id
=
course
.
id
,
group_type
=
CourseUserGroup
.
COHORT
,
name
=
cohort_name
)
except
CourseUserGroup
.
DoesNotExist
:
return
None
def
config_course_cohorts
(
course
,
discussions
,
cohorted
,
cohorted_discussions
=
None
,
auto_cohort_groups
=
None
):
"""
Given a course with no discussion set up, add the discussions and set
the cohort config appropriately.
...
...
@@ -33,7 +60,6 @@ def config_course_cohorts(course, discussions,
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).
...
...
@@ -54,8 +80,6 @@ def config_course_cohorts(course, discussions,
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
...
...
common/djangoapps/course_groups/tests/test_cohorts.py
View file @
3bb1ab08
This diff is collapsed.
Click to expand it.
common/djangoapps/course_groups/tests/test_views.py
View file @
3bb1ab08
...
...
@@ -4,7 +4,7 @@ from django.test.client import RequestFactory
from
django.test.utils
import
override_settings
from
factory
import
post_generation
,
Sequence
from
factory.django
import
DjangoModelFactory
from
course_groups.tests.helpers
import
config_course_cohorts
from
course_groups.tests.helpers
import
config_course_cohorts
,
get_cohort_in_course
,
get_default_cohort
from
collections
import
namedtuple
from
django.http
import
Http404
...
...
@@ -18,6 +18,7 @@ from xmodule.modulestore.tests.factories import CourseFactory
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
course_groups.views
import
list_cohorts
,
add_cohort
,
users_in_cohort
,
add_users_to_cohort
,
remove_user_from_cohort
from
course_groups.cohorts
import
get_cohort
class
CohortFactory
(
DjangoModelFactory
):
FACTORY_FOR
=
CourseUserGroup
...
...
@@ -61,22 +62,6 @@ class CohortViewsTestCase(ModuleStoreTestCase):
self
.
cohort2
=
CohortFactory
.
create
(
course_id
=
self
.
course
.
id
,
users
=
self
.
cohort2_users
)
self
.
cohort3
=
CohortFactory
.
create
(
course_id
=
self
.
course
.
id
,
users
=
self
.
cohort3_users
)
def
_cohort_in_course
(
self
,
cohort_name
,
course
):
"""
Returns true iff `course` contains a cohort with the name
`cohort_name`.
"""
try
:
CourseUserGroup
.
objects
.
get
(
course_id
=
course
.
id
,
group_type
=
CourseUserGroup
.
COHORT
,
name
=
cohort_name
)
except
CourseUserGroup
.
DoesNotExist
:
return
False
else
:
return
True
def
_user_in_cohort
(
self
,
username
,
cohort
):
"""
Return true iff a user with `username` exists in `cohort`.
...
...
@@ -117,10 +102,14 @@ class ListCohortsTestCase(CohortViewsTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
return
json
.
loads
(
response
.
content
)
def
verify_lists_expected_cohorts
(
self
,
response_dict
,
expected_cohorts
):
def
verify_lists_expected_cohorts
(
self
,
expected_cohorts
,
response_dict
=
None
):
"""
Verify that the server response contains the expected_cohorts.
If response_dict is None, the list of cohorts is requested from the server.
"""
if
response_dict
is
None
:
response_dict
=
self
.
request_list_cohorts
(
self
.
course
)
self
.
assertTrue
(
response_dict
.
get
(
"success"
))
self
.
assertItemsEqual
(
response_dict
.
get
(
"cohorts"
),
...
...
@@ -148,7 +137,7 @@ class ListCohortsTestCase(CohortViewsTestCase):
"""
Verify that no cohorts are in response for a course with no cohorts.
"""
self
.
verify_lists_expected_cohorts
(
self
.
request_list_cohorts
(
self
.
course
),
[])
self
.
verify_lists_expected_cohorts
([])
def
test_some_cohorts
(
self
):
"""
...
...
@@ -160,13 +149,13 @@ class ListCohortsTestCase(CohortViewsTestCase):
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
(
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
,
config_course_cohorts
(
self
.
course
,
[],
cohorted
=
True
,
auto_cohort_groups
=
[
"AutoGroup1"
,
"AutoGroup2"
])
# Will create cohort1, cohort2, and cohort3. Auto cohorts remain uncreated.
...
...
@@ -174,16 +163,8 @@ class ListCohortsTestCase(CohortViewsTestCase):
# 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"
)
auto_cohort_1
=
get_cohort_in_course
(
"AutoGroup1"
,
self
.
course
)
auto_cohort_2
=
get_cohort_in_course
(
"AutoGroup2"
,
self
.
course
)
expected_cohorts
=
[
ListCohortsTestCase
.
create_expected_cohort
(
self
.
cohort1
,
3
),
ListCohortsTestCase
.
create_expected_cohort
(
self
.
cohort2
,
2
),
...
...
@@ -191,7 +172,36 @@ class ListCohortsTestCase(CohortViewsTestCase):
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
)
self
.
verify_lists_expected_cohorts
(
expected_cohorts
,
actual_cohorts
)
def
test_default_cohort
(
self
):
"""
Verify that the default cohort is not created and included in the response until students are assigned to it.
"""
# verify the default cohort is not created when the course is not cohorted
self
.
verify_lists_expected_cohorts
([])
# create a cohorted course without any auto_cohort_groups
config_course_cohorts
(
self
.
course
,
[],
cohorted
=
True
)
# verify the default cohort is not yet created until a user is assigned
self
.
verify_lists_expected_cohorts
([])
# create enrolled users
unassigned_users
=
[
UserFactory
.
create
()
for
_
in
range
(
3
)]
self
.
_enroll_users
(
unassigned_users
,
self
.
course
.
id
)
# mimic users accessing the discussion forum
for
user
in
unassigned_users
:
get_cohort
(
user
,
self
.
course
.
id
)
# verify the default cohort is automatically created
actual_cohorts
=
self
.
request_list_cohorts
(
self
.
course
)
default_cohort
=
get_default_cohort
(
self
.
course
)
self
.
verify_lists_expected_cohorts
(
[
ListCohortsTestCase
.
create_expected_cohort
(
default_cohort
,
len
(
unassigned_users
))],
actual_cohorts
,
)
class
AddCohortTestCase
(
CohortViewsTestCase
):
...
...
@@ -208,7 +218,7 @@ class AddCohortTestCase(CohortViewsTestCase):
self
.
assertEqual
(
response
.
status_code
,
200
)
return
json
.
loads
(
response
.
content
)
def
verify_contains_added_cohort
(
self
,
response_dict
,
cohort_name
,
course
,
expected_error_msg
=
None
):
def
verify_contains_added_cohort
(
self
,
response_dict
,
cohort_name
,
expected_error_msg
=
None
):
"""
Check that `add_cohort`'s response correctly returns the newly added
cohort (or error) in the response. Also verify that the cohort was
...
...
@@ -226,7 +236,7 @@ class AddCohortTestCase(CohortViewsTestCase):
response_dict
.
get
(
"cohort"
)
.
get
(
"name"
),
cohort_name
)
self
.
assert
True
(
self
.
_cohort_in_course
(
cohort_name
,
course
))
self
.
assert
IsNotNone
(
get_cohort_in_course
(
cohort_name
,
self
.
course
))
def
test_non_staff
(
self
):
"""
...
...
@@ -242,7 +252,6 @@ class AddCohortTestCase(CohortViewsTestCase):
self
.
verify_contains_added_cohort
(
self
.
request_add_cohort
(
cohort_name
,
self
.
course
),
cohort_name
,
self
.
course
)
def
test_no_cohort
(
self
):
...
...
@@ -263,7 +272,6 @@ class AddCohortTestCase(CohortViewsTestCase):
self
.
verify_contains_added_cohort
(
self
.
request_add_cohort
(
cohort_name
,
self
.
course
),
cohort_name
,
self
.
course
,
expected_error_msg
=
"Can't create two cohorts with the same name"
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment