from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from django.db.models import Count, Q from tastypie import fields from tastypie.authentication import Authentication, BasicAuthentication from tastypie.authorization import DjangoAuthorization, Authorization from django.conf.urls import url from tastypie.constants import ALL from tastypie.http import HttpGone, HttpMultipleChoices from tastypie.utils import trailing_slash from spa.api.v1.BackboneCompatibleResource import BackboneCompatibleResource from spa.models.activity import ActivityFollow from spa.models.userprofile import UserProfile from spa.models.mix import Mix class UserResource(BackboneCompatibleResource): followers = fields.ToManyField(to='self', attribute='followers', related_name='followers', null=True) class Meta: queryset = UserProfile.objects.all().annotate(mix_count=Count('mixes')).order_by('-mix_count') favourites = fields.ToManyField('spa.api.v1.MixResource.MixResource', 'favourites', null=True) resource_name = 'user' excludes = ['is_active', 'is_staff', 'is_superuser', 'password'] ordering = ['mix_count'] filtering = { 'slug': ALL, } authorization = Authorization() authentication = Authentication() favourites = fields.ToManyField('spa.api.v1.MixResource', 'favourites') def _hydrateBitmapOption(self, source, comparator): return True if (source & comparator) != 0 else False 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"), url(r"^(?P%s)/(?P\w[\w/-]*)/followers%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_followers'), name="api_get_followers"), ] def apply_filters(self, request, applicable_filters): semi_filtered = super(UserResource, self).apply_filters(request, applicable_filters) return semi_filtered def __apply_filters(self, request, applicable_filters): semi_filtered = super(UserResource, self).apply_filters(request, applicable_filters) q = request.GET.get('q', None) if q is not None: semi_filtered = semi_filtered.filter( Q(user__first_name__icontains=q) | Q(user__last_name__icontains=q) | Q(display_name__icontains=q) ) return semi_filtered def _patch_resource(self, bundle): #Handle the patched items from backbone if 'following' in bundle.data: if bundle.data['following']: bundle.obj.add_follower(bundle.request.user.get_profile()) activity = ActivityFollow() activity.user = bundle.request.user.get_profile() activity.to_user = bundle.obj activity.save() else: bundle.obj.remove_follower(bundle.request.user.get_profile()) 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'] #need to figure out why this is excepting, granted I shouldn't be #trying to update followers in here but still though. try: self._patch_resource(bundle) except: pass return super(UserResource, self).obj_update(bundle, skip_errors, **kwargs) def dehydrate_description(self, bundle): return bundle.obj.get_profile_description() 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['email'] = bundle.obj.email bundle.data['first_name'] = bundle.obj.first_name bundle.data['last_name'] = bundle.obj.last_name 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['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) bundle.data['url'] = bundle.obj.get_profile_url() bundle.data['date_joined'] = bundle.obj.user.date_joined bundle.data['last_login'] = bundle.obj.user.last_login bundle.data['mix_count'] = bundle.obj.mix_count return bundle 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 get_followers(self, request, **kwargs): try: basic_bundle = self.build_bundle(request=request) obj = self.cached_obj_get(bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) except ObjectDoesNotExist: return HttpGone() except MultipleObjectsReturned: return HttpMultipleChoices("More than one resource is found at this URI.") child_resource = UserResource() return child_resource.get_list(request, mix=obj)