Commit 226fcd72 by Matt Drayer Committed by Jonathan Piacenti

mattdrayer/api-moderator-role-valiation: Confirm add/remove of role

parent 4076d976
......@@ -11,6 +11,7 @@ from urllib import urlencode
from django.contrib.auth.models import Group
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.test import TestCase, Client
from django.test.utils import override_settings
......@@ -1476,7 +1477,6 @@ class CoursesApiTests(TestCase):
def test_coursemodulecompletions_get_invalid_course(self):
completion_uri = '{}/{}/completions/'.format(self.base_courses_uri, self.test_bogus_course_id)
print completion_uri
response = self.do_get(completion_uri)
self.assertEqual(response.status_code, 404)
......@@ -1796,11 +1796,23 @@ class CoursesApiTests(TestCase):
# filter roleset by user
user_id = {'user_id': '{}'.format(self.users[0].id)}
test_uri = '{}?{}'.format(test_uri, urlencode(user_id))
response = self.do_get(test_uri)
user_filter_uri = '{}?{}'.format(test_uri, urlencode(user_id))
response = self.do_get(user_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
# filter roleset by role
role = {'role': 'instructor'}
role_filter_uri = '{}?{}'.format(test_uri, urlencode(role))
response = self.do_get(role_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
role = {'role': 'invalid_role'}
role_filter_uri = '{}?{}'.format(test_uri, urlencode(role))
response = self.do_get(role_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)
def test_courses_roles_list_get_invalid_course(self):
test_uri = '/api/courses/{}/roles/'.format(self.test_bogus_course_id)
response = self.do_get(test_uri)
......@@ -1819,6 +1831,11 @@ class CoursesApiTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
# Confirm this user also has forum moderation permissions
role = Role.objects.get(course_id=self.course.id, name=FORUM_ROLE_MODERATOR)
has_role = role.users.get(id=self.users[0].id)
self.assertTrue(has_role)
def test_courses_roles_list_post_invalid_course(self):
test_uri = '/api/courses/{}/roles/'.format(self.test_bogus_course_id)
data = {'user_id': self.users[0].id, 'role': 'instructor'}
......@@ -1844,17 +1861,23 @@ class CoursesApiTests(TestCase):
self.assertEqual(response.status_code, 201)
response = self.do_get(test_uri)
print response.data
self.assertEqual(len(response.data), 1)
delete_uri = '{}instructor/users/{}'.format(test_uri, self.users[0].id)
print delete_uri
response = self.do_delete(delete_uri)
self.assertEqual(response.status_code, 204)
response = self.do_get(test_uri)
self.assertEqual(len(response.data), 0)
# Confirm this user no longer has forum moderation permissions
role = Role.objects.get(course_id=self.course.id, name=FORUM_ROLE_MODERATOR)
try:
has_role = role.users.get(id=self.users[0].id)
self.assertTrue(False)
except ObjectDoesNotExist:
pass
def test_courses_roles_users_detail_delete_invalid_course(self):
test_uri = '/api/courses/{}/roles/'.format(self.test_bogus_course_id)
delete_uri = '{}instructor/users/{}'.format(test_uri, self.users[0].id)
......@@ -1870,6 +1893,5 @@ class CoursesApiTests(TestCase):
def test_courses_roles_users_detail_delete_invalid_role(self):
test_uri = '/api/courses/{}/roles/'.format(unicode(self.course.id))
delete_uri = '{}invalid_role/users/{}'.format(test_uri, self.users[0].id)
print delete_uri
response = self.do_delete(delete_uri)
self.assertEqual(response.status_code, 404)
......@@ -6,7 +6,6 @@ import itertools
from lxml import etree
from StringIO import StringIO
from django.conf import settings
from django.contrib.auth.models import Group, User
from django.core.exceptions import ObjectDoesNotExist
......@@ -22,9 +21,9 @@ from courseware.courses import get_course_about_section, get_course_info_section
from courseware.models import StudentModule
from courseware.views import get_static_tab_contents
from django_comment_common.models import FORUM_ROLE_MODERATOR
from instructor.access import allow_access, revoke_access, update_forum_role
from instructor.access import revoke_access, update_forum_role
from student.models import CourseEnrollment, CourseEnrollmentAllowed
from student.roles import CourseInstructorRole, CourseStaffRole, CourseObserverRole, UserBasedRole
from student.roles import CourseAccessRole, CourseInstructorRole, CourseStaffRole, CourseObserverRole, UserBasedRole
from xmodule.modulestore.django import modulestore
......@@ -279,24 +278,30 @@ def _manage_role(course_descriptor, user, role, action):
"""
Helper method for managing course/forum roles
"""
supported_roles = ('instructor', 'staff', 'observer')
forum_moderator_roles = ('instructor', 'staff')
if role not in supported_roles:
raise ValueError
if action is 'allow':
allow_access(course_descriptor, user, role)
existing_role = CourseAccessRole.objects.filter(user=user, role=role, course_id=course_descriptor.id, org=course_descriptor.org)
if not existing_role:
new_role = CourseAccessRole(user=user, role=role, course_id=course_descriptor.id, org=course_descriptor.org)
new_role.save()
if role in forum_moderator_roles:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'allow')
elif action is 'revoke':
revoke_access(course_descriptor, user, role)
if role in forum_moderator_roles:
# There's a possibilty that the user may play more than one role in a course
# And that more than one of these roles allow for forum moderation
# So we need to confirm the current role is the only one for this user for this course
# So we need to confirm the removed role was the only role for this user for this course
# Before we can safely remove the corresponding forum moderator role
user_instructor_courses = UserBasedRole(user, CourseInstructorRole.ROLE).courses_with_role()
user_staff_courses = UserBasedRole(user, CourseStaffRole.ROLE).courses_with_role()
queryset = user_instructor_courses | user_staff_courses
queryset = queryset.filter(course_id=course_descriptor.id)
if len(queryset) <= 1:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'allow')
revoke_access(course_descriptor, user, role)
if len(queryset) == 0:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'revoke')
class CourseContentList(SecureAPIView):
......@@ -1329,7 +1334,6 @@ class CourseModuleCompletionList(SecureListAPIView):
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
print course_descriptor
if not course_descriptor:
raise Http404
queryset = CourseModuleCompletion.objects.filter(course_id=course_key)
......@@ -1712,6 +1716,10 @@ class CoursesRolesList(SecureAPIView):
if user_id:
response_data = list([item for item in response_data if int(item['id']) == int(user_id)])
role = self.request.QUERY_PARAMS.get('role', None)
if role:
response_data = list([item for item in response_data if item['role'] == role])
return Response(response_data, status=status.HTTP_200_OK)
def post(self, request, course_id):
......
......@@ -893,7 +893,6 @@ class GroupsApiTests(ModuleStoreTestCase):
response = self.do_post(test_uri, data)
self.assertEqual(response.status_code, 201)
test_uri = '{}/{}/courses/{}'.format(self.base_groups_uri, group_id, self.test_course_id)
print test_uri
response = self.do_get(test_uri)
self.assertEqual(response.status_code, 200)
confirm_uri = '{}{}/{}/courses/{}'.format(
......
......@@ -12,10 +12,11 @@ import uuid
from urllib import urlencode
from mock import patch
from django.utils.translation import ugettext as _
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist
from django.test import Client
from django.test.utils import override_settings
from django.utils.translation import ugettext as _
from capa.tests.response_xml_factory import StringResponseXMLFactory
from courseware.tests.factories import StudentModuleFactory
......@@ -1385,11 +1386,23 @@ class UsersApiTests(ModuleStoreTestCase):
# filter roleset by course
course_id = {'course_id': '{}'.format(unicode(course3.id))}
test_uri = '{}?{}'.format(test_uri, urlencode(course_id))
response = self.do_get(test_uri)
course_filter_uri = '{}?{}'.format(test_uri, urlencode(course_id))
response = self.do_get(course_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['count'], 1)
# filter roleset by role
role = {'role': 'instructor'}
role_filter_uri = '{}?{}'.format(test_uri, urlencode(role))
response = self.do_get(role_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['count'], 1)
role = {'role': 'invalid_role'}
role_filter_uri = '{}?{}'.format(test_uri, urlencode(role))
response = self.do_get(role_filter_uri)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['count'], 0)
def test_users_roles_list_get_invalid_user(self):
test_uri = '/api/users/23423/roles/'
response = self.do_get(test_uri)
......@@ -1415,6 +1428,11 @@ class UsersApiTests(ModuleStoreTestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data['count'], 1)
# Confirm this user also has forum moderation permissions
role = Role.objects.get(course_id=self.course.id, name=FORUM_ROLE_MODERATOR)
has_role = role.users.get(id=self.user.id)
self.assertTrue(has_role)
def test_users_roles_list_post_invalid_user(self):
test_uri = '/api/users/2131/roles/'
data = {'course_id': unicode(self.course.id), 'role': 'instructor'}
......@@ -1525,6 +1543,14 @@ class UsersApiTests(ModuleStoreTestCase):
response = self.do_get(test_uri)
self.assertEqual(response.data['count'], 0)
# Confirm this user no longer has forum moderation permissions
role = Role.objects.get(course_id=self.course.id, name=FORUM_ROLE_MODERATOR)
try:
has_role = role.users.get(id=self.user.id)
self.assertTrue(False)
except ObjectDoesNotExist:
pass
def test_users_roles_courses_detail_delete_invalid_course(self):
test_uri = '/api/users/{}/roles/'.format(self.user.id)
delete_uri = '{}instructor/courses/{}'.format(test_uri, self.test_bogus_course_id)
......
......@@ -20,14 +20,13 @@ from courseware.model_data import FieldDataCache
from courseware.models import StudentModule
from courseware.views import save_child_position, get_current_child
from django_comment_common.models import FORUM_ROLE_MODERATOR
from instructor.access import allow_access, revoke_access, update_forum_role
from instructor.access import revoke_access, update_forum_role
from lang_pref import LANGUAGE_KEY
from lms.lib.comment_client.user import User as CommentUser
from lms.lib.comment_client.utils import CommentClientRequestError
from student.models import CourseEnrollment, PasswordHistory, UserProfile
from openedx.core.djangoapps.user_api.models import UserPreference
from student.roles import CourseInstructorRole, CourseStaffRole, UserBasedRole
from student.roles import CourseInstructorRole, CourseObserverRole, CourseStaffRole, UserBasedRole
from student.roles import CourseAccessRole, CourseInstructorRole, CourseObserverRole, CourseStaffRole, UserBasedRole
from util.bad_request_rate_limiter import BadRequestRateLimiter
from util.password_policy_validators import (
validate_password_length, validate_password_complexity,
......@@ -99,24 +98,30 @@ def _manage_role(course_descriptor, user, role, action):
"""
Helper method for managing course/forum roles
"""
supported_roles = ('instructor', 'staff', 'observer')
forum_moderator_roles = ('instructor', 'staff')
if role not in supported_roles:
raise ValueError
if action is 'allow':
allow_access(course_descriptor, user, role)
existing_role = CourseAccessRole.objects.filter(user=user, role=role, course_id=course_descriptor.id, org=course_descriptor.org)
if not existing_role:
new_role = CourseAccessRole(user=user, role=role, course_id=course_descriptor.id, org=course_descriptor.org)
new_role.save()
if role in forum_moderator_roles:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'allow')
elif action is 'revoke':
revoke_access(course_descriptor, user, role)
if role in forum_moderator_roles:
# There's a possibilty that the user may play more than one role in a course
# And that more than one of these roles allow for forum moderation
# So we need to confirm the current role is the only one for this user for this course
# So we need to confirm the removed role was the only role for this user for this course
# Before we can safely remove the corresponding forum moderator role
user_instructor_courses = UserBasedRole(user, CourseInstructorRole.ROLE).courses_with_role()
user_staff_courses = UserBasedRole(user, CourseStaffRole.ROLE).courses_with_role()
queryset = user_instructor_courses | user_staff_courses
queryset = queryset.filter(course_id=course_descriptor.id)
if len(queryset) == 1:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'allow')
revoke_access(course_descriptor, user, role)
if len(queryset) == 0:
update_forum_role(course_descriptor.id, user, FORUM_ROLE_MODERATOR, 'revoke')
class UsersList(SecureListAPIView):
......@@ -1139,6 +1144,10 @@ class UsersRolesList(SecureListAPIView):
raise Http404
queryset = queryset.filter(course_id=course_key)
role = self.request.QUERY_PARAMS.get('role', None)
if role:
queryset = queryset.filter(role=role)
return queryset
def post(self, request, user_id):
......@@ -1216,9 +1225,7 @@ class UsersRolesCoursesDetail(SecureAPIView):
return Response({}, status=status.HTTP_404_NOT_FOUND)
try:
revoke_access(course_descriptor, user, role)
if role in ('instructor', 'staff'):
update_forum_role(course_key, user, FORUM_ROLE_MODERATOR, 'revoke')
_manage_role(course_descriptor, user, role, 'revoke')
except ValueError:
return Response({}, status=status.HTTP_404_NOT_FOUND)
......
......@@ -172,7 +172,7 @@ class WorkgroupsApiTests(ModuleStoreTestCase):
response.data['id'],
self.test_workgroup_name
)
cohort = get_cohort_by_name(self.test_project.course_id, cohort_name, CourseUserGroup.WORKGROUP)
cohort = get_cohort_by_name(self.test_course.id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertIsNotNone(cohort)
def test_workgroups_detail_get(self):
......@@ -266,7 +266,7 @@ class WorkgroupsApiTests(ModuleStoreTestCase):
response.data['id'],
self.test_workgroup_name
)
cohort = get_cohort_by_name(self.test_project.course_id, cohort_name, CourseUserGroup.WORKGROUP)
cohort = get_cohort_by_name(self.test_course.id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertIsNotNone(cohort)
self.assertTrue(is_user_in_cohort(cohort, self.test_user.id, CourseUserGroup.WORKGROUP))
......@@ -296,15 +296,15 @@ class WorkgroupsApiTests(ModuleStoreTestCase):
)
# now let's remove existing cohort users
cohort = get_cohort_by_name(self.test_project.course_id, cohort_name, CourseUserGroup.WORKGROUP)
cohort = get_cohort_by_name(self.test_course.id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertTrue(is_user_in_cohort(cohort, self.test_user.id, CourseUserGroup.WORKGROUP))
remove_user_from_cohort(cohort, self.test_user.username, CourseUserGroup.WORKGROUP)
self.assertFalse(is_user_in_cohort(cohort, self.test_user.id, CourseUserGroup.WORKGROUP))
# delete cohort
delete_empty_cohort(self.test_project.course_id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertEqual(0, len(get_course_cohort_names(self.test_project.course_id, CourseUserGroup.WORKGROUP)))
delete_empty_cohort(self.test_course.id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertEqual(0, len(get_course_cohort_names(self.test_course.id, CourseUserGroup.WORKGROUP)))
# add a 2nd user and make sure a discussion cohort was created and users were backfilled
test_uri = '{}{}/'.format(self.test_workgroups_uri, str(response.data['id']))
......@@ -314,7 +314,7 @@ class WorkgroupsApiTests(ModuleStoreTestCase):
self.assertEqual(response.status_code, 201)
# now inspect cohort and assert that things are as we anticipate (i.e. both users are in there)
cohort = get_cohort_by_name(self.test_project.course_id, cohort_name, CourseUserGroup.WORKGROUP)
cohort = get_cohort_by_name(self.test_course.id, cohort_name, CourseUserGroup.WORKGROUP)
self.assertIsNotNone(cohort)
self.assertTrue(is_user_in_cohort(cohort, self.test_user.id, CourseUserGroup.WORKGROUP))
self.assertTrue(is_user_in_cohort(cohort, self.test_user2.id, CourseUserGroup.WORKGROUP))
......
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