You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12 jaren geleden
12 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. from django.core.exceptions import ObjectDoesNotExist
  2. from tastypie import fields
  3. from tastypie.authorization import DjangoAuthorization
  4. from tastypie.constants import ALL, ALL_WITH_RELATIONS
  5. from tastypie.exceptions import Unauthorized
  6. from tastypie.resources import ModelResource
  7. from django_images.models import Thumbnail
  8. from .models import Pin, Image
  9. from users.models import User
  10. def _is_pin_owner(obj_or_list, user):
  11. assert obj_or_list is not None
  12. if not isinstance(obj_or_list, (tuple, list)):
  13. obj_or_list = (obj_or_list,)
  14. results = tuple(
  15. obj.submitter == user
  16. for obj in obj_or_list
  17. if isinstance(obj, Pin)
  18. )
  19. if len(results) <= 0:
  20. raise ValueError(
  21. "You should never check permission on %s with this function."
  22. % obj_or_list
  23. )
  24. return all(results)
  25. def _is_authenticated_and_owner(object_list, bundle):
  26. if bundle.request.user.is_anonymous():
  27. return object_list.none()
  28. return object_list.filter(submitter=bundle.request.user)
  29. class PinryAuthorization(DjangoAuthorization):
  30. """
  31. Pinry-specific Authorization backend with object-level permission checking.
  32. """
  33. def _is_obj_owner(self, object_list, bundle):
  34. klass = self.base_checks(bundle.request, bundle.obj.__class__)
  35. if klass is False:
  36. raise Unauthorized("You are not allowed to access that resource.")
  37. return _is_pin_owner(bundle.obj, bundle.request.user)
  38. def read_list(self, object_list, bundle):
  39. # This assumes a ``QuerySet`` from ``ModelResource``.
  40. return object_list
  41. def read_detail(self, object_list, bundle):
  42. """
  43. User can always read detail of any Pin object.
  44. """
  45. return True
  46. def create_detail(self, object_list, bundle):
  47. return self._is_obj_owner(object_list, bundle)
  48. def update_detail(self, object_list, bundle):
  49. return self._is_obj_owner(object_list, bundle)
  50. def delete_detail(self, object_list, bundle):
  51. return self._is_obj_owner(object_list, bundle)
  52. def update_list(self, object_list, bundle):
  53. return _is_authenticated_and_owner(object_list, bundle)
  54. def delete_list(self, object_list, bundle):
  55. return _is_authenticated_and_owner(object_list, bundle)
  56. class ImageAuthorization(DjangoAuthorization):
  57. """
  58. Pinry-specific Authorization backend with object-level permission checking.
  59. """
  60. def __init__(self):
  61. DjangoAuthorization.__init__(self)
  62. def read_list(self, object_list, bundle):
  63. return object_list
  64. def read_detail(self, object_list, bundle):
  65. """
  66. User can always read detail of any Pin object.
  67. """
  68. return True
  69. def create_detail(self, object_list, bundle):
  70. return bundle.request.user.is_authenticated()
  71. def update_detail(self, object_list, bundle):
  72. return bundle.request.user.is_authenticated()
  73. def delete_detail(self, object_list, bundle):
  74. return bundle.request.user.is_authenticated()
  75. def update_list(self, object_list, bundle):
  76. if not bundle.request.user.is_authenticated():
  77. return object_list.none()
  78. return object_list
  79. def delete_list(self, object_list, bundle):
  80. if not bundle.request.user.is_authenticated():
  81. return object_list.none()
  82. return object_list
  83. class UserResource(ModelResource):
  84. gravatar = fields.CharField(readonly=True)
  85. def dehydrate_gravatar(self, bundle):
  86. return bundle.obj.gravatar
  87. class Meta:
  88. list_allowed_methods = ['get']
  89. filtering = {
  90. 'username': ALL
  91. }
  92. queryset = User.objects.all()
  93. resource_name = 'user'
  94. fields = ['username']
  95. include_resource_uri = False
  96. def filter_generator_for(size):
  97. def wrapped_func(bundle, **kwargs):
  98. if hasattr(bundle.obj, '_prefetched_objects_cache') and 'thumbnail' in bundle.obj._prefetched_objects_cache:
  99. for thumbnail in bundle.obj._prefetched_objects_cache['thumbnail']:
  100. if thumbnail.size == size:
  101. return thumbnail
  102. raise ObjectDoesNotExist()
  103. else:
  104. return bundle.obj.get_by_size(size)
  105. return wrapped_func
  106. class ThumbnailResource(ModelResource):
  107. class Meta:
  108. list_allowed_methods = ['get']
  109. fields = ['image', 'width', 'height']
  110. queryset = Thumbnail.objects.all()
  111. resource_name = 'thumbnail'
  112. include_resource_uri = False
  113. class ImageResource(ModelResource):
  114. standard = fields.ToOneField(
  115. ThumbnailResource, full=True,
  116. attribute=lambda bundle: filter_generator_for('standard')(bundle),
  117. related_name='thumbnail',
  118. )
  119. thumbnail = fields.ToOneField(
  120. ThumbnailResource, full=True,
  121. attribute=lambda bundle: filter_generator_for('thumbnail')(bundle),
  122. related_name='thumbnail',
  123. )
  124. square = fields.ToOneField(
  125. ThumbnailResource, full=True,
  126. attribute=lambda bundle: filter_generator_for('square')(bundle),
  127. related_name='thumbnail',
  128. )
  129. class Meta:
  130. fields = ['image', 'width', 'height']
  131. include_resource_uri = False
  132. resource_name = 'image'
  133. queryset = Image.objects.all()
  134. authorization = ImageAuthorization()
  135. class PinResource(ModelResource):
  136. submitter = fields.ToOneField(UserResource, 'submitter', full=True)
  137. image = fields.ToOneField(ImageResource, 'image', full=True)
  138. tags = fields.ListField()
  139. def hydrate_image(self, bundle):
  140. url = bundle.data.get('url', None)
  141. if url:
  142. image = Image.objects.create_for_url(
  143. url,
  144. referer=bundle.data.get('referer', None),
  145. )
  146. bundle.data['image'] = '/api/v1/image/{}/'.format(image.pk)
  147. return bundle
  148. def hydrate(self, bundle):
  149. """Run some early/generic processing
  150. Make sure that user is authorized to create Pins first, before
  151. we hydrate the Image resource, creating the Image object in process
  152. """
  153. submitter = bundle.data.get('submitter', None)
  154. if not submitter:
  155. bundle.data['submitter'] = '/api/v1/user/{}/'.format(bundle.request.user.pk)
  156. else:
  157. if not '/api/v1/user/{}/'.format(bundle.request.user.pk) == submitter:
  158. raise Unauthorized("You are not authorized to create Pins for other users")
  159. return bundle
  160. def dehydrate_tags(self, bundle):
  161. return list(map(str, bundle.obj.tags.all()))
  162. def build_filters(self, filters=None, ignore_bad_filters=False):
  163. orm_filters = super(PinResource, self).build_filters(filters, ignore_bad_filters=ignore_bad_filters)
  164. if filters and 'tag' in filters:
  165. orm_filters['tags__name__in'] = filters['tag'].split(',')
  166. return orm_filters
  167. def save_m2m(self, bundle):
  168. tags = bundle.data.get('tags', None)
  169. if tags:
  170. bundle.obj.tags.set(*tags)
  171. return super(PinResource, self).save_m2m(bundle)
  172. class Meta:
  173. fields = ['id', 'url', 'origin', 'description', 'referer']
  174. ordering = ['id']
  175. filtering = {
  176. 'submitter': ALL_WITH_RELATIONS
  177. }
  178. queryset = Pin.objects.all().select_related('submitter', 'image'). \
  179. prefetch_related('image__thumbnail_set', 'tags')
  180. resource_name = 'pin'
  181. include_resource_uri = False
  182. always_return_data = True
  183. authorization = PinryAuthorization()