Commit babd972c by Matt Drayer Committed by Jonathan Piacenti

mattdrayer/api-course-exists-check: Refactored course lookup logic

parent 7cab70b6
......@@ -474,7 +474,7 @@ class CoursesApiTests(TestCase):
def test_courses_groups_list_get(self):
test_uri = '{}/{}/groups'.format(self.base_courses_uri, self.test_course_id)
course_fail_uri = '{}/{}/groups'.format(self.base_courses_uri, '/ed/Open_DemoX/edx_demo_course')
course_fail_uri = '{}/{}/groups'.format(self.base_courses_uri, 'ed/Open_DemoX/edx_demo_course')
for i in xrange(2):
data_dict = {
'name': 'Alpha Group {}'.format(i), 'type': 'Programming',
......@@ -1311,7 +1311,6 @@ class CoursesApiTests(TestCase):
data = {'group_id': group_id}
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 201)
# Create another group and add it to course module
data = {'name': 'Beta Group', 'type': 'project'}
response = self.do_post(self.base_groups_uri, data)
......@@ -1320,7 +1319,6 @@ class CoursesApiTests(TestCase):
data = {'group_id': another_group_id}
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 201)
# create a 5 new users
for i in xrange(1, 6):
data = {
......@@ -1344,12 +1342,10 @@ class CoursesApiTests(TestCase):
data = {'user_id': created_user_id}
response = self.do_post(test_group_users_uri, data)
self.assertEqual(response.status_code, 201)
#enroll one user in Alpha Group and one in Beta Group created user
if i >= 2:
response = self.do_post(test_course_users_uri, data)
self.assertEqual(response.status_code, 201)
response = self.do_get('{}?enrolled={}'.format(test_uri_users, 'True'))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
......
......@@ -27,7 +27,7 @@ from student.roles import CourseRole, CourseAccessRole, CourseInstructorRole, Co
from xmodule.modulestore.django import modulestore
from api_manager.courseware_access import get_course, get_course_child, get_course_leaf_nodes
from api_manager.courseware_access import get_course, get_course_child, get_course_leaf_nodes, get_course_key, course_exists
from api_manager.models import CourseGroupRelationship, CourseContentGroupRelationship, GroupProfile, \
CourseModuleCompletion
from api_manager.permissions import SecureAPIView, SecureListAPIView
......@@ -387,7 +387,7 @@ class CourseContentList(SecureAPIView):
response_data = []
content_type = request.QUERY_PARAMS.get('type', None)
if course_id != content_id:
content_descriptor, content_key, content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
content_descriptor, content_key, content = get_course_child(request, request.user, course_key, content_id, load_content=True) # pylint: disable=W0612
else:
content = course_descriptor
if content:
......@@ -460,7 +460,7 @@ class CourseContentDetail(SecureAPIView):
response_data['uri'] = base_uri
if course_id != content_id:
element_name = 'children'
content_descriptor, content_key, content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
content_descriptor, content_key, content = get_course_child(request, request.user, course_key, content_id, load_content=True) # pylint: disable=W0612
else:
element_name = 'content'
protocol = 'http'
......@@ -666,9 +666,9 @@ class CoursesGroupsList(SecureAPIView):
response_data = {}
group_id = request.DATA['group_id']
base_uri = generate_base_uri(request)
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
try:
existing_group = Group.objects.get(id=group_id)
except ObjectDoesNotExist:
......@@ -695,12 +695,11 @@ class CoursesGroupsList(SecureAPIView):
"""
GET /api/courses/{course_id}/groups?type=workgroup
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
group_type = request.QUERY_PARAMS.get('type', None)
course_key = get_course_key(course_id)
course_groups = CourseGroupRelationship.objects.filter(course_id=course_key)
if group_type:
course_groups = course_groups.filter(group__groupprofile__group_type=group_type)
response_data = []
......@@ -727,14 +726,14 @@ class CoursesGroupsDetail(SecureAPIView):
"""
GET /api/courses/{course_id}/groups/{group_id}
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
try:
existing_group = Group.objects.get(id=group_id)
except ObjectDoesNotExist:
return Response({}, status=status.HTTP_404_NOT_FOUND)
try:
course_key = get_course_key(course_id)
CourseGroupRelationship.objects.get(course_id=course_key, group=existing_group)
except ObjectDoesNotExist:
return Response({}, status=status.HTTP_404_NOT_FOUND)
......@@ -749,11 +748,11 @@ class CoursesGroupsDetail(SecureAPIView):
"""
DELETE /api/courses/{course_id}/groups/{group_id}
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_204_NO_CONTENT)
try:
existing_group = Group.objects.get(id=group_id)
course_key = get_course_key(course_id)
CourseGroupRelationship.objects.get(course_id=course_key, group=existing_group).delete()
except ObjectDoesNotExist:
pass
......@@ -994,9 +993,9 @@ class CoursesUsersList(SecureAPIView):
"""
POST /api/courses/{course_id}/users
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
if 'user_id' in request.DATA:
user_id = request.DATA['user_id']
try:
......@@ -1034,9 +1033,9 @@ class CoursesUsersList(SecureAPIView):
response_data = OrderedDict()
base_uri = generate_base_uri(request)
response_data['uri'] = base_uri
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
# Get a list of all enrolled students
users = CourseEnrollment.users_enrolled_in(course_key)
upper_bound = getattr(settings, 'API_LOOKUP_UPPER_BOUND', 100)
......@@ -1106,7 +1105,7 @@ class CoursesUsersDetail(SecureAPIView):
user = User.objects.get(id=user_id, is_active=True)
except ObjectDoesNotExist:
return Response(response_data, status=status.HTTP_404_NOT_FOUND)
course_descriptor, course_key, course_content = get_course(request, user, course_id)
course_descriptor, course_key, course_content = get_course(request, user, course_id, load_content=True)
if not course_descriptor:
return Response(response_data, status=status.HTTP_404_NOT_FOUND)
if CourseEnrollment.is_enrolled(user, course_key):
......@@ -1124,9 +1123,9 @@ class CoursesUsersDetail(SecureAPIView):
user = User.objects.get(id=user_id, is_active=True)
except ObjectDoesNotExist:
return Response({}, status=status.HTTP_204_NO_CONTENT)
course_descriptor, course_key, course_content = get_course(request, user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
CourseEnrollment.unenroll(user, course_key)
response_data = {}
base_uri = generate_base_uri(request)
......@@ -1157,11 +1156,11 @@ class CourseContentGroupsList(SecureAPIView):
"""
POST /api/courses/{course_id}/content/{content_id}/groups
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_404_NOT_FOUND)
group_id = request.DATA.get('group_id')
if group_id is None:
......@@ -1174,12 +1173,12 @@ class CourseContentGroupsList(SecureAPIView):
base_uri = generate_base_uri(request)
response_data['uri'] = '{}/{}'.format(base_uri, existing_profile.group_id)
response_data['course_id'] = unicode(course_key)
response_data['content_id'] = unicode(existing_content.scope_ids.usage_id)
response_data['content_id'] = unicode(content_key)
response_data['group_id'] = str(existing_profile.group_id)
try:
CourseContentGroupRelationship.objects.get(
course_id=course_key,
content_id=existing_content.location,
content_id=content_key,
group_profile=existing_profile
)
response_data['message'] = "Relationship already exists."
......@@ -1187,7 +1186,7 @@ class CourseContentGroupsList(SecureAPIView):
except ObjectDoesNotExist:
CourseContentGroupRelationship.objects.create(
course_id=course_key,
content_id=existing_content.location,
content_id=content_key,
group_profile=existing_profile
)
return Response(response_data, status=status.HTTP_201_CREATED)
......@@ -1198,15 +1197,15 @@ class CourseContentGroupsList(SecureAPIView):
"""
response_data = []
group_type = request.QUERY_PARAMS.get('type')
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_404_NOT_FOUND)
relationships = CourseContentGroupRelationship.objects.filter(
course_id=course_key,
content_id=existing_content.location,
content_id=content_key,
).select_related("groupprofile")
if group_type:
relationships = relationships.filter(group_profile__group_type=group_type)
......@@ -1230,16 +1229,16 @@ class CourseContentGroupsDetail(SecureAPIView):
"""
GET /api/courses/{course_id}/content/{content_id}/groups/{group_id}
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_404_NOT_FOUND)
try:
CourseContentGroupRelationship.objects.get(
course_id=course_key,
content_id=existing_content.location,
content_id=content_key,
group_profile__group_id=group_id
)
except ObjectDoesNotExist:
......@@ -1271,17 +1270,17 @@ class CourseContentUsersList(SecureAPIView):
"""
GET /api/courses/{course_id}/content/{content_id}/users
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_404_NOT_FOUND)
enrolled = self.request.QUERY_PARAMS.get('enrolled', 'True')
group_type = self.request.QUERY_PARAMS.get('type', None)
group_id = self.request.QUERY_PARAMS.get('group_id', None)
relationships = CourseContentGroupRelationship.objects.filter(
course_id=course_key, content_id=existing_content.location).select_related("groupprofile")
course_id=course_key, content_id=content_key).select_related("groupprofile")
if group_id:
relationships = relationships.filter(group_profile__group__id=group_id)
......@@ -1351,9 +1350,9 @@ class CourseModuleCompletionList(SecureListAPIView):
content_id = self.request.QUERY_PARAMS.get('content_id', None)
stage = self.request.QUERY_PARAMS.get('stage', None)
course_id = self.kwargs['course_id']
course_descriptor, course_key, course_content = get_course(self.request, self.request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(self.request, self.request.user, course_id):
raise Http404
course_key = get_course_key(course_id)
queryset = CourseModuleCompletion.objects.filter(course_id=course_key)
upper_bound = getattr(settings, 'API_LOOKUP_UPPER_BOUND', 100)
if user_ids:
......@@ -1362,9 +1361,9 @@ class CourseModuleCompletionList(SecureListAPIView):
if content_id:
content_descriptor, content_key, existing_content = get_course_child(self.request, self.request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
raise Http404
queryset = queryset.filter(content_id=existing_content.location)
queryset = queryset.filter(content_id=content_key)
if stage:
queryset = queryset.filter(stage=stage)
......@@ -1382,16 +1381,16 @@ class CourseModuleCompletionList(SecureListAPIView):
return Response({'message': _('content_id is missing')}, status.HTTP_400_BAD_REQUEST)
if not user_id:
return Response({'message': _('user_id is missing')}, status.HTTP_400_BAD_REQUEST)
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({'message': _('content_id is invalid')}, status.HTTP_400_BAD_REQUEST)
completion, created = CourseModuleCompletion.objects.get_or_create(user_id=user_id,
course_id=course_key,
content_id=existing_content.location,
content_id=content_key,
stage=stage)
serializer = CourseModuleCompletionSerializer(completion)
if created:
......@@ -1413,9 +1412,9 @@ class CoursesGradesList(SecureListAPIView):
"""
GET /api/courses/{course_id}/grades?user_ids=1,2&content_ids=i4x://1/2/3,i4x://a/b/c
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
queryset = StudentModule.objects.filter(
course_id__exact=course_key,
grade__isnull=False,
......@@ -1432,9 +1431,9 @@ class CoursesGradesList(SecureListAPIView):
content_id = self.request.QUERY_PARAMS.get('content_id', None)
if content_id:
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_400_BAD_REQUEST)
queryset = queryset.filter(module_state_key=existing_content.location)
queryset = queryset.filter(module_state_key=content_key)
queryset_grade_avg = queryset.aggregate(Avg('grade'))
queryset_grade_sum = queryset.aggregate(Sum('grade'))
......@@ -1478,7 +1477,7 @@ class CoursesProjectList(SecureListAPIView):
def get_queryset(self):
course_id = self.kwargs['course_id']
course_descriptor, course_key, course_content = get_course(self.request, self.request.user, course_id) # pylint: disable=W0612
course_key = get_course_key(course_id)
return Project.objects.filter(course_id=course_key)
......@@ -1495,9 +1494,9 @@ class CourseMetrics(SecureAPIView):
"""
GET /api/courses/{course_id}/metrics/
"""
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
users_enrolled = CourseEnrollment.num_enrolled_in(course_key)
data = {
'users_enrolled': users_enrolled
......@@ -1530,10 +1529,9 @@ class CoursesLeadersList(SecureListAPIView):
count = self.request.QUERY_PARAMS.get('count', 3)
data = {}
course_avg = 0
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
exclude_users = _get_aggregate_exclusion_user_ids(course_key)
queryset = StudentModule.objects.filter(
course_id__exact=course_key,
......@@ -1545,9 +1543,9 @@ class CoursesLeadersList(SecureListAPIView):
if content_id:
content_descriptor, content_key, existing_content = get_course_child(request, request.user, course_key, content_id) # pylint: disable=W0612
if not existing_content:
if not content_descriptor:
return Response({}, status=status.HTTP_400_BAD_REQUEST)
queryset = queryset.filter(module_state_key=existing_content.location)
queryset = queryset.filter(module_state_key=content_key)
if user_id:
user_points = StudentModule.objects.filter(course_id__exact=course_key,
......@@ -1600,10 +1598,9 @@ class CoursesCompletionsLeadersList(SecureAPIView):
count = self.request.QUERY_PARAMS.get('count', 3)
data = {}
course_avg = 0
course_descriptor, course_key, course_content = get_course(request, request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_key = get_course_key(course_id)
total_possible_completions = len(get_course_leaf_nodes(course_key,
['discussion-course', 'group-project']))
exclude_users = _get_aggregate_exclusion_user_ids(course_key)
......@@ -1647,8 +1644,7 @@ class CoursesWorkgroupsList(SecureListAPIView):
def get_queryset(self):
course_id = self.kwargs['course_id']
course_descriptor, course_key, course_content = get_course(self.request, self.request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(self.request, self.request.user, course_id):
raise Http404
queryset = Workgroup.objects.filter(project__course_id=course_id)
......@@ -1712,10 +1708,9 @@ class CoursesCitiesMetrics(SecureListAPIView):
course_id = self.kwargs['course_id']
city = self.request.QUERY_PARAMS.get('city', None)
upper_bound = getattr(settings, 'API_LOOKUP_UPPER_BOUND', 100)
course_descriptor, course_key, course_content = get_course(self.request, self.request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(self.request, self.request.user, course_id):
raise Http404
course_key = get_course_key(course_id)
exclude_users = _get_aggregate_exclusion_user_ids(course_key)
queryset = CourseEnrollment.users_enrolled_in(course_key).exclude(id__in=exclude_users)
if city:
......@@ -1745,12 +1740,11 @@ class CoursesRolesList(SecureAPIView):
GET /api/courses/{course_id}/roles/
"""
course_id = self.kwargs['course_id']
course_descriptor, course_key, course_content = get_course(self.request, self.request.user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, request.user, course_id):
raise Http404
response_data = []
course_key = get_course_key(course_id)
instructors = CourseInstructorRole(course_key).users_with_role()
for instructor in instructors:
response_data.append({'id': instructor.id, 'role': 'instructor'})
......
......@@ -10,64 +10,32 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
def get_course(request, user, course_id, depth=0):
def get_course(request, user, course_id, depth=0, load_content=False):
"""
Utility method to obtain course components
"""
course_descriptor = None
course_key = None
course_content = None
try:
course_key = CourseKey.from_string(course_id)
except InvalidKeyError:
try:
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
except InvalidKeyError:
pass
course_key = get_course_key(course_id)
if course_key:
try:
course_descriptor = courses.get_course(course_key, depth)
except ValueError:
pass
if course_descriptor:
field_data_cache = FieldDataCache([course_descriptor], course_key, user)
course_content = module_render.get_module_for_descriptor(
user,
request,
course_descriptor,
field_data_cache,
course_key)
course_descriptor = get_course_descriptor(course_key, depth)
if course_descriptor and load_content:
course_content = get_course_content(request, user, course_key, course_descriptor)
return course_descriptor, course_key, course_content
def get_course_child(request, user, course_key, content_id):
def get_course_child(request, user, course_key, content_id, load_content=False):
"""
Return a course xmodule/xblock to the caller
"""
content_descriptor = None
content_key = None
content = None
try:
content_key = UsageKey.from_string(content_id)
except InvalidKeyError:
try:
content_key = Location.from_deprecated_string(content_id)
except (InvalidLocationError, InvalidKeyError):
pass
if content_key:
try:
content_descriptor = modulestore().get_item(content_key)
except ItemNotFoundError:
pass
if content_descriptor:
field_data_cache = FieldDataCache([content_descriptor], course_key, user)
content = module_render.get_module_for_descriptor(
user,
request,
content_descriptor,
field_data_cache,
course_key)
return content_descriptor, content_key, content
child_descriptor = None
child_content = None
child_key = get_course_child_key(content_id)
if child_key:
child_descriptor = get_course_child_descriptor(child_key)
if child_descriptor and load_content:
child_content = get_course_child_content(request, user, course_key, child_descriptor)
return child_descriptor, child_key, child_content
def get_course_total_score(course_summary):
......@@ -92,3 +60,72 @@ def get_course_leaf_nodes(course_key, detached_categories):
nodes.extend([unit.location for unit in vertical.get_children()
if getattr(unit, 'category') not in detached_categories])
return nodes
def get_course_key(course_id):
try:
course_key = CourseKey.from_string(course_id)
except InvalidKeyError:
try:
course_key = SlashSeparatedCourseKey.from_deprecated_string(course_id)
except InvalidKeyError:
course_key = None
return course_key
def get_course_descriptor(course_key, depth):
try:
course_descriptor = courses.get_course(course_key, depth)
except ValueError:
course_descriptor = None
return course_descriptor
def get_course_content(request, user, course_key, course_descriptor):
field_data_cache = FieldDataCache([course_descriptor], course_key, user)
course_content = module_render.get_module_for_descriptor(
user,
request,
course_descriptor,
field_data_cache,
course_key)
return course_content
def course_exists(request, user, course_id):
course_key = get_course_key(course_id)
if not course_key:
return False
if not modulestore().has_course(course_key):
return False
return True
def get_course_child_key(content_id):
try:
content_key = UsageKey.from_string(content_id)
except InvalidKeyError:
try:
content_key = Location.from_deprecated_string(content_id)
except (InvalidLocationError, InvalidKeyError):
content_key = None
return content_key
def get_course_child_descriptor(child_key):
try:
content_descriptor = modulestore().get_item(child_key)
except ItemNotFoundError:
content_descriptor = None
return content_descriptor
def get_course_child_content(request, user, course_key, child_descriptor):
field_data_cache = FieldDataCache([child_descriptor], course_key, user)
child_content = module_render.get_module_for_descriptor(
user,
request,
child_descriptor,
field_data_cache,
course_key)
return child_content
......@@ -22,7 +22,7 @@ from capa.tests.response_xml_factory import StringResponseXMLFactory
from courseware.tests.factories import StudentModuleFactory
from django_comment_common.models import Role, FORUM_ROLE_MODERATOR
from instructor.access import allow_access
from projects.models import Project
from projects.models import Project, Workgroup
from student.tests.factories import UserFactory
from student.models import anonymous_id_for_user
from xmodule.modulestore.tests.django_utils import ModuleStoreTestCase
......@@ -60,6 +60,7 @@ class UsersApiTests(ModuleStoreTestCase):
self.groups_base_uri = '/api/server/groups'
self.org_base_uri = '/api/server/organizations/'
self.workgroups_base_uri = '/api/server/workgroups/'
self.projects_base_uri = '/api/server/projects/'
self.users_base_uri = '/api/server/users'
self.sessions_base_uri = '/api/server/sessions'
self.test_bogus_course_id = 'foo/bar/baz'
......@@ -1251,47 +1252,46 @@ class UsersApiTests(ModuleStoreTestCase):
def test_user_workgroups_list(self):
test_workgroups_uri = self.workgroups_base_uri
user_id = self.user.id
# create anonymous user
anonymous_id = anonymous_id_for_user(self.user, self.course.id)
for i in xrange(1, 12):
course = CourseFactory.create(
display_name="TEST COURSE {}".format(i),
)
course_content = ItemFactory.create(
category="videosequence",
parent_location=course.location,
data=self.test_course_data,
display_name="View_Sequence"
)
project_1 = Project.objects.create(
course_id=unicode(self.course.id),
content_id=unicode(self.course_content.scope_ids.usage_id),
)
p1_workgroup_1 = Workgroup.objects.create(
name = 'Workgroup 1',
project = project_1
)
test_project = Project.objects.create(
course_id=unicode(course.id),
content_id=unicode(course_content.scope_ids.usage_id)
)
data = {
'name': 'Workgroup ' + str(i),
'project': test_project.id
}
response = self.do_post(test_workgroups_uri, data)
self.assertEqual(response.status_code, 201)
test_uri = '{}{}/'.format(test_workgroups_uri, str(response.data['id']))
users_uri = '{}users/'.format(test_uri)
data = {"id": user_id}
project_2 = Project.objects.create(
course_id=unicode(self.course2.id),
content_id=unicode(self.course2_content.scope_ids.usage_id),
)
p2_workgroup_1 = Workgroup.objects.create(
name = 'Workgroup 2',
project = project_2
)
for i in xrange(1,12):
test_user = UserFactory()
users_uri = '{}{}/users/'.format(self.workgroups_base_uri, 1)
data = {"id": test_user.id}
response = self.do_post(users_uri, data)
self.assertEqual(response.status_code, 201)
if test_user.id > 6:
users_uri = '{}{}/users/'.format(self.workgroups_base_uri, 2)
data = {"id": test_user.id}
response = self.do_post(users_uri, data)
self.assertEqual(response.status_code, 201)
# test with anonymous user id
test_uri = '{}/{}/workgroups/?page_size=10'.format(self.users_base_uri, anonymous_id)
anonymous_id = anonymous_id_for_user(test_user, self.course.id)
test_uri = '{}/{}/workgroups/?page_size=1'.format(self.users_base_uri, anonymous_id)
response = self.do_get(test_uri)
self.assertEqual(response.data['count'], 11)
self.assertEqual(len(response.data['results']), 10)
self.assertEqual(response.data['count'], 2)
self.assertEqual(len(response.data['results']), 1)
self.assertEqual(response.data['num_pages'], 2)
# test with course_id filter and integer user id
course_id = {'course_id': unicode(course.id)}
response = self.do_get('{}/{}/workgroups/?{}'.format(self.users_base_uri, user_id, urlencode(course_id)))
course_id = {'course_id': unicode(self.course.id)}
response = self.do_get('{}/{}/workgroups/?{}'.format(self.users_base_uri, test_user.id, urlencode(course_id)))
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['count'], 1)
self.assertEqual(len(response.data['results']), 1)
......
......@@ -34,7 +34,7 @@ from util.password_policy_validators import (
)
from api_manager.courses.serializers import CourseModuleCompletionSerializer
from api_manager.courseware_access import get_course, get_course_child, get_course_total_score
from api_manager.courseware_access import get_course, get_course_child, get_course_total_score, get_course_key, course_exists
from api_manager.permissions import SecureAPIView, SecureListAPIView, IdsInFilterBackend, HasOrgsFilterBackend
from api_manager.models import GroupProfile, APIUser as User
from api_manager.organizations.serializers import OrganizationSerializer
......@@ -90,10 +90,9 @@ def _save_content_position(request, user, course_key, position):
parent_content_id = position['parent_content_id']
child_content_id = position['child_content_id']
if unicode(course_key) == parent_content_id:
parent_descriptor, parent_key, parent_content = get_course(request, user, parent_content_id) # pylint: disable=W0612
parent_descriptor, parent_key, parent_content = get_course(request, user, parent_content_id, load_content=True) # pylint: disable=W0612
else:
parent_descriptor, parent_key, parent_content = get_course_child(request, user, course_key, parent_content_id) # pylint: disable=W0612
parent_descriptor, parent_key, parent_content = get_course_child(request, user, course_key, parent_content_id, load_content=True) # pylint: disable=W0612
if not parent_descriptor:
return None
......@@ -126,8 +125,7 @@ def _save_child_position(parent_descriptor, target_child_location):
# Only save if position changed
if position != parent_descriptor.position:
parent_descriptor.position = position
# Save this new position to the underlying KeyValueStore
parent_descriptor.save()
parent_descriptor.save()
def _manage_role(course_descriptor, user, role, action):
......@@ -807,13 +805,13 @@ class UsersCoursesDetail(SecureAPIView):
user = User.objects.get(id=user_id, is_active=True)
except ObjectDoesNotExist:
return Response({}, status=status.HTTP_404_NOT_FOUND)
course_descriptor, course_key, course_content = get_course(request, user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, user, course_id):
return Response({}, status=status.HTTP_404_NOT_FOUND)
response_data['user_id'] = user.id
response_data['course_id'] = course_id
if request.DATA['positions']:
course_key = get_course_key(course_id)
response_data['positions'] = []
for position in request.DATA['positions']:
content_position = _save_content_position(
......@@ -865,7 +863,7 @@ class UsersCoursesDetail(SecureAPIView):
response_data['position_tree'][current_child_loc.category] = {}
response_data['position_tree'][current_child_loc.category]['id'] = unicode(current_child_loc)
_,_,parent_module = get_course_child(request, user, course_key, unicode(current_child_loc))
_,_,parent_module = get_course_child(request, user, course_key, unicode(current_child_loc), load_content=True)
else:
parent_module = None
......@@ -879,9 +877,9 @@ class UsersCoursesDetail(SecureAPIView):
user = User.objects.get(id=user_id, is_active=True)
except ObjectDoesNotExist:
return Response({}, status=status.HTTP_204_NO_CONTENT)
course_descriptor, course_key, course_content = get_course(request, user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(request, user, course_id):
return Response({}, status=status.HTTP_204_NO_CONTENT)
course_key = get_course_key(course_id)
CourseEnrollment.unenroll(user, course_key)
return Response({}, status=status.HTTP_204_NO_CONTENT)
......@@ -1234,9 +1232,9 @@ class UsersRolesList(SecureListAPIView):
course_id = self.request.QUERY_PARAMS.get('course_id', None)
if course_id:
course_descriptor, course_key, course_content = get_course(self.request, user, course_id) # pylint: disable=W0612
if not course_descriptor:
if not course_exists(self.request, user, course_id):
raise Http404
course_key = get_course_key(course_id)
queryset = queryset.filter(course_id=course_key)
role = self.request.QUERY_PARAMS.get('role', None)
......
......@@ -30,7 +30,7 @@ from .serializers import ProjectSerializer, WorkgroupSerializer, WorkgroupSubmis
from .serializers import WorkgroupReviewSerializer, WorkgroupSubmissionReviewSerializer, WorkgroupPeerReviewSerializer
def _get_course(request, user, course_id, depth=0):
def _get_course(request, user, course_id, depth=0, load_content=False):
"""
Utility method to obtain course components
"""
......@@ -49,7 +49,7 @@ def _get_course(request, user, course_id, depth=0):
course_descriptor = get_course(course_key, depth=depth)
except ValueError:
pass
if course_descriptor:
if course_descriptor and load_content:
field_data_cache = FieldDataCache([course_descriptor], course_key, user)
course_content = module_render.get_module(
user,
......@@ -60,7 +60,7 @@ def _get_course(request, user, course_id, depth=0):
return course_descriptor, course_key, course_content
def _get_course_child(request, user, course_key, content_id):
def _get_course_child(request, user, course_key, content_id, load_content=False):
"""
Return a course xmodule/xblock to the caller
"""
......@@ -77,7 +77,7 @@ def _get_course_child(request, user, course_key, content_id):
if content_key:
store = modulestore()
content_descriptor = store.get_item(content_key)
if content_descriptor:
if content_descriptor and load_content:
field_data_cache = FieldDataCache([content_descriptor], course_key, user)
content = module_render.get_module(
user,
......
......@@ -500,3 +500,11 @@ PROFILE_IMAGE_MIN_BYTES = 100
FEATURES['ENABLE_LTI_PROVIDER'] = True
INSTALLED_APPS += ('lti_provider',)
AUTHENTICATION_BACKENDS += ('lti_provider.users.LtiBackend',)
########################## SECURITY #######################
FEATURES['ENFORCE_PASSWORD_POLICY'] = False
FEATURES['ENABLE_MAX_FAILED_LOGIN_ATTEMPTS'] = False
FEATURES['SQUELCH_PII_IN_LOGS'] = False
FEATURES['PREVENT_CONCURRENT_LOGINS'] = False
FEATURES['ADVANCED_SECURITY'] = False
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