Commit bc3300fd by David Ormsbee

Merge pull request #15 from edx/dcs/authentication

Add authentication and model permission checking to REST API.
parents 8e1dcac6 35cac655
"""
init
"""
from django.contrib.auth.models import User, Permission
from rest_framework.test import APITestCase
class APIAuthTestCase(APITestCase):
"""
TestCase that creates a readwrite and readonly user in setUp
"""
def setUp(self):
self.username = self.password = 'readwrite'
self.readwrite_user = User.objects.create_user(self.username, password=self.password)
self.readwrite_user.user_permissions = Permission.objects.filter(content_type__app_label='edxval')
self.readonly_user = User.objects.create_user('readonly', 'readonly')
self._login()
def _logout(self):
self.client.logout()
def _login(self, readonly=False):
if readonly:
username = password = 'readonly'
else:
username, password = self.username, self.password
self.client.login(username=username, password=password)
......@@ -10,14 +10,13 @@ from django.db import DatabaseError
from django.core.urlresolvers import reverse
from django.core.exceptions import ValidationError
from rest_framework import status
from rest_framework.test import APITestCase
from ddt import ddt, data
from edxval.models import Profile, Video, EncodedVideo
from edxval import api as api
from edxval.api import ValCannotCreateError
from edxval.serializers import VideoSerializer
from edxval.tests import constants
from edxval.tests import constants, APIAuthTestCase
@ddt
class CreateVideoTest(TestCase):
......@@ -190,7 +189,7 @@ class GetVideoInfoTest(TestCase):
)
class GetVideoInfoTestWithHttpCalls(APITestCase):
class GetVideoInfoTestWithHttpCalls(APIAuthTestCase):
"""
Tests for the get_info_video, using the HTTP requests to populate database
"""
......@@ -200,9 +199,10 @@ class GetVideoInfoTestWithHttpCalls(APITestCase):
Creates EncodedVideo objects in database with HTTP requests.
The tests are similar to the GetVideoInfoTest class. This class
is to tests that we have the same results, using a populated
is to test that we have the same results, using a populated
database via HTTP uploads.
"""
super(GetVideoInfoTestWithHttpCalls, self).setUp()
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
url = reverse('video-list')
......
......@@ -4,13 +4,12 @@ Tests for Video Abstraction Layer views
"""
from django.core.urlresolvers import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from edxval.tests import constants
from edxval.tests import constants, APIAuthTestCase
from edxval.models import Profile, Video
class VideoDetail(APITestCase):
class VideoDetail(APIAuthTestCase):
"""
Tests Retrieve, Update and Destroy requests
"""
......@@ -21,9 +20,33 @@ class VideoDetail(APITestCase):
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
super(VideoDetail, self).setUp()
# Tests for successful PUT requests.
def test_anonymous_denied(self):
"""
Tests that writing checks model permissions.
"""
self._logout()
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_no_perms(self):
"""
Tests that writing checks model permissions, even for logged in users.
"""
self._logout()
self._login(readonly=True)
url = reverse('video-list')
response = self.client.post(url, constants.VIDEO_DICT_ANIMAL, format='json')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_update_video(self):
"""
Tests PUTting a single video with no encoded videos.
......@@ -290,7 +313,7 @@ class VideoDetail(APITestCase):
)
class VideoListTest(APITestCase):
class VideoListTest(APIAuthTestCase):
"""
Tests the creations of Videos via POST/GET
"""
......@@ -300,6 +323,7 @@ class VideoListTest(APITestCase):
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
super(VideoListTest, self).setUp()
# Tests for successful POST 201 requests.
def test_complete_set_two_encoded_video_post(self):
......@@ -435,7 +459,7 @@ class VideoListTest(APITestCase):
Tests number of queries for a Video with no Encoded Videos
"""
url = reverse('video-list')
with self.assertNumQueries(4):
with self.assertNumQueries(8):
self.client.post(url, constants.VIDEO_DICT_ZEBRA, format='json')
def test_queries_for_two_encoded_video(self):
......@@ -443,7 +467,7 @@ class VideoListTest(APITestCase):
Tests number of queries for a Video/EncodedVideo(2) pair
"""
url = reverse('video-list')
with self.assertNumQueries(16):
with self.assertNumQueries(20):
self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
def test_queries_for_single_encoded_videos(self):
......@@ -451,11 +475,11 @@ class VideoListTest(APITestCase):
Tests number of queries for a Video/EncodedVideo(1) pair
"""
url = reverse('video-list')
with self.assertNumQueries(10):
with self.assertNumQueries(14):
self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
class VideoDetailTest(APITestCase):
class VideoDetailTest(APIAuthTestCase):
"""
Tests for GET
"""
......@@ -465,6 +489,7 @@ class VideoDetailTest(APITestCase):
"""
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
super(VideoDetailTest, self).setUp()
def test_get_all_videos(self):
"""
......@@ -487,25 +512,26 @@ class VideoDetailTest(APITestCase):
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
response = self.client.post(url, constants.VIDEO_DICT_ZEBRA, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(4):
with self.assertNumQueries(6):
self.client.get("/edxval/video/").data
response = self.client.post(url, constants.COMPLETE_SET_FISH, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(9):
with self.assertNumQueries(11):
self.client.get("/edxval/video/").data
response = self.client.post(url, constants.COMPLETE_SET_STAR, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
with self.assertNumQueries(12):
with self.assertNumQueries(14):
self.client.get("/edxval/video/").data
class SubtitleDetailTest(APITestCase):
class SubtitleDetailTest(APIAuthTestCase):
"""
Tests for subtitle API
"""
def setUp(self):
Profile.objects.create(**constants.PROFILE_DICT_MOBILE)
Profile.objects.create(**constants.PROFILE_DICT_DESKTOP)
super(SubtitleDetailTest, self).setUp()
def test_get_subtitle_content(self):
"""
......
......@@ -3,6 +3,7 @@ Views file for django app edxval.
"""
from rest_framework import generics
from rest_framework.permissions import DjangoModelPermissions
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import last_modified
......@@ -32,6 +33,7 @@ class VideoList(generics.ListCreateAPIView):
"""
GETs or POST video objects
"""
permission_classes = (DjangoModelPermissions,)
queryset = Video.objects.all().prefetch_related("encoded_videos")
lookup_field = "edx_video_id"
serializer_class = VideoSerializer
......@@ -41,6 +43,7 @@ class ProfileList(generics.ListCreateAPIView):
"""
GETs or POST video objects
"""
permission_classes = (DjangoModelPermissions,)
queryset = Profile.objects.all()
lookup_field = "profile_name"
serializer_class = ProfileSerializer
......@@ -50,6 +53,7 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Gets a video instance given its edx_video_id
"""
permission_classes = (DjangoModelPermissions,)
lookup_field = "edx_video_id"
queryset = Video.objects.all()
serializer_class = VideoSerializer
......@@ -59,6 +63,7 @@ class SubtitleDetail(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPI
"""
Gets a subtitle instance given its id
"""
permission_classes = (DjangoModelPermissions,)
lookup_fields = ("video__edx_video_id", "language")
queryset = Subtitle.objects.all()
serializer_class = SubtitleSerializer
......
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