mirror of
https://github.com/pinry/pinry.git
synced 2025-11-14 00:55:43 +01:00
Feature: Remove unused django-tastypie
This commit is contained in:
227
core/api.py
227
core/api.py
@@ -1,227 +0,0 @@
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from tastypie import fields
|
|
||||||
from tastypie.authorization import DjangoAuthorization
|
|
||||||
from tastypie.constants import ALL, ALL_WITH_RELATIONS
|
|
||||||
from tastypie.exceptions import Unauthorized
|
|
||||||
from tastypie.resources import ModelResource
|
|
||||||
from django_images.models import Thumbnail
|
|
||||||
|
|
||||||
from .models import Pin, Image
|
|
||||||
from users.models import User
|
|
||||||
|
|
||||||
|
|
||||||
def _is_pin_owner(obj_or_list, user):
|
|
||||||
assert obj_or_list is not None
|
|
||||||
if not isinstance(obj_or_list, (tuple, list)):
|
|
||||||
obj_or_list = (obj_or_list,)
|
|
||||||
results = tuple(
|
|
||||||
obj.submitter == user
|
|
||||||
for obj in obj_or_list
|
|
||||||
if isinstance(obj, Pin)
|
|
||||||
)
|
|
||||||
if len(results) <= 0:
|
|
||||||
raise ValueError(
|
|
||||||
"You should never check permission on %s with this function."
|
|
||||||
% obj_or_list
|
|
||||||
)
|
|
||||||
return all(results)
|
|
||||||
|
|
||||||
|
|
||||||
def _is_authenticated_and_owner(object_list, bundle):
|
|
||||||
if bundle.request.user.is_anonymous():
|
|
||||||
return object_list.none()
|
|
||||||
return object_list.filter(submitter=bundle.request.user)
|
|
||||||
|
|
||||||
|
|
||||||
class PinryAuthorization(DjangoAuthorization):
|
|
||||||
"""
|
|
||||||
Pinry-specific Authorization backend with object-level permission checking.
|
|
||||||
"""
|
|
||||||
def _is_obj_owner(self, object_list, bundle):
|
|
||||||
klass = self.base_checks(bundle.request, bundle.obj.__class__)
|
|
||||||
|
|
||||||
if klass is False:
|
|
||||||
raise Unauthorized("You are not allowed to access that resource.")
|
|
||||||
return _is_pin_owner(bundle.obj, bundle.request.user)
|
|
||||||
|
|
||||||
def read_list(self, object_list, bundle):
|
|
||||||
# This assumes a ``QuerySet`` from ``ModelResource``.
|
|
||||||
return object_list
|
|
||||||
|
|
||||||
def read_detail(self, object_list, bundle):
|
|
||||||
"""
|
|
||||||
User can always read detail of any Pin object.
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def create_detail(self, object_list, bundle):
|
|
||||||
return self._is_obj_owner(object_list, bundle)
|
|
||||||
|
|
||||||
def update_detail(self, object_list, bundle):
|
|
||||||
return self._is_obj_owner(object_list, bundle)
|
|
||||||
|
|
||||||
def delete_detail(self, object_list, bundle):
|
|
||||||
return self._is_obj_owner(object_list, bundle)
|
|
||||||
|
|
||||||
def update_list(self, object_list, bundle):
|
|
||||||
return _is_authenticated_and_owner(object_list, bundle)
|
|
||||||
|
|
||||||
def delete_list(self, object_list, bundle):
|
|
||||||
return _is_authenticated_and_owner(object_list, bundle)
|
|
||||||
|
|
||||||
|
|
||||||
class ImageAuthorization(DjangoAuthorization):
|
|
||||||
"""
|
|
||||||
Pinry-specific Authorization backend with object-level permission checking.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
DjangoAuthorization.__init__(self)
|
|
||||||
|
|
||||||
def read_list(self, object_list, bundle):
|
|
||||||
return object_list
|
|
||||||
|
|
||||||
def read_detail(self, object_list, bundle):
|
|
||||||
"""
|
|
||||||
User can always read detail of any Pin object.
|
|
||||||
"""
|
|
||||||
return True
|
|
||||||
|
|
||||||
def create_detail(self, object_list, bundle):
|
|
||||||
return bundle.request.user.is_authenticated()
|
|
||||||
|
|
||||||
def update_detail(self, object_list, bundle):
|
|
||||||
return bundle.request.user.is_authenticated()
|
|
||||||
|
|
||||||
def delete_detail(self, object_list, bundle):
|
|
||||||
return bundle.request.user.is_authenticated()
|
|
||||||
|
|
||||||
def update_list(self, object_list, bundle):
|
|
||||||
if not bundle.request.user.is_authenticated():
|
|
||||||
return object_list.none()
|
|
||||||
return object_list
|
|
||||||
|
|
||||||
def delete_list(self, object_list, bundle):
|
|
||||||
if not bundle.request.user.is_authenticated():
|
|
||||||
return object_list.none()
|
|
||||||
return object_list
|
|
||||||
|
|
||||||
|
|
||||||
class UserResource(ModelResource):
|
|
||||||
gravatar = fields.CharField(readonly=True)
|
|
||||||
|
|
||||||
def dehydrate_gravatar(self, bundle):
|
|
||||||
return bundle.obj.gravatar
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
list_allowed_methods = ['get']
|
|
||||||
filtering = {
|
|
||||||
'username': ALL
|
|
||||||
}
|
|
||||||
queryset = User.objects.all()
|
|
||||||
resource_name = 'user'
|
|
||||||
fields = ['username']
|
|
||||||
include_resource_uri = False
|
|
||||||
|
|
||||||
|
|
||||||
def filter_generator_for(size):
|
|
||||||
def wrapped_func(bundle, **kwargs):
|
|
||||||
if hasattr(bundle.obj, '_prefetched_objects_cache') and 'thumbnail' in bundle.obj._prefetched_objects_cache:
|
|
||||||
for thumbnail in bundle.obj._prefetched_objects_cache['thumbnail']:
|
|
||||||
if thumbnail.size == size:
|
|
||||||
return thumbnail
|
|
||||||
raise ObjectDoesNotExist()
|
|
||||||
else:
|
|
||||||
return bundle.obj.get_by_size(size)
|
|
||||||
return wrapped_func
|
|
||||||
|
|
||||||
|
|
||||||
class ThumbnailResource(ModelResource):
|
|
||||||
class Meta:
|
|
||||||
list_allowed_methods = ['get']
|
|
||||||
fields = ['image', 'width', 'height']
|
|
||||||
queryset = Thumbnail.objects.all()
|
|
||||||
resource_name = 'thumbnail'
|
|
||||||
include_resource_uri = False
|
|
||||||
|
|
||||||
|
|
||||||
class ImageResource(ModelResource):
|
|
||||||
standard = fields.ToOneField(
|
|
||||||
ThumbnailResource, full=True,
|
|
||||||
attribute=lambda bundle: filter_generator_for('standard')(bundle),
|
|
||||||
related_name='thumbnail',
|
|
||||||
)
|
|
||||||
thumbnail = fields.ToOneField(
|
|
||||||
ThumbnailResource, full=True,
|
|
||||||
attribute=lambda bundle: filter_generator_for('thumbnail')(bundle),
|
|
||||||
related_name='thumbnail',
|
|
||||||
)
|
|
||||||
square = fields.ToOneField(
|
|
||||||
ThumbnailResource, full=True,
|
|
||||||
attribute=lambda bundle: filter_generator_for('square')(bundle),
|
|
||||||
related_name='thumbnail',
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
fields = ['image', 'width', 'height']
|
|
||||||
include_resource_uri = False
|
|
||||||
resource_name = 'image'
|
|
||||||
queryset = Image.objects.all()
|
|
||||||
authorization = ImageAuthorization()
|
|
||||||
|
|
||||||
|
|
||||||
class PinResource(ModelResource):
|
|
||||||
submitter = fields.ToOneField(UserResource, 'submitter', full=True)
|
|
||||||
image = fields.ToOneField(ImageResource, 'image', full=True)
|
|
||||||
tags = fields.ListField()
|
|
||||||
|
|
||||||
def hydrate_image(self, bundle):
|
|
||||||
url = bundle.data.get('url', None)
|
|
||||||
if url:
|
|
||||||
image = Image.objects.create_for_url(
|
|
||||||
url,
|
|
||||||
referer=bundle.data.get('referer', None),
|
|
||||||
)
|
|
||||||
bundle.data['image'] = '/api/v1/image/{}/'.format(image.pk)
|
|
||||||
return bundle
|
|
||||||
|
|
||||||
def hydrate(self, bundle):
|
|
||||||
"""Run some early/generic processing
|
|
||||||
|
|
||||||
Make sure that user is authorized to create Pins first, before
|
|
||||||
we hydrate the Image resource, creating the Image object in process
|
|
||||||
"""
|
|
||||||
submitter = bundle.data.get('submitter', None)
|
|
||||||
if not submitter:
|
|
||||||
bundle.data['submitter'] = '/api/v1/user/{}/'.format(bundle.request.user.pk)
|
|
||||||
else:
|
|
||||||
if not '/api/v1/user/{}/'.format(bundle.request.user.pk) == submitter:
|
|
||||||
raise Unauthorized("You are not authorized to create Pins for other users")
|
|
||||||
return bundle
|
|
||||||
|
|
||||||
def dehydrate_tags(self, bundle):
|
|
||||||
return list(map(str, bundle.obj.tags.all()))
|
|
||||||
|
|
||||||
def build_filters(self, filters=None, ignore_bad_filters=False):
|
|
||||||
orm_filters = super(PinResource, self).build_filters(filters, ignore_bad_filters=ignore_bad_filters)
|
|
||||||
if filters and 'tag' in filters:
|
|
||||||
orm_filters['tags__name__in'] = filters['tag'].split(',')
|
|
||||||
return orm_filters
|
|
||||||
|
|
||||||
def save_m2m(self, bundle):
|
|
||||||
tags = bundle.data.get('tags', None)
|
|
||||||
if tags:
|
|
||||||
bundle.obj.tags.set(*tags)
|
|
||||||
return super(PinResource, self).save_m2m(bundle)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
fields = ['id', 'url', 'origin', 'description', 'referer']
|
|
||||||
ordering = ['id']
|
|
||||||
filtering = {
|
|
||||||
'submitter': ALL_WITH_RELATIONS
|
|
||||||
}
|
|
||||||
queryset = Pin.objects.all().select_related('submitter', 'image'). \
|
|
||||||
prefetch_related('image__thumbnail_set', 'tags')
|
|
||||||
resource_name = 'pin'
|
|
||||||
include_resource_uri = False
|
|
||||||
always_return_data = True
|
|
||||||
authorization = PinryAuthorization()
|
|
||||||
14
core/urls.py
14
core/urls.py
@@ -1,22 +1,10 @@
|
|||||||
from django.conf.urls import include, url
|
from django.conf.urls import url
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from tastypie.api import Api
|
|
||||||
|
|
||||||
from .api import ImageResource, ThumbnailResource, PinResource, UserResource
|
|
||||||
|
|
||||||
v1_api = Api(api_name='v1')
|
|
||||||
v1_api.register(ImageResource())
|
|
||||||
v1_api.register(ThumbnailResource())
|
|
||||||
v1_api.register(PinResource())
|
|
||||||
v1_api.register(UserResource())
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^api/', include(v1_api.urls, namespace='api')),
|
|
||||||
|
|
||||||
url(r'^pins/pin-form/$', TemplateView.as_view(template_name='core/pin_form.html'),
|
url(r'^pins/pin-form/$', TemplateView.as_view(template_name='core/pin_form.html'),
|
||||||
name='pin-form'),
|
name='pin-form'),
|
||||||
|
|
||||||
url(r'^pins/tags/(?P<tag>(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'),
|
url(r'^pins/tags/(?P<tag>(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'),
|
||||||
name='tag-pins'),
|
name='tag-pins'),
|
||||||
url(r'^pins/users/(?P<user>(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'),
|
url(r'^pins/users/(?P<user>(\w|-)+)/$', TemplateView.as_view(template_name='core/pins.html'),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from rest_framework import viewsets, mixins, routers
|
|||||||
from rest_framework.filters import SearchFilter, OrderingFilter
|
from rest_framework.filters import SearchFilter, OrderingFilter
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
|
||||||
from core import drf_api as api
|
from core import serializers as api
|
||||||
from core.models import Image, Pin
|
from core.models import Image, Pin
|
||||||
from core.permissions import IsOwnerOrReadOnly
|
from core.permissions import IsOwnerOrReadOnly
|
||||||
from users.models import User
|
from users.models import User
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from django.test.utils import override_settings
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from .auth.backends import CombinedAuthBackend
|
from .auth.backends import CombinedAuthBackend
|
||||||
from core.models import Image, Pin
|
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user