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
5ea7ced9
Commit
5ea7ced9
authored
Dec 18, 2014
by
cahrens
Committed by
Andy Armstrong
Jan 15, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Create a RESTful handle_cohort view method for GET and PUT/POST.
parent
9b85ac1f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
140 additions
and
99 deletions
+140
-99
lms/static/js/models/cohort.js
+15
-1
lms/urls.py
+2
-5
openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py
+21
-36
openedx/core/djangoapps/course_groups/tests/test_views.py
+0
-0
openedx/core/djangoapps/course_groups/views.py
+102
-57
No files found.
lms/static/js/models/cohort.js
View file @
5ea7ced9
...
...
@@ -3,7 +3,21 @@
idAttribute
:
'id'
,
defaults
:
{
name
:
''
,
user_count
:
0
user_count
:
0
,
/**
* Indicates how students are added to the cohort. Will be "none" (signifying manual assignment) or
* "random" (indicating students are randomly assigned).
*/
assignment_type
:
''
,
/**
* If this cohort is associated with a user partition group, the ID of the user partition.
*/
user_partition_id
:
null
,
/**
* If this cohort is associated with a user partition group, the ID of the group within the
* partition associated with user_partition_id.
*/
group_id
:
null
}
});
...
...
lms/urls.py
View file @
5ea7ced9
...
...
@@ -345,11 +345,8 @@ if settings.COURSEWARE_ENABLED:
'open_ended_grading.views.take_action_on_flags'
,
name
=
'open_ended_flagged_problems_take_action'
),
# Cohorts management
url
(
r'^courses/{}/cohorts$'
.
format
(
settings
.
COURSE_KEY_PATTERN
),
'openedx.core.djangoapps.course_groups.views.list_cohorts'
,
name
=
"cohorts"
),
url
(
r'^courses/{}/cohorts/add$'
.
format
(
settings
.
COURSE_KEY_PATTERN
),
'openedx.core.djangoapps.course_groups.views.add_cohort'
,
name
=
"add_cohort"
),
url
(
r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)?$'
.
format
(
settings
.
COURSE_KEY_PATTERN
),
'openedx.core.djangoapps.course_groups.views.cohort_handler'
,
name
=
"cohorts"
),
url
(
r'^courses/{}/cohorts/(?P<cohort_id>[0-9]+)$'
.
format
(
settings
.
COURSE_KEY_PATTERN
),
'openedx.core.djangoapps.course_groups.views.users_in_cohort'
,
name
=
"list_cohort"
),
...
...
openedx/core/djangoapps/course_groups/tests/test_partition_scheme.py
View file @
5ea7ced9
...
...
@@ -21,6 +21,7 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
from
openedx.core.djangoapps.user_api.partition_schemes
import
RandomUserPartitionScheme
from
..partition_scheme
import
CohortPartitionScheme
,
get_cohorted_user_partition
from
..models
import
CourseUserGroupPartitionGroup
from
..views
import
link_cohort_to_partition_group
,
unlink_cohort_partition_group
from
..cohorts
import
add_user_to_cohort
,
get_course_cohorts
from
.helpers
import
CohortFactory
,
config_course_cohorts
...
...
@@ -55,22 +56,6 @@ class TestCohortPartitionScheme(django.test.TestCase):
)
self
.
student
=
UserFactory
.
create
()
def
link_cohort_partition_group
(
self
,
cohort
,
partition
,
group
):
"""
Utility for creating cohort -> partition group links
"""
CourseUserGroupPartitionGroup
(
course_user_group
=
cohort
,
partition_id
=
partition
.
id
,
group_id
=
group
.
id
,
)
.
save
()
def
unlink_cohort_partition_group
(
self
,
cohort
):
"""
Utility for removing cohort -> partition group links
"""
CourseUserGroupPartitionGroup
.
objects
.
filter
(
course_user_group
=
cohort
)
.
delete
()
def
assert_student_in_group
(
self
,
group
,
partition
=
None
):
"""
Utility for checking that our test student comes up as assigned to the
...
...
@@ -99,16 +84,16 @@ class TestCohortPartitionScheme(django.test.TestCase):
self
.
assert_student_in_group
(
None
)
# link first cohort to group 0 in the partition
self
.
link_cohort
_partition_group
(
link_cohort_to
_partition_group
(
first_cohort
,
self
.
user_partition
,
self
.
groups
[
0
],
self
.
user_partition
.
id
,
self
.
groups
[
0
]
.
id
,
)
# link second cohort to to group 1 in the partition
self
.
link_cohort
_partition_group
(
link_cohort_to
_partition_group
(
second_cohort
,
self
.
user_partition
,
self
.
groups
[
1
],
self
.
user_partition
.
id
,
self
.
groups
[
1
]
.
id
,
)
self
.
assert_student_in_group
(
self
.
groups
[
0
])
...
...
@@ -133,26 +118,26 @@ class TestCohortPartitionScheme(django.test.TestCase):
self
.
assert_student_in_group
(
None
)
# link cohort to group 0
self
.
link_cohort
_partition_group
(
link_cohort_to
_partition_group
(
test_cohort
,
self
.
user_partition
,
self
.
groups
[
0
],
self
.
user_partition
.
id
,
self
.
groups
[
0
]
.
id
,
)
# now the scheme should find a link
self
.
assert_student_in_group
(
self
.
groups
[
0
])
# link cohort to group 1 (first unlink it from group 0)
self
.
unlink_cohort_partition_group
(
test_cohort
)
self
.
link_cohort
_partition_group
(
unlink_cohort_partition_group
(
test_cohort
)
link_cohort_to
_partition_group
(
test_cohort
,
self
.
user_partition
,
self
.
groups
[
1
],
self
.
user_partition
.
id
,
self
.
groups
[
1
]
.
id
,
)
# scheme should pick up the link
self
.
assert_student_in_group
(
self
.
groups
[
1
])
# unlink cohort from anywhere
self
.
unlink_cohort_partition_group
(
unlink_cohort_partition_group
(
test_cohort
,
)
# scheme should now return nothing
...
...
@@ -171,10 +156,10 @@ class TestCohortPartitionScheme(django.test.TestCase):
cohort
=
get_course_cohorts
(
self
.
course
)[
0
]
# map that cohort to a group in our partition
self
.
link_cohort
_partition_group
(
link_cohort_to
_partition_group
(
cohort
,
self
.
user_partition
,
self
.
groups
[
0
],
self
.
user_partition
.
id
,
self
.
groups
[
0
]
.
id
,
)
# The student will be lazily assigned to the default cohort
...
...
@@ -190,10 +175,10 @@ class TestCohortPartitionScheme(django.test.TestCase):
test_cohort
=
CohortFactory
(
course_id
=
self
.
course_key
)
# link cohort to group 0
self
.
link_cohort
_partition_group
(
link_cohort_to
_partition_group
(
test_cohort
,
self
.
user_partition
,
self
.
groups
[
0
],
self
.
user_partition
.
id
,
self
.
groups
[
0
]
.
id
,
)
# place student into cohort
add_user_to_cohort
(
test_cohort
,
self
.
student
.
username
)
...
...
openedx/core/djangoapps/course_groups/tests/test_views.py
View file @
5ea7ced9
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/course_groups/views.py
View file @
5ea7ced9
...
...
@@ -4,6 +4,9 @@ from django.contrib.auth.models import User
from
django.core.paginator
import
Paginator
,
EmptyPage
from
django.core.urlresolvers
import
reverse
from
django.http
import
Http404
,
HttpResponse
,
HttpResponseBadRequest
from
django.views.decorators.http
import
require_http_methods
from
util.json_request
import
expect_json
,
JsonResponse
from
django.contrib.auth.decorators
import
login_required
import
json
import
logging
import
re
...
...
@@ -12,9 +15,8 @@ from opaque_keys.edx.locations import SlashSeparatedCourseKey
from
courseware.courses
import
get_course_with_access
from
edxmako.shortcuts
import
render_to_response
from
util.json_request
import
JsonResponse
from
.
import
cohorts
from
.models
import
CourseUserGroup
from
.models
import
CourseUserGroup
,
CourseUserGroupPartitionGroup
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -29,76 +31,119 @@ def json_http_response(data):
def
split_by_comma_and_whitespace
(
cstr
):
"""
Split a string both by commas and whitesp
i
ce. Returns a list.
Split a string both by commas and whitesp
a
ce. Returns a list.
"""
return
re
.
split
(
r'[\s,]+'
,
cstr
)
@ensure_csrf_cookie
def
list_cohorts
(
request
,
course_key_string
):
def
link_cohort_to_partition_group
(
cohort
,
partition_id
,
group_id
):
"""
Return json dump of dict:
{'success': True,
'cohorts': [{'name': name, 'id': id}, ...]}
Create cohort to partition_id/group_id link.
"""
CourseUserGroupPartitionGroup
(
course_user_group
=
cohort
,
partition_id
=
partition_id
,
group_id
=
group_id
,
)
.
save
()
# this is a string when we get it here
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_key_string
)
course
=
get_course_with_access
(
request
.
user
,
'staff'
,
course_key
)
def
unlink_cohort_partition_group
(
cohort
):
"""
Remove any existing cohort to partition_id/group_id link.
"""
CourseUserGroupPartitionGroup
.
objects
.
filter
(
course_user_group
=
cohort
)
.
delete
()
all_cohorts
=
[
{
'name'
:
c
.
name
,
'id'
:
c
.
id
,
'user_count'
:
c
.
users
.
count
(),
'assignment_type'
:
cohorts
.
CohortAssignmentType
.
get
(
c
,
course
)
}
for
c
in
cohorts
.
get_course_cohorts
(
course
)
]
return
json_http_response
({
'success'
:
True
,
'cohorts'
:
all_cohorts
})
def
_get_cohort_representation
(
cohort
,
course
):
"""
Returns a JSON representation of a cohort.
"""
group_id
,
partition_id
=
cohorts
.
get_group_info_for_cohort
(
cohort
)
return
{
'name'
:
cohort
.
name
,
'id'
:
cohort
.
id
,
'user_count'
:
cohort
.
users
.
count
(),
'assignment_type'
:
cohorts
.
CohortAssignmentType
.
get
(
cohort
,
course
),
'user_partition_id'
:
partition_id
,
'group_id'
:
group_id
}
@require_http_methods
((
"GET"
,
"PUT"
,
"POST"
,
"PATCH"
))
@ensure_csrf_cookie
@require_POST
def
add_cohort
(
request
,
course_key_string
):
@expect_json
@login_required
def
cohort_handler
(
request
,
course_key_string
,
cohort_id
=
None
):
"""
Return json of dict:
{'success': True,
'cohort': {'id': id,
'name': name}}
or
{'success': False,
'msg': error_msg} if there's an error
The restful handler for cohort requests. Requires JSON.
GET
If a cohort ID is specified, returns a JSON representation of the cohort
(name, id, user_count, assignment_type, user_partition_id, group_id).
If no cohort ID is specified, returns the JSON representation of all cohorts.
This is returned as a dict with the list of cohort information stored under the
key `cohorts`.
PUT or POST or PATCH
If a cohort ID is specified, updates the cohort with the specified ID. Currently the only
properties that can be updated are `name`, `user_partition_id` and `group_id`.
Returns the JSON representation of the updated cohort.
If no cohort ID is specified, creates a new cohort and returns the JSON representation of the updated
cohort.
"""
# this is a string when we get it here
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_key_string
)
get_course_with_access
(
request
.
user
,
'staff'
,
course_key
)
name
=
request
.
POST
.
get
(
"name"
)
if
not
name
:
return
json_http_response
({
'success'
:
False
,
'msg'
:
"No name specified"
})
try
:
cohort
=
cohorts
.
add_cohort
(
course_key
,
name
)
except
ValueError
as
err
:
return
json_http_response
({
'success'
:
False
,
'msg'
:
str
(
err
)})
return
json_http_response
({
'success'
:
'True'
,
'cohort'
:
{
'id'
:
cohort
.
id
,
'name'
:
cohort
.
name
}
})
course
=
get_course_with_access
(
request
.
user
,
'staff'
,
course_key
)
if
request
.
method
==
'GET'
:
if
not
cohort_id
:
all_cohorts
=
[
_get_cohort_representation
(
c
,
course
)
for
c
in
cohorts
.
get_course_cohorts
(
course
)
]
# TODO: change to just directly returning the lists.
return
JsonResponse
({
'cohorts'
:
all_cohorts
})
else
:
cohort
=
cohorts
.
get_cohort_by_id
(
course_key
,
cohort_id
)
return
JsonResponse
(
_get_cohort_representation
(
cohort
,
course
))
else
:
# If cohort_id is specified, update the existing cohort. Otherwise, create a new cohort.
if
cohort_id
:
cohort
=
cohorts
.
get_cohort_by_id
(
course_key
,
cohort_id
)
name
=
request
.
json
.
get
(
'name'
)
if
name
!=
cohort
.
name
:
if
cohorts
.
CohortAssignmentType
.
get
(
cohort
,
course
)
==
cohorts
.
CohortAssignmentType
.
RANDOM
:
return
JsonResponse
(
# Note: error message not translated because it is not exposed to the user (UI prevents).
{
"error"
:
"Renaming of random cohorts is not supported at this time."
},
400
)
cohort
.
name
=
name
cohort
.
save
()
else
:
name
=
request
.
json
.
get
(
'name'
)
if
not
name
:
# Note: error message not translated because it is not exposed to the user (UI prevents this state).
return
JsonResponse
({
"error"
:
"In order to create a cohort, a name must be specified."
},
400
)
try
:
cohort
=
cohorts
.
add_cohort
(
course_key
,
name
)
except
ValueError
as
err
:
return
JsonResponse
({
"error"
:
unicode
(
err
)},
400
)
group_id
=
request
.
json
.
get
(
'group_id'
)
if
group_id
is
not
None
:
user_partition_id
=
request
.
json
.
get
(
'user_partition_id'
)
if
user_partition_id
is
None
:
# Note: error message not translated because it is not exposed to the user (UI prevents this state).
return
JsonResponse
(
{
"error"
:
"If group_id is specified, user_partition_id must also be specified."
},
400
)
existing_group_id
,
existing_partition_id
=
cohorts
.
get_group_info_for_cohort
(
cohort
)
if
group_id
!=
existing_group_id
or
user_partition_id
!=
existing_partition_id
:
unlink_cohort_partition_group
(
cohort
)
link_cohort_to_partition_group
(
cohort
,
user_partition_id
,
group_id
)
else
:
# If group_id was specified as None, unlink the cohort if it previously was associated with a group.
existing_group_id
,
_
=
cohorts
.
get_group_info_for_cohort
(
cohort
)
if
existing_group_id
is
not
None
:
unlink_cohort_partition_group
(
cohort
)
return
JsonResponse
(
_get_cohort_representation
(
cohort
,
course
))
@ensure_csrf_cookie
...
...
@@ -121,7 +166,7 @@ def users_in_cohort(request, course_key_string, cohort_id):
get_course_with_access
(
request
.
user
,
'staff'
,
course_key
)
# this will error if called with a non-int cohort_id. That's ok--it
# shoudn't happen for valid clients.
# shou
l
dn't happen for valid clients.
cohort
=
cohorts
.
get_cohort_by_id
(
course_key
,
int
(
cohort_id
))
paginator
=
Paginator
(
cohort
.
users
.
all
(),
100
)
...
...
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