mirror of
https://github.com/pinry/pinry.git
synced 2025-11-13 16:45:41 +01:00
Too lax unique constraints for Thumbnail coped with "on demand" thumbnail generation may leave database in inconsistent state where two thumbnail for the same size are saved. We should be able to prevent that from happening by generating all thumbnails when we save the image. Should fix #24, but I can't figure out a way to actually test it.
143 lines
4.8 KiB
Python
143 lines
4.8 KiB
Python
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
|
|
|
|
|
|
class PinryAuthorization(DjangoAuthorization):
|
|
"""
|
|
Pinry-specific Authorization backend with object-level permission checking.
|
|
"""
|
|
def update_detail(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.")
|
|
|
|
permission = '%s.change_%s' % (klass._meta.app_label, klass._meta.module_name)
|
|
|
|
if not bundle.request.user.has_perm(permission, bundle.obj):
|
|
raise Unauthorized("You are not allowed to access that resource.")
|
|
|
|
return True
|
|
|
|
def delete_detail(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.")
|
|
|
|
permission = '%s.delete_%s' % (klass._meta.app_label, klass._meta.module_name)
|
|
|
|
if not bundle.request.user.has_perm(permission, bundle.obj):
|
|
raise Unauthorized("You are not allowed to access that resource.")
|
|
|
|
return True
|
|
|
|
|
|
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):
|
|
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))
|
|
thumbnail = fields.ToOneField(ThumbnailResource, full=True,
|
|
attribute=lambda bundle: filter_generator_for('thumbnail')(bundle))
|
|
square = fields.ToOneField(ThumbnailResource, full=True,
|
|
attribute=lambda bundle: filter_generator_for('square')(bundle))
|
|
|
|
class Meta:
|
|
fields = ['image', 'width', 'height']
|
|
include_resource_uri = False
|
|
resource_name = 'image'
|
|
queryset = Image.objects.all()
|
|
authorization = DjangoAuthorization()
|
|
|
|
|
|
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)
|
|
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 map(str, bundle.obj.tags.all())
|
|
|
|
def build_filters(self, filters=None):
|
|
orm_filters = super(PinResource, self).build_filters(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']
|
|
ordering = ['id']
|
|
filtering = {
|
|
'submitter': ALL_WITH_RELATIONS
|
|
}
|
|
queryset = Pin.objects.all()
|
|
resource_name = 'pin'
|
|
include_resource_uri = False
|
|
always_return_data = True
|
|
authorization = PinryAuthorization()
|