Skip to content

Commit

Permalink
made new permission for user-level results, updated view to use it, u…
Browse files Browse the repository at this point in the history
…pdated tests accordingly
  • Loading branch information
Diane Kaplan committed Oct 30, 2020
1 parent d7278f1 commit e7e6528
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 12 deletions.
10 changes: 10 additions & 0 deletions lms/djangoapps/experiments/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,13 @@ def has_permission(self, request, view):
class IsStaffOrReadOnly(BasePermission):
def has_permission(self, request, view):
return request.user.is_staff or request.method in SAFE_METHODS


class IsStaffOrReadOnlyForSelf(BasePermission):
"""
Grants access to staff or to user reading info about their own user
"""
def has_permission(self, request, view):
username = request.user.username
return request.user.is_staff or (request.method in SAFE_METHODS and (
username == request.parser_context['kwargs']['username']))
46 changes: 36 additions & 10 deletions lms/djangoapps/experiments/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,21 +296,47 @@ def test_permissions(self):


class ExperimentUserMetaDataViewTests(APITestCase, ModuleStoreTestCase):
""" Internal user_metadata view/API for use in Optimizely experiments """

def test_UserMetaDataView_get_success_same_user(self):
""" Request succeeds when logged-in user makes request for self """
lookup_user = UserFactory()
lookup_course = CourseFactory.create(start=now() - timedelta(days=30))
call_args = [lookup_user.username, lookup_course.id]
self.client.login(username=lookup_user.username, password=UserFactory._DEFAULT_PASSWORD)

def test_UserMetaDataView_get(self):
""" Internal user_metadata view/API for use in Optimizely experiments """
user = UserFactory()
course = CourseFactory.create(start=now() - timedelta(days=30))
call_args = [user.username, course.id]
response = self.client.get(reverse('api_experiments:user_metadata', args=call_args))
self.assertEqual(response.status_code, 200)

call_args_with_bogus_user = ['bugsbunny', course.id]
response = self.client.get(reverse('api_experiments:user_metadata', args=call_args_with_bogus_user))
self.assertEqual(response.status_code, 404)
self.assertEqual(response.json()['message'], 'Provided user is not found')
def test_UserMetaDataView_get_success_staff_user(self):
""" Request succeeds when logged-in staff user makes request for different user """
lookup_user = UserFactory()
lookup_course = CourseFactory.create(start=now() - timedelta(days=30))
call_args = [lookup_user.username, lookup_course.id]
staff_user = UserFactory(is_staff=True)

self.client.login(username=staff_user.username, password=UserFactory._DEFAULT_PASSWORD)

response = self.client.get(reverse('api_experiments:user_metadata', args=call_args))
self.assertEqual(response.status_code, 200)

def test_UserMetaDataView_get_different_user(self):
""" Request fails when not logged in for requested user or staff """
lookup_user = UserFactory()
lookup_course = CourseFactory.create(start=now() - timedelta(days=30))
call_args = [lookup_user.username, lookup_course.id]

response = self.client.get(reverse('api_experiments:user_metadata', args=call_args))
self.assertEqual(response.status_code, 401)

def test_UserMetaDataView_get_missing_course(self):
""" Request fails when not course not found """
lookup_user = UserFactory()
lookup_course = CourseFactory.create(start=now() - timedelta(days=30))
call_args = [lookup_user.username, lookup_course.id]
self.client.login(username=lookup_user.username, password=UserFactory._DEFAULT_PASSWORD)

call_args_with_bogus_course = [user.username, 'course-v1:edX+DemoX+Demo_BOGUS']
call_args_with_bogus_course = [lookup_user.username, 'course-v1:edX+DemoX+Demo_BOGUS']
response = self.client.get(reverse('api_experiments:user_metadata', args=call_args_with_bogus_course))
self.assertEqual(response.status_code, 404)
self.assertEqual(response.json()['message'], 'Provided course is not found')
4 changes: 2 additions & 2 deletions lms/djangoapps/experiments/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

from experiments import filters, serializers
from experiments.models import ExperimentData, ExperimentKeyValue
from experiments.permissions import IsStaffOrOwner, IsStaffOrReadOnly
from experiments.permissions import IsStaffOrOwner, IsStaffOrReadOnly, IsStaffOrReadOnlyForSelf
from experiments.utils import get_experiment_user_metadata_context
from openedx.core.djangoapps.cors_csrf.authentication import SessionAuthenticationCrossDomainCsrf
from student.models import get_user_by_username_or_email
Expand Down Expand Up @@ -95,7 +95,7 @@ class ExperimentKeyValueViewSet(viewsets.ModelViewSet):

class UserMetaDataView(APIView):
authentication_classes = (JwtAuthentication, ExperimentCrossDomainSessionAuth,)
permission_classes = (IsStaffOrReadOnly,)
permission_classes = (IsStaffOrReadOnlyForSelf,)

def get(self, request, course_id=None, username=None):
""" Return user-metadata for the given course and user """
Expand Down

0 comments on commit e7e6528

Please sign in to comment.