Commit 57d49b0a by Eric Fischer

Support filtering team membership

Adds tests and functionality to support filtering the results returned
from team_membership endpoint with optional course_id parameter. Will
return 400 Bad Request in the event that the given course_id does not
match up with the provided team_id (team.course_id does not match), or
if the user is not enrolled in the course given.

Documentation has been added to the relevant API page on the wiki:
https://openedx.atlassian.net/wiki/display/TNL/Team+API
parent f785ae46
......@@ -231,3 +231,4 @@ Vedran Karačić <vedran@edx.org>
William Ono <william.ono@ubc.ca>
Dongwook Yoon <dy252@cornell.edu>
Awais Qureshi <awais.qureshi@arbisoft.com>
Eric Fischer <efischer@edx.org>
......@@ -198,6 +198,14 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
topic_id='topic_6'
)
self.test_team_name_id_map = {team.name: team for team in (
self.test_team_1,
self.test_team_2,
self.test_team_3,
self.test_team_4,
self.test_team_5,
)}
for user, course in [('staff', self.test_course_1), ('course_staff', self.test_course_1)]:
CourseEnrollment.enroll(
self.users[user], course.id, check_access=True
......@@ -777,6 +785,40 @@ class TestListMembershipAPI(TeamAPITestCase):
else:
self.assertEqual(membership['count'], 0)
@ddt.data(
('student_enrolled_both_courses_other_team', 'TestX/TS101/Test_Course', 200, 'Nuclear Team'),
('student_enrolled_both_courses_other_team', 'MIT/6.002x/Circuits', 200, 'Another Team'),
('student_enrolled', 'TestX/TS101/Test_Course', 200, u'sólar team'),
('student_enrolled', 'MIT/6.002x/Circuits', 400, ''),
)
@ddt.unpack
def test_course_filter_with_username(self, user, course_id, status, team_name):
membership = self.get_membership_list(
status,
{
'username': self.users[user],
'course_id': course_id
},
user=user
)
if status == 200:
self.assertEqual(membership['count'], 1)
self.assertEqual(membership['results'][0]['team']['team_id'], self.test_team_name_id_map[team_name].team_id)
@ddt.data(
('TestX/TS101/Test_Course', 200),
('MIT/6.002x/Circuits', 400),
)
@ddt.unpack
def test_course_filter_with_team_id(self, course_id, status):
membership = self.get_membership_list(status, {'team_id': self.test_team_1.team_id, 'course_id': course_id})
if status == 200:
self.assertEqual(membership['count'], 1)
self.assertEqual(membership['results'][0]['team']['team_id'], self.test_team_1.team_id)
def test_bad_course_id(self):
self.get_membership_list(404, {'course_id': 'no_such_course'})
def test_no_username_or_team_id(self):
self.get_membership_list(400, {})
......
......@@ -793,8 +793,17 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
"""GET /api/team/v0/team_membership"""
specified_username_or_team = False
username = None
valid_courses = None
team_id = None
requested_course_id = None
requested_course_key = None
accessible_course_ids = None
if 'course_id' in request.QUERY_PARAMS:
requested_course_id = request.QUERY_PARAMS['course_id']
try:
requested_course_key = CourseKey.from_string(requested_course_id)
except InvalidKeyError:
return Response(status=status.HTTP_404_NOT_FOUND)
if 'team_id' in request.QUERY_PARAMS:
specified_username_or_team = True
......@@ -803,6 +812,8 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
team = CourseTeam.objects.get(team_id=team_id)
except CourseTeam.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if requested_course_key is not None and requested_course_key != team.course_id:
return Response(status=status.HTTP_400_BAD_REQUEST)
if not has_team_api_access(request.user, team.course_id):
return Response(status=status.HTTP_404_NOT_FOUND)
......@@ -816,11 +827,9 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
staff_courses = (
CourseAccessRole.objects.filter(user=request.user, role='staff').values_list('course_id', flat=True)
)
valid_courses = [
CourseKey.from_string(course_key_string)
for course_list in [enrolled_courses, staff_courses]
for course_key_string in course_list
]
accessible_course_ids = [item for sublist in (enrolled_courses, staff_courses) for item in sublist]
if requested_course_id is not None and requested_course_id not in accessible_course_ids:
return Response(status=status.HTTP_400_BAD_REQUEST)
if not specified_username_or_team:
return Response(
......@@ -828,7 +837,13 @@ class MembershipListView(ExpandableFieldViewMixin, GenericAPIView):
status=status.HTTP_400_BAD_REQUEST
)
queryset = CourseTeamMembership.get_memberships(username, valid_courses, team_id)
course_keys = None
if requested_course_key is not None:
course_keys = [requested_course_key]
elif accessible_course_ids is not None:
course_keys = [CourseKey.from_string(course_string) for course_string in accessible_course_ids]
queryset = CourseTeamMembership.get_memberships(username, course_keys, team_id)
page = self.paginate_queryset(queryset)
serializer = self.get_pagination_serializer(page)
return Response(serializer.data) # pylint: disable=maybe-no-member
......
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