Commit 695f19c4 by Ben McMorran

TNL-1907 Implement Course Team Membership API

parent 5faaca0d
...@@ -7,7 +7,9 @@ from .views import ( ...@@ -7,7 +7,9 @@ from .views import (
TeamsListView, TeamsListView,
TeamsDetailView, TeamsDetailView,
TopicDetailView, TopicDetailView,
TopicListView TopicListView,
MembershipListView,
MembershipDetailView
) )
TEAM_ID_PATTERN = r'(?P<team_id>[a-z\d_-]+)' TEAM_ID_PATTERN = r'(?P<team_id>[a-z\d_-]+)'
...@@ -35,5 +37,15 @@ urlpatterns = patterns( ...@@ -35,5 +37,15 @@ urlpatterns = patterns(
r'^v0/topics/' + TOPIC_ID_PATTERN + ',' + settings.COURSE_ID_PATTERN + '$', r'^v0/topics/' + TOPIC_ID_PATTERN + ',' + settings.COURSE_ID_PATTERN + '$',
TopicDetailView.as_view(), TopicDetailView.as_view(),
name="topics_detail" name="topics_detail"
),
url(
r'^v0/team_membership$',
MembershipListView.as_view(),
name="team_membership_list"
),
url(
r'^v0/team_membership/' + TEAM_ID_PATTERN + ',' + USERNAME_PATTERN + '$',
MembershipDetailView.as_view(),
name="team_membership_detail"
) )
) )
"""Errors thrown in the Team API"""
class TeamAPIRequestError(Exception):
"""There was a problem with a request to the Team API."""
pass
class NotEnrolledInCourseForTeam(TeamAPIRequestError):
"""User is not enrolled in the course for the team they are trying to join."""
pass
class AlreadyOnTeamInCourse(TeamAPIRequestError):
"""User is already a member of another team in the same course."""
pass
...@@ -7,7 +7,8 @@ from django_countries.fields import CountryField ...@@ -7,7 +7,8 @@ from django_countries.fields import CountryField
from xmodule_django.models import CourseKeyField from xmodule_django.models import CourseKeyField
from util.model_utils import generate_unique_readable_id from util.model_utils import generate_unique_readable_id
from student.models import LanguageField from student.models import LanguageField, CourseEnrollment
from .errors import AlreadyOnTeamInCourse, NotEnrolledInCourseForTeam
class CourseTeam(models.Model): class CourseTeam(models.Model):
...@@ -62,7 +63,11 @@ class CourseTeam(models.Model): ...@@ -62,7 +63,11 @@ class CourseTeam(models.Model):
def add_user(self, user): def add_user(self, user):
"""Adds the given user to the CourseTeam.""" """Adds the given user to the CourseTeam."""
CourseTeamMembership.objects.get_or_create( if not CourseEnrollment.is_enrolled(user, self.course_id):
raise NotEnrolledInCourseForTeam
if CourseTeamMembership.objects.filter(user=user, team__course_id=self.course_id).exists():
raise AlreadyOnTeamInCourse
return CourseTeamMembership.objects.create(
user=user, user=user,
team=self team=self
) )
......
...@@ -70,6 +70,16 @@ class DeveloperErrorViewMixin(object): ...@@ -70,6 +70,16 @@ class DeveloperErrorViewMixin(object):
raise raise
class ExpandableFieldViewMixin(object):
"""A view mixin to add expansion information to the serializer context for later use by an ExpandableField."""
def get_serializer_context(self):
"""Adds expand information from query parameters to the serializer context to support expandable fields."""
result = super(ExpandableFieldViewMixin, self).get_serializer_context()
result['expand'] = [x for x in self.request.QUERY_PARAMS.get('expand', '').split(',') if x]
return result
def view_course_access(depth=0, access_action='load', check_for_milestones=False): def view_course_access(depth=0, access_action='load', check_for_milestones=False):
""" """
Method decorator for an API endpoint that verifies the user has access to the course. Method decorator for an API endpoint that verifies the user has access to the course.
...@@ -142,6 +152,21 @@ def add_serializer_errors(serializer, data, field_errors): ...@@ -142,6 +152,21 @@ def add_serializer_errors(serializer, data, field_errors):
return field_errors return field_errors
def build_api_error(message, **kwargs):
"""Build an error dict corresponding to edX API conventions.
Args:
message (string): The string to use for developer and user messages.
The user message will be translated, but for this to work message
must have already been scraped. ugettext_noop is useful for this.
**kwargs: format parameters for message
"""
return {
'developer_message': message.format(**kwargs),
'user_message': _(message).format(**kwargs), # pylint: disable=translation-of-non-string
}
class RetrievePatchAPIView(RetrieveModelMixin, UpdateModelMixin, GenericAPIView): class RetrievePatchAPIView(RetrieveModelMixin, UpdateModelMixin, GenericAPIView):
"""Concrete view for retrieving and updating a model instance. """Concrete view for retrieving and updating a model instance.
......
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