Commit 695f19c4 by Ben McMorran

TNL-1907 Implement Course Team Membership API

parent 5faaca0d
......@@ -7,7 +7,9 @@ from .views import (
TeamsListView,
TeamsDetailView,
TopicDetailView,
TopicListView
TopicListView,
MembershipListView,
MembershipDetailView
)
TEAM_ID_PATTERN = r'(?P<team_id>[a-z\d_-]+)'
......@@ -35,5 +37,15 @@ urlpatterns = patterns(
r'^v0/topics/' + TOPIC_ID_PATTERN + ',' + settings.COURSE_ID_PATTERN + '$',
TopicDetailView.as_view(),
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
from xmodule_django.models import CourseKeyField
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):
......@@ -62,7 +63,11 @@ class CourseTeam(models.Model):
def add_user(self, user):
"""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,
team=self
)
......
......@@ -70,6 +70,16 @@ class DeveloperErrorViewMixin(object):
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):
"""
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):
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):
"""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