Commit 9e84ae14 by Victor Shnayder

Started integration work with Kevin's cohort changes

- Create new cohorts.py file
- moved code there from models.py
- implemented necessary functions.

Next: testing :)
parent 7bdb5c23
"""
This file contains the logic for cohort groups, as exposed internally to the
forums, and to the cohort admin views.
"""
from django.contrib.auth.models import User
import logging
from courseware import courses
from .models import CourseUserGroup
log = logging.getLogger(__name__)
def is_course_cohorted(course_id):
"""
Given a course id, return a boolean for whether or not the course is
cohorted.
Raises:
Http404 if the course doesn't exist.
"""
return courses.get_course_by_id(course_id).is_cohorted
def get_cohort_id(user, course_id):
"""
Given a course id and a user, return the id of the cohort that user is
assigned to in that course. If they don't have a cohort, return None.
"""
cohort = get_cohort(user, course_id)
return None if cohort is None else cohort.id
def is_commentable_cohorted(course_id, commentable_id):
"""
Given a course and a commentable id, return whether or not this commentable
is cohorted.
Raises:
Http404 if the course doesn't exist.
"""
course = courses.get_course_by_id(course_id)
return commentable_id in course.cohorted_discussions()
def get_cohort(user, course_id):
"""
Given a django User and a course_id, return the user's cohort. In classes with
auto-cohorting, put the user in a cohort if they aren't in one already.
Arguments:
user: a Django User object.
course_id: string in the format 'org/course/run'
Returns:
A CourseUserGroup object if the User has a cohort, or None.
"""
try:
group = CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
users__id=user.id)
except CourseUserGroup.DoesNotExist:
group = None
if group:
return group
# TODO: add auto-cohorting logic here once we know what that will be.
return None
def get_course_cohorts(course_id):
"""
Get a list of all the cohorts in the given course.
Arguments:
course_id: string in the format 'org/course/run'
Returns:
A list of CourseUserGroup objects. Empty if there are no cohorts.
"""
return list(CourseUserGroup.objects.filter(course_id=course_id,
group_type=CourseUserGroup.COHORT))
### Helpers for cohort management views
def get_cohort_by_name(course_id, name):
"""
Return the CourseUserGroup object for the given cohort. Raises DoesNotExist
it isn't present.
"""
return CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name)
def get_cohort_by_id(course_id, cohort_id):
"""
Return the CourseUserGroup object for the given cohort. Raises DoesNotExist
it isn't present. Uses the course_id for extra validation...
"""
return CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
id=cohort_id)
def add_cohort(course_id, name):
"""
Add a cohort to a course. Raises ValueError if a cohort of the same name already
exists.
"""
log.debug("Adding cohort %s to %s", name, course_id)
if CourseUserGroup.objects.filter(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name).exists():
raise ValueError("Can't create two cohorts with the same name")
return CourseUserGroup.objects.create(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name)
def add_user_to_cohort(cohort, username_or_email):
"""
Look up the given user, and if successful, add them to the specified cohort.
Arguments:
cohort: CourseUserGroup
username_or_email: string. Treated as email if has '@'
Returns:
User object.
Raises:
User.DoesNotExist if can't find user.
ValueError if user already present.
"""
if '@' in username_or_email:
user = User.objects.get(email=username_or_email)
else:
user = User.objects.get(username=username_or_email)
if cohort.users.filter(id=user.id).exists():
raise ValueError("User {0} already present".format(user.username))
cohort.users.add(user)
return user
def get_course_cohort_names(course_id):
"""
Return a list of the cohort names in a course.
"""
return [c.name for c in get_course_cohorts(course_id)]
def delete_empty_cohort(course_id, name):
"""
Remove an empty cohort. Raise ValueError if cohort is not empty.
"""
cohort = get_cohort_by_name(course_id, name)
if cohort.users.exists():
raise ValueError(
"Can't delete non-empty cohort {0} in course {1}".format(
name, course_id))
cohort.delete()
......@@ -31,123 +31,4 @@ class CourseUserGroup(models.Model):
GROUP_TYPE_CHOICES = ((COHORT, 'Cohort'),)
group_type = models.CharField(max_length=20, choices=GROUP_TYPE_CHOICES)
def get_cohort(user, course_id):
"""
Given a django User and a course_id, return the user's cohort. In classes with
auto-cohorting, put the user in a cohort if they aren't in one already.
Arguments:
user: a Django User object.
course_id: string in the format 'org/course/run'
Returns:
A CourseUserGroup object if the User has a cohort, or None.
"""
try:
group = CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
users__id=user.id)
except CourseUserGroup.DoesNotExist:
group = None
if group:
return group
# TODO: add auto-cohorting logic here
return None
def get_course_cohorts(course_id):
"""
Get a list of all the cohorts in the given course.
Arguments:
course_id: string in the format 'org/course/run'
Returns:
A list of CourseUserGroup objects. Empty if there are no cohorts.
"""
return list(CourseUserGroup.objects.filter(course_id=course_id,
group_type=CourseUserGroup.COHORT))
### Helpers for cohor management views
def get_cohort_by_name(course_id, name):
"""
Return the CourseUserGroup object for the given cohort. Raises DoesNotExist
it isn't present.
"""
return CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name)
def get_cohort_by_id(course_id, cohort_id):
"""
Return the CourseUserGroup object for the given cohort. Raises DoesNotExist
it isn't present. Uses the course_id for extra validation...
"""
return CourseUserGroup.objects.get(course_id=course_id,
group_type=CourseUserGroup.COHORT,
id=cohort_id)
def add_cohort(course_id, name):
"""
Add a cohort to a course. Raises ValueError if a cohort of the same name already
exists.
"""
log.debug("Adding cohort %s to %s", name, course_id)
if CourseUserGroup.objects.filter(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name).exists():
raise ValueError("Can't create two cohorts with the same name")
return CourseUserGroup.objects.create(course_id=course_id,
group_type=CourseUserGroup.COHORT,
name=name)
def add_user_to_cohort(cohort, username_or_email):
"""
Look up the given user, and if successful, add them to the specified cohort.
Arguments:
cohort: CourseUserGroup
username_or_email: string. Treated as email if has '@'
Returns:
User object.
Raises:
User.DoesNotExist if can't find user.
ValueError if user already present.
"""
if '@' in username_or_email:
user = User.objects.get(email=username_or_email)
else:
user = User.objects.get(username=username_or_email)
if cohort.users.filter(id=user.id).exists():
raise ValueError("User {0} already present".format(user.username))
cohort.users.add(user)
return user
def get_course_cohort_names(course_id):
"""
Return a list of the cohort names in a course.
"""
return [c.name for c in get_course_cohorts(course_id)]
def delete_empty_cohort(course_id, name):
"""
Remove an empty cohort. Raise ValueError if cohort is not empty.
"""
cohort = get_cohort_by_name(course_id, name)
if cohort.users.exists():
raise ValueError(
"Can't delete non-empty cohort {0} in course {1}".format(
name, course_id))
cohort.delete()
import json
from django_future.csrf import ensure_csrf_cookie
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
......@@ -7,6 +6,7 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseForbidden, Http404
from django.shortcuts import redirect
import json
import logging
from courseware.courses import get_course_with_access
......@@ -14,7 +14,7 @@ from mitxmako.shortcuts import render_to_response, render_to_string
from string_util import split_by_comma_and_whitespace
from .models import CourseUserGroup
from . import models
from . import cohorts
import track.views
......@@ -38,11 +38,11 @@ def list_cohorts(request, course_id):
"""
get_course_with_access(request.user, course_id, 'staff')
cohorts = [{'name': c.name, 'id': c.id}
for c in models.get_course_cohorts(course_id)]
all_cohorts = [{'name': c.name, 'id': c.id}
for c in cohorts.get_course_cohorts(course_id)]
return JsonHttpReponse({'success': True,
'cohorts': cohorts})
'cohorts': all_cohorts})
@ensure_csrf_cookie
......@@ -70,7 +70,7 @@ def add_cohort(request, course_id):
'msg': "No name specified"})
try:
cohort = models.add_cohort(course_id, name)
cohort = cohorts.add_cohort(course_id, name)
except ValueError as err:
return JsonHttpReponse({'success': False,
'msg': str(err)})
......@@ -98,7 +98,7 @@ def users_in_cohort(request, course_id, cohort_id):
"""
get_course_with_access(request.user, course_id, 'staff')
cohort = models.get_cohort_by_id(course_id, int(cohort_id))
cohort = cohorts.get_cohort_by_id(course_id, int(cohort_id))
paginator = Paginator(cohort.users.all(), 100)
page = request.GET.get('page')
......@@ -141,7 +141,7 @@ def add_users_to_cohort(request, course_id, cohort_id):
if request.method != "POST":
raise Http404("Must POST to add users to cohorts")
cohort = models.get_cohort_by_id(course_id, cohort_id)
cohort = cohorts.get_cohort_by_id(course_id, cohort_id)
users = request.POST.get('users', '')
added = []
......@@ -149,7 +149,7 @@ def add_users_to_cohort(request, course_id, cohort_id):
unknown = []
for username_or_email in split_by_comma_and_whitespace(users):
try:
user = models.add_user_to_cohort(cohort, username_or_email)
user = cohorts.add_user_to_cohort(cohort, username_or_email)
added.append({'username': user.username,
'name': "{0} {1}".format(user.first_name, user.last_name),
'email': user.email,
......
......@@ -223,7 +223,7 @@ class CourseDescriptor(SequenceDescriptor):
return policy_str
@classmethod
def from_xml(cls, xml_data, system, org=None, course=None):
instance = super(CourseDescriptor, cls).from_xml(xml_data, system, org, course)
......@@ -248,7 +248,7 @@ class CourseDescriptor(SequenceDescriptor):
except ValueError:
system.error_tracker("Unable to decode grading policy as json")
policy = None
# cdodge: import the grading policy information that is on disk and put into the
# descriptor 'definition' bucket as a dictionary so that it is persisted in the DB
instance.definition['data']['grading_policy'] = policy
......@@ -303,28 +303,28 @@ class CourseDescriptor(SequenceDescriptor):
@property
def enrollment_start(self):
return self._try_parse_time("enrollment_start")
@enrollment_start.setter
def enrollment_start(self, value):
if isinstance(value, time.struct_time):
self.metadata['enrollment_start'] = stringify_time(value)
@property
def enrollment_end(self):
def enrollment_end(self):
return self._try_parse_time("enrollment_end")
@enrollment_end.setter
def enrollment_end(self, value):
if isinstance(value, time.struct_time):
self.metadata['enrollment_end'] = stringify_time(value)
@property
def grader(self):
return self._grading_policy['GRADER']
@property
def raw_grader(self):
return self._grading_policy['RAW_GRADER']
@raw_grader.setter
def raw_grader(self, value):
# NOTE WELL: this change will not update the processed graders. If we need that, this needs to call grader_from_conf
......@@ -334,12 +334,12 @@ class CourseDescriptor(SequenceDescriptor):
@property
def grade_cutoffs(self):
return self._grading_policy['GRADE_CUTOFFS']
@grade_cutoffs.setter
def grade_cutoffs(self, value):
self._grading_policy['GRADE_CUTOFFS'] = value
self.definition['data'].setdefault('grading_policy',{})['GRADE_CUTOFFS'] = value
@property
def lowest_passing_grade(self):
......@@ -371,6 +371,19 @@ class CourseDescriptor(SequenceDescriptor):
return bool(config.get("cohorted"))
def cohorted_discussions(self):
"""
Return the set of discussions that is cohorted. It may be the empty
set.
"""
config = self.metadata.get("cohort-config")
if config is None:
return set()
return set(config.get("cohorted-discussions", []))
@property
def is_new(self):
"""
......
......@@ -83,26 +83,6 @@ def get_opt_course_with_access(user, course_id, action):
return None
return get_course_with_access(user, course_id, action)
def get_cohort_id(user, course_id):
"""
given a course id and a user, return the id of the cohort that user is assigned to
and if the course is not cohorted or the user is an instructor, return None
"""
return 127
def is_commentable_cohorted(course_id,commentable_id):
"""
given a course and a commentable id, return whether or not this commentable is cohorted
"""
def get_cohort_ids(course_id):
"""
given a course id, return an array of all cohort ids for that course (needed for UI
"""
def course_image_url(course):
"""Try to look up the image url for the course. If it's not found,
......
......@@ -21,7 +21,7 @@ from django.contrib.auth.models import User
from mitxmako.shortcuts import render_to_response, render_to_string
from courseware.courses import get_course_with_access
from courseware.courses import get_cohort_id,is_commentable_cohorted
from course_groups.cohorts import get_cohort_id, is_commentable_cohorted
from django_comment_client.utils import JsonResponse, JsonError, extract, get_courseware_context
......
......@@ -11,7 +11,7 @@ from django.contrib.auth.models import User
from mitxmako.shortcuts import render_to_response, render_to_string
from courseware.courses import get_course_with_access
from courseware.courses import get_cohort_id
from course_groups.cohorts import get_cohort_id
from courseware.access import has_access
from urllib import urlencode
......
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