from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.db.models import Count import humanize from tastypie import fields from tastypie.authentication import Authentication from tastypie.authorization import DjangoAuthorization from django.conf.urls import url from tastypie.http import HttpMultipleChoices, HttpGone from tastypie.utils import trailing_slash from spa.api.v1.BackboneCompatibleResource import BackboneCompatibleResource from spa.api.v1.MixResource import MixResource from spa.models import UserProfile, Mix class UserProfileResource(BackboneCompatibleResource): class Meta: queryset = UserProfile.manager.annotate(fcount=Count('followers')) resource_name = 'profile' include_resource_uri = False include_absolute_url = False always_return_data = True authorization = DjangoAuthorization() authentication = Authentication() def _hydrateBitmapOption(self, source, comparator): return True if (source & comparator) != 0 else False def hydrate(self, bundle): if 'activity_sharing_likes' in bundle.data: likes = UserProfile.ACTIVITY_SHARE_LIKES if bundle.data['activity_sharing_likes'] else 0 favourites = UserProfile.ACTIVITY_SHARE_FAVOURITES if bundle.data['activity_sharing_favourites'] else 0 comments = UserProfile.ACTIVITY_SHARE_COMMENTS if bundle.data['activity_sharing_comments'] else 0 bundle.data['activity_sharing'] = (likes | favourites | comments) del bundle.data['activity_sharing_likes'] del bundle.data['activity_sharing_favourites'] del bundle.data['activity_sharing_comments'] if 'activity_sharing_networks_facebook' in bundle.data: facebook = UserProfile.ACTIVITY_SHARE_NETWORK_FACEBOOK if bundle.data[ 'activity_sharing_networks_facebook'] else 0 twitter = UserProfile.ACTIVITY_SHARE_NETWORK_TWITTER if bundle.data[ 'activity_sharing_networks_twitter'] else 0 bundle.data['activity_sharing_networks'] = (facebook | twitter) del bundle.data['activity_sharing_networks_facebook'] del bundle.data['activity_sharing_networks_twitter'] return bundle def obj_update(self, bundle, skip_errors=False, **kwargs): """ This feels extremely hacky - but for some reason, deleting from the bundle in hydrate is not preventing the fields from being serialized at the ORM """ if 'activity_sharing_networks_facebook' in kwargs: del kwargs['activity_sharing_networks_facebook'] if 'activity_sharing_networks_twitter' in kwargs: del kwargs['activity_sharing_networks_twitter'] if 'activity_sharing_likes' in kwargs: del kwargs['activity_sharing_likes'] if 'activity_sharing_favourites' in kwargs: del kwargs['activity_sharing_favourites'] if 'activity_sharing_comments' in kwargs: del kwargs['activity_sharing_comments'] return super(UserProfileResource, self).obj_update(bundle, skip_errors, **kwargs) def dehydrate(self, bundle): del bundle.data['activity_sharing'] del bundle.data['activity_sharing_networks'] bundle.data['display_name'] = bundle.obj.get_nice_name() bundle.data['avatar_image'] = bundle.obj.get_avatar_image() if bundle.obj.user.id == bundle.request.user.id: bundle.data['activity_sharing_likes'] = \ self._hydrateBitmapOption(bundle.obj.activity_sharing, UserProfile.ACTIVITY_SHARE_LIKES) bundle.data['activity_sharing_favourites'] = \ self._hydrateBitmapOption(bundle.obj.activity_sharing, UserProfile.ACTIVITY_SHARE_FAVOURITES) bundle.data['activity_sharing_comments'] = \ self._hydrateBitmapOption(bundle.obj.activity_sharing, UserProfile.ACTIVITY_SHARE_COMMENTS) bundle.data['activity_sharing_networks_facebook'] = \ self._hydrateBitmapOption(bundle.obj.activity_sharing_networks, UserProfile.ACTIVITY_SHARE_NETWORK_FACEBOOK) bundle.data['activity_sharing_networks_twitter'] = \ self._hydrateBitmapOption(bundle.obj.activity_sharing_networks, UserProfile.ACTIVITY_SHARE_NETWORK_TWITTER) bundle.data['mix_count'] = Mix.objects.filter(user=bundle.obj).count() bundle.data['like_count'] = Mix.objects.filter(likes__user=bundle.obj).count() bundle.data['favourite_count'] = Mix.objects.filter(favourites__user=bundle.obj).count() bundle.data['follower_count'] = bundle.obj.followers.count() bundle.data['following_count'] = bundle.obj.following.count() bundle.data['following'] = bundle.obj.is_follower(bundle.request.user) return bundle class UserResource(BackboneCompatibleResource): profile = fields.ToOneField(UserProfileResource, attribute='userprofile', related_name='user', full=True) class Meta: queryset = User.objects.all() resource_name = 'user' excludes = ['is_active', 'is_staff', 'is_superuser', 'password'] authorization = DjangoAuthorization() authentication = Authentication() favourites = fields.ToManyField(MixResource, 'favourites') def prepend_urls(self): return [ url(r"^(?P%s)/(?P[\w\d_.-]+)/favourites%s$" % ( self._meta.resource_name, trailing_slash()), self.wrap_view('get_user_favourites'), name="api_get_user_favourites"), url(r"^(?P%s)/(?P\d+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), url(r"^(?P%s)/(?P[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), ] def get_object_list(self, request): return super(UserResource, self).get_object_list(request) def get_user_favourites(self, request, **kwargs): try: obj = self.cached_obj_get(bundle=self.build_bundle(request=request), **self.remove_api_resource_names(kwargs)) except ObjectDoesNotExist: return HttpGone() except MultipleObjectsReturned: return HttpMultipleChoices("More than one resource is found at this URI.") mixes = MixResource() return mixes.get_list(request, favourites__user=obj.get_profile()) def dehydrate(self, bundle): if bundle.obj.id != bundle.request.user.id: del bundle.data['email'] del bundle.data['username'] bundle.data['human_last_login'] = humanize.naturaltime(bundle.obj.last_login.replace(tzinfo=None)) return bundle