EDUCATOR-4920 Control permission to REST endpoint

EDUCATOR-4920 Control permission to REST endpoint
CR1

EDUCATOR-4920 Control permission to REST endpoint
CR1
This commit is contained in:
atesker
2020-03-03 11:23:03 -05:00
committed by Andytr1
parent 1ccbd7d0c2
commit bf14bc97d2
3 changed files with 106 additions and 15 deletions

View File

@@ -207,16 +207,30 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
def setUpClass(cls):
# pylint: disable=super-method-not-called
with super(TeamAPITestCase, cls).setUpClassAndTestData():
base_topics = [{
'id': 'topic_{}'.format(i), 'name': name,
'description': u'Description for topic {}.'.format(i)
} for i, name in enumerate([u'Sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power'])]
base_topics.append(
{
'id': 'private_topic_1_id',
'name': 'private_topic_1_name',
'description': u'Description for topic private topic 1.',
'type': u'private_managed'
}
)
base_topics.append(
{
'id': 'private_topic_2_id',
'name': 'private_topic_2_name',
'description': u'Description for topic private topic 2.',
'type': u'private_managed'
}
)
teams_configuration_1 = TeamsConfig({
'topics':
[
{
'id': 'topic_{}'.format(i),
'name': name,
'description': u'Description for topic {}.'.format(i)
} for i, name in enumerate([u'Sólar power', 'Wind Power', 'Nuclear Power', 'Coal Power'])
]
'topics': base_topics
})
cls.test_course_1 = CourseFactory.create(
org='TestX',
course='TS101',
@@ -255,12 +269,14 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
@classmethod
def setUpTestData(cls):
super(TeamAPITestCase, cls).setUpTestData()
cls.topics_count = 4
cls.topics_count = 6
cls.users = {
'staff': AdminFactory.create(password=cls.test_password),
'course_staff': StaffFactory.create(course_key=cls.test_course_1.id, password=cls.test_password)
}
cls.create_and_enroll_student(username='student_enrolled')
cls.create_and_enroll_student(username='student_on_team_1_private_set_1', mode=CourseMode.MASTERS)
cls.create_and_enroll_student(username='student_not_member_of_private_teams', mode=CourseMode.MASTERS)
cls.create_and_enroll_student(username='student_enrolled_not_on_team')
cls.create_and_enroll_student(username='student_unenrolled', courses=[])
@@ -346,6 +362,36 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
organization_protected=True
)
cls.team_1_in_private_teamset_1 = CourseTeamFactory.create(
name='team 1 in private teamset 1',
description='team 1 in private teamset 1 desc',
country='US',
language='EN',
course_id=cls.test_course_1.id,
topic_id='private_topic_1_id',
organization_protected=True
)
cls.team_2_in_private_teamset_1 = CourseTeamFactory.create(
name='team 2 in private teamset 1',
description='team 2 in private teamset 1 desc',
country='US',
language='EN',
course_id=cls.test_course_1.id,
topic_id='private_topic_1_id',
organization_protected=True
)
cls.team_1_in_private_teamset_2 = CourseTeamFactory.create(
name='team 1 in private teamset 2',
description='team 1 in private teamset 2 desc',
country='US',
language='EN',
course_id=cls.test_course_1.id,
topic_id='private_topic_2_id',
organization_protected=True
)
cls.test_team_name_id_map = {team.name: team for team in (
cls.solar_team,
cls.wind_team,
@@ -370,6 +416,7 @@ class TeamAPITestCase(APITestCase, SharedModuleStoreTestCase):
cls.another_team.add_user(cls.users['student_enrolled_both_courses_other_team'])
cls.public_profile_team.add_user(cls.users['student_enrolled_public_profile'])
cls.masters_only_team.add_user(cls.users['student_masters'])
cls.team_1_in_private_teamset_1.add_user(cls.users['student_on_team_1_private_set_1'])
def build_membership_data_raw(self, username, team):
"""Assembles a membership creation payload based on the raw values provided."""
@@ -581,8 +628,8 @@ class TestListTeamsAPI(EventTestMixin, TeamAPITestCase):
('student_inactive', 401),
('student_unenrolled', 403),
('student_enrolled', 200, 3),
('staff', 200, 4),
('course_staff', 200, 4),
('staff', 200, 7),
('course_staff', 200, 7),
('community_ta', 200, 3),
('student_masters', 200, 1)
)
@@ -662,6 +709,25 @@ class TestListTeamsAPI(EventTestMixin, TeamAPITestCase):
result = self.get_teams_list(200, {'page_size': 2})
self.assertEqual(2, result['num_pages'])
def test_non_member_trying_to_get_private_topic(self):
"""
Verifies that when a student that is enrolled in a course, but is NOT a member of
a private team set, asks for information about that team set, an empty list is returned.
"""
result = self.get_teams_list(data={'topic_id': 'private_topic_1_id'})
self.assertEqual([], result['results'])
def test_member_trying_to_get_private_topic(self):
"""
Verifies that when a student that is enrolled in a course, and IS a member of
a private team set, asks for information about that team set, information about the teamset is returned.
"""
result = self.get_teams_list(data={'topic_id': 'private_topic_1_id'},
user='student_on_team_1_private_set_1')
self.assertEqual(1, len(result['results']))
self.assertEqual('private_topic_1_id', result['results'][0]['topic_id'])
self.assertNotEqual([], result['results'])
def test_page(self):
result = self.get_teams_list(200, {'page_size': 1, 'page': 3})
self.assertEqual(3, result['num_pages'])
@@ -1141,11 +1207,14 @@ class TestListTopicsAPI(TeamAPITestCase):
self.get_topics_list(400)
@ddt.data(
(None, 200, ['Coal Power', 'Nuclear Power', u'Sólar power', 'Wind Power'], 'name'),
('name', 200, ['Coal Power', 'Nuclear Power', u'Sólar power', 'Wind Power'], 'name'),
(None, 200, ['Coal Power', 'Nuclear Power', 'private_topic_1_name', 'private_topic_2_name',
u'Sólar power', 'Wind Power'], 'name'),
('name', 200, ['Coal Power', 'Nuclear Power', 'private_topic_1_name', 'private_topic_2_name',
u'Sólar power', 'Wind Power'], 'name'),
# Note that "Nuclear Power" and "Solar power" both have 2 teams. "Coal Power" and "Window Power"
# both have 0 teams. The secondary sort is alphabetical by name.
('team_count', 200, ['Nuclear Power', u'Sólar power', 'Coal Power', 'Wind Power'], 'team_count'),
('team_count', 200, ['Nuclear Power', u'Sólar power', 'Coal Power', 'private_topic_1_name',
'private_topic_2_name', 'Wind Power'], 'team_count'),
('no_such_field', 400, [], None),
)
@ddt.unpack

View File

@@ -419,6 +419,9 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
topic_id=topic_id
)
return Response(error, status=status.HTTP_400_BAD_REQUEST)
if course_module.teamsets_by_id[topic_id].is_private_managed:
result_filter.update({'membership__user__username': request.user})
result_filter.update({'topic_id': topic_id})
organization_protection_status = user_organization_protection_status(
@@ -467,7 +470,19 @@ class TeamsListView(ExpandableFieldViewMixin, GenericAPIView):
'open_slots': ('team_size', '-last_activity_at'),
'last_activity_at': ('-last_activity_at', 'team_size'),
}
queryset = CourseTeam.objects.filter(**result_filter)
if not has_access(request.user, 'staff', course_key):
# hide private_managed courses from non-admin users that aren't members of those teams
private_topic_ids = [ts.teamset_id for ts in course_module.teamsets if
ts.is_private_managed]
public_teams = CourseTeam.objects.filter(**result_filter).exclude(
topic_id__in=private_topic_ids)
private_managed_teams_of_user = CourseTeam.objects.filter(topic_id__in=private_topic_ids,
membership__user__username=request.user)
queryset = public_teams | private_managed_teams_of_user
else:
queryset = CourseTeam.objects.filter(**result_filter)
order_by_input = request.query_params.get('order_by', 'name')
if order_by_input not in ordering_schemes:
return Response(

View File

@@ -308,6 +308,13 @@ class TeamsetConfig(object):
except (KeyError, ValueError):
return TeamsetType.get_default()
@cached_property
def is_private_managed(self):
"""
Returns true if teamsettype is private_managed
"""
return self.teamset_type == TeamsetType.private_managed
class TeamsetType(Enum):
"""