A massive amount of work upgrading the API to Tastypie >= 0.9.14 with new authorization schema.

master
Nick Sergeant 2013-03-24 22:38:04 -04:00
parent fb0142f249
commit e669c5f25c
7 changed files with 235 additions and 35 deletions

View File

@ -1,4 +1,4 @@
from django.conf.urls.defaults import *
from django.conf.urls import *
from accounts import views

View File

@ -1,4 +1,4 @@
from django.conf.urls.defaults import *
from django.conf.urls import *
urlpatterns = patterns('',
url(r'^$', views.blog, name='blog'),

View File

@ -151,9 +151,15 @@ SESSION_COOKIE_AGE = 15801100
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse'
}
},
'handlers': {
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},

View File

@ -3,6 +3,7 @@ from tastypie.authentication import ApiKeyAuthentication
from tastypie.authorization import Authorization
from django.template.defaultfilters import date, urlize, linebreaksbr
from tastypie.resources import ModelResource
from tastypie.exceptions import Unauthorized
from django.contrib.auth.models import User
from tastypie.validation import Validation
from tastypie.models import create_api_key
@ -22,8 +23,137 @@ import parsedatetime.parsedatetime as pdt
models.signals.post_save.connect(create_api_key, sender=User)
class PrivateFavoriteAuthorization(Authorization):
def read_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def read_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
raise Unauthorized()
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
class PrivateSniptAuthorization(Authorization):
def read_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def read_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def update_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def update_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def delete_list(self, object_list, bundle):
return object_list.filter(user=bundle.request.user)
def delete_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
class PrivateTagAuthorization(Authorization):
def read_list(self, object_list, bundle):
object_list = object_list.filter(snipt__user=bundle.request.user)
object_list = object_list.annotate(count=models.Count('taggit_taggeditem_items__id'))
object_list = object_list.order_by('-count', 'name')
return object_list
def read_detail(self, object_list, bundle):
raise Unauthorized()
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
raise Unauthorized()
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
raise Unauthorized()
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
raise Unauthorized()
class PrivateUserProfileAuthorization(Authorization):
def read_list(self, object_list, bundle):
raise Unauthorized()
def read_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
raise Unauthorized()
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
return bundle.obj.user == bundle.request.user
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
raise Unauthorized()
class PrivateUserAuthorization(Authorization):
def read_list(self, object_list, bundle):
raise Unauthorized()
def read_detail(self, object_list, bundle):
return bundle.obj == bundle.request.user
def create_list(self, object_list, bundle):
raise Unauthorized()
def create_detail(self, object_list, bundle):
raise Unauthorized()
def update_list(self, object_list, bundle):
raise Unauthorized()
def update_detail(self, object_list, bundle):
raise Unauthorized()
def delete_list(self, object_list, bundle):
raise Unauthorized()
def delete_detail(self, object_list, bundle):
raise Unauthorized()
class FavoriteValidation(Validation):
def is_valid(self, bundle):
def is_valid(self, bundle, request=None):
errors = {}
snipt = bundle.data['snipt']
@ -33,7 +163,7 @@ class FavoriteValidation(Validation):
return errors
class UserProfileValidation(Validation):
def is_valid(self, bundle):
def is_valid(self, bundle, request=None):
errors = {}
if not bundle.request.user.profile.is_pro:
@ -142,13 +272,10 @@ class PrivateUserProfileResource(ModelResource):
allowed_methods = ['get', 'put']
list_allowed_methods = []
authentication = ApiKeyAuthentication()
authorization = Authorization()
authorization = PrivateUserProfileAuthorization()
always_return_data = True
max_limit = 200
def apply_authorization_limits(self, request, object_list):
return object_list.filter(user=request.user)
def dehydrate(self, bundle):
bundle.data['email'] = bundle.obj.user.email
bundle.data['username'] = bundle.obj.user.username
@ -168,14 +295,11 @@ class PrivateUserResource(ModelResource):
allowed_methods = ['get']
list_allowed_methods = []
authentication = ApiKeyAuthentication()
authorization = Authorization()
authorization = PrivateUserAuthorization()
always_return_data = True
max_limit = 200
cache = SimpleCache()
def apply_authorization_limits(self, request, object_list):
return object_list.filter(username=request.user.username)
def dehydrate(self, bundle):
bundle.data['email_md5'] = hashlib.md5(bundle.obj.email.lower()).hexdigest()
bundle.data['is_pro'] = bundle.obj.profile.is_pro
@ -190,7 +314,7 @@ class PrivateTagResource(ModelResource):
fields = ['id', 'name',]
allowed_methods = ['get']
authentication = ApiKeyAuthentication()
authorization = Authorization()
authorization = PrivateTagAuthorization()
always_return_data = True
max_limit = 200
cache = SimpleCache()
@ -205,6 +329,7 @@ class PrivateTagResource(ModelResource):
orm_filters['slug'] = filters['q']
return orm_filters
def dehydrate(self, bundle):
bundle.data['absolute_url'] = '/%s/tag/%s/' % (bundle.request.user.username,
bundle.obj.slug)
@ -216,11 +341,6 @@ class PrivateTagResource(ModelResource):
return bundle
def apply_authorization_limits(self, request, object_list):
object_list = object_list.filter(snipt__user=request.user)
object_list = object_list.annotate(count=models.Count('taggit_taggeditem_items__id'))
object_list = object_list.order_by('-count', 'name')
return object_list
class PrivateSniptResource(ModelResource):
user = fields.ForeignKey(PrivateUserResource, 'user', full=True)
@ -236,7 +356,7 @@ class PrivateSniptResource(ModelResource):
detail_allowed_methods = ['get', 'patch', 'put', 'delete']
list_allowed_methods = ['get', 'post']
authentication = ApiKeyAuthentication()
authorization = Authorization()
authorization = PrivateSniptAuthorization()
ordering = ['created', 'modified',]
always_return_data = True
max_limit = 200
@ -321,9 +441,6 @@ class PrivateSniptResource(ModelResource):
return orm_filters
def apply_authorization_limits(self, request, object_list):
return object_list.filter(user=request.user)
def save_m2m(self, bundle):
tags = bundle.data.get('tags_list', [])
if tags != '':
@ -343,7 +460,7 @@ class PrivateFavoriteResource(ModelResource):
detail_allowed_methods = ['get', 'post', 'delete']
list_allowed_methods = ['get', 'post',]
authentication = ApiKeyAuthentication()
authorization = Authorization()
authorization = PrivateFavoriteAuthorization()
ordering = ['created',]
always_return_data = True
max_limit = 200
@ -359,6 +476,3 @@ class PrivateFavoriteResource(ModelResource):
bundle.data['snipt'] = Snipt.objects.get(pk=bundle.data['snipt'])
return super(PrivateFavoriteResource, self).obj_create(bundle,
user=bundle.request.user, **kwargs)
def apply_authorization_limits(self, request, object_list):
return object_list.filter(user=request.user)

View File

@ -1,9 +1,89 @@
from django.test import TestCase
from django.contrib.auth.models import User
from tastypie.test import ResourceTestCase
from tastypie.models import ApiKey
from snipts.models import Snipt
class SniptAPITest(TestCase):
def test_get_snipt(self):
"""
We should be able to get a public snipt from the API.
"""
self.assertEqual(1 + 1, 2)
class SniptResourceTest(ResourceTestCase):
fixtures = ['test_entries.json']
def setUp(self):
super(SniptResourceTest, self).setUp()
# Johnny
self.johnny = User.objects.create_user('johnny', 'johnny@snipt.net', 'password')
ApiKey.objects.get_or_create(user=self.johnny)
self.johnny_auth = self.create_apikey(self.johnny, self.johnny.api_key.key)
self.johnny_private = Snipt(title='Private snipt for Johnny', lexer='text', public=False, user=self.johnny)
self.johnny_public = Snipt(title='Public snipt for Johnny', lexer='text', public=True, user=self.johnny)
self.johnny_private.save()
self.johnny_public.save()
# Bob
self.bob = User.objects.create_user('bob', 'bob@snipt.net', 'password')
ApiKey.objects.get_or_create(user=self.bob)
self.bob_auth = self.create_apikey(self.bob, self.bob.api_key.key)
self.bob_private = Snipt(title='Private snipt for Bob', lexer='text', public=False, user=self.bob)
self.bob_public = Snipt(title='Public snipt for Bob', lexer='text', public=True, user=self.bob)
self.bob_private.save()
self.bob_public.save()
# Private
def test_get_private_list(self):
resp = self.api_client.get('/api/private/snipt/', format='json', authentication=self.johnny_auth)
self.assertHttpOK(resp)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)['objects']), 2)
def test_get_private_detail(self):
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json', authentication=self.johnny_auth)
self.assertHttpOK(resp)
self.assertValidJSONResponse(resp)
self.assertEqual(self.deserialize(resp)['key'], self.johnny_private.key)
# Unauthenticated request.
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json')
self.assertHttpUnauthorized(resp)
# Unauthorized request.
resp = self.api_client.get('/api/private/snipt/{}/'.format(self.johnny_private.pk), format='json', authentication=self.bob_auth)
self.assertHttpUnauthorized(resp)
def test_post_private_list(self):
new_snipt = {
'title': 'A new private snipt.',
'lexer': 'text',
'public': False,
}
resp = self.api_client.post('/api/private/snipt/',
data=new_snipt,
format='json',
authentication=self.johnny_auth)
self.assertHttpCreated(resp)
self.assertEqual(Snipt.objects.count(), 5)
resp = self.api_client.get('/api/private/snipt/', format='json', authentication=self.johnny_auth)
self.assertEqual(len(self.deserialize(resp)['objects']), 3)
resp = self.api_client.get('/api/public/snipt/', format='json')
self.assertEqual(len(self.deserialize(resp)['objects']), 2)
# Public
def test_get_public_list(self):
self.assertEqual(Snipt.objects.count(), 4)
resp = self.api_client.get('/api/public/snipt/', format='json')
self.assertHttpOK(resp)
self.assertValidJSONResponse(resp)
self.assertEqual(len(self.deserialize(resp)['objects']), 2)

View File

@ -1,4 +1,4 @@
from django.conf.urls.defaults import *
from django.conf.urls import *
from snipts import views

View File

@ -1,5 +1,5 @@
from views import (homepage, lexers, pro_signup, sitemap, tags, pro_signup_complete)
from django.conf.urls.defaults import include, patterns, url
from django.conf.urls import include, patterns, url
from utils.views import SniptRegistrationView
from django.views.generic import TemplateView
from django.http import HttpResponseRedirect