diff options
author | Leif Johansson <leifj@sunet.se> | 2011-08-07 14:34:14 +0200 |
---|---|---|
committer | Leif Johansson <leifj@sunet.se> | 2011-08-07 14:34:14 +0200 |
commit | 99a05864a9a9ff8ac1c68400f111ede67cf3fe28 (patch) | |
tree | 470f3c631d52a860ec5376c9993a61a1eaee2688 /coip/apps | |
parent | 63ec9216a9d85c80499fef9e0d9682d09ffa2875 (diff) |
first take at minimal opensocial
Diffstat (limited to 'coip/apps')
-rw-r--r-- | coip/apps/opensocial/__init__.py | 6 | ||||
-rw-r--r-- | coip/apps/opensocial/people.py | 107 | ||||
-rw-r--r-- | coip/apps/opensocial/serializer.py | 130 | ||||
-rw-r--r-- | coip/apps/userprofile/models.py | 2 | ||||
-rw-r--r-- | coip/apps/userprofile/views.py | 1 |
5 files changed, 176 insertions, 70 deletions
diff --git a/coip/apps/opensocial/__init__.py b/coip/apps/opensocial/__init__.py index 289f68c..6f81e98 100644 --- a/coip/apps/opensocial/__init__.py +++ b/coip/apps/opensocial/__init__.py @@ -1,6 +1,8 @@ from tastypie.api import Api -from coip.apps.opensocial.people import PersonResource, MembershipResource +from coip.apps.opensocial.people import PersonResource, MembershipResource,\ + GroupResource opensocial_v1 = Api(api_name = "1.0") opensocial_v1.register(PersonResource()) -opensocial_v1.register(MembershipResource())
\ No newline at end of file +opensocial_v1.register(MembershipResource()) +opensocial_v1.register(GroupResource())
\ No newline at end of file diff --git a/coip/apps/opensocial/people.py b/coip/apps/opensocial/people.py index 128b2c7..4572829 100644 --- a/coip/apps/opensocial/people.py +++ b/coip/apps/opensocial/people.py @@ -9,30 +9,115 @@ from django.contrib.auth.models import User from coip.apps.opensocial.serializer import OpenSocialSerializer from django.conf.urls.defaults import url from coip.apps.membership.models import Membership -from tastypie.fields import ToManyField, ToOneField +from tastypie.fields import ToOneField from tastypie.utils.urls import trailing_slash from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from tastypie.http import HttpGone, HttpMultipleChoices +from coip.apps.name.models import Name +from tastypie.constants import ALL_WITH_RELATIONS +from django.shortcuts import get_object_or_404 import logging -from tastypie.serializers import Serializer from pprint import pformat +from tastypie.bundle import Bundle -class MembershipResource(ModelResource): +_rekey = { + 'objects': 'entry' +} + +class OpenSocialResource(ModelResource): + + def _restructure(self,request,data,depth): + if isinstance(data, (list,tuple)): + for v in data: + self._restructure(request,v,depth+1) + elif isinstance(data,dict): + for (key,value) in data.iteritems(): + nkey = key + if _rekey.has_key(key): + nkey = _rekey[key] + + data[nkey] = self._restructure(request,data.pop(key),depth+1) + + if data.has_key('meta') and depth == 1: + meta = data.pop('meta') + if request.GET.has_key('count'): + data['totalResults'] = meta['total_count'] + data['itemsPerPage'] = meta['limit'] + data['startIndex'] = meta['offset'] + elif isinstance(data,Bundle): + pass + + return data + + def alter_list_data_to_serialize(self,request,data): + return self._restructure(request,{'response':data},0) + + def alter_detail_data_to_serialize(self,request,data): + return self._restructure(request,{'response': data},0) + +class GroupResource(OpenSocialResource): + + class Meta: + queryset = Name.objects.all() + serializer = OpenSocialSerializer() + resource_name = 'groups' + fields = ['short','description','id'] + + def override_urls(self): + return [ + url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)/(?P<group_name_id>[\d]+)%s?" % (self._meta.resource_name,trailing_slash()), + self.wrap_view('list_memberships'), name="api_list_memberships"), + url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)%s" % (self._meta.resource_name,trailing_slash()), + self.wrap_view('list_memberships'), name="api_list_memberships"), + url(r"^(?P<resource_name>%s)%s" % (self._meta.resource_name,trailing_slash()), + self.wrap_view('list_memberships'), name="api_list_memberships"), + ] + + def list_memberships(self, request, **kwargs): + logging.debug(pformat(kwargs)) + try: + user = self.cached_obj_get(request=request, username=kwargs['username']) + logging.debug(pformat(user)) + except ObjectDoesNotExist: + return HttpGone() + except MultipleObjectsReturned: + return HttpMultipleChoices("More than one resource is found at this URI.") + + group_resource = GroupResource() + if kwargs.has_key('name_id'): + name_id = kwargs.pop('name_id') + return group_resource.get_list(request=request, pk=name_id) + else: + + return + + + def dispatch(self, request_type, request, **kwargs): + if kwargs.has_key('username') and kwargs['username'] == '@me': + kwargs['username'] = request.user.username + return super(GroupResource, self).dispatch(request_type, request, **kwargs) + +class MembershipResource(OpenSocialResource): user = ToOneField("coip.apps.opensocial.people.PersonResource",'user',full=True) + name = ToOneField("coip.apps.opensocial.people.GroupResource",'name',full=False) class Meta: queryset = Membership.objects.all() serializer = OpenSocialSerializer() resource_name = 'membership' - fields = ['user'] + fields = ['user','name'] + filtering = { + 'name': ALL_WITH_RELATIONS + } def dehydrate(self,bundle): bundle = super(MembershipResource,self).dehydrate(bundle) del bundle.data['resource_uri'] + logging.debug(pformat(bundle)) return bundle -class PersonResource(ModelResource): +class PersonResource(OpenSocialResource): #memberships = ToManyField(MembershipResource,'memberships',full=True) @@ -44,7 +129,7 @@ class PersonResource(ModelResource): def override_urls(self): return [ - url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)/(?P<pk>[\d]+)%s?" % (self._meta.resource_name,trailing_slash()), + url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)/(?P<name_id>[\d]+)%s?" % (self._meta.resource_name,trailing_slash()), self.wrap_view('list_memberships'), name="api_list_memberships"), url(r"^(?P<resource_name>%s)/(?P<username>[\@\w\d_.-:]+)(?:/\@self)?%s" % (self._meta.resource_name,trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), @@ -53,15 +138,17 @@ class PersonResource(ModelResource): def list_memberships(self, request, **kwargs): logging.debug(pformat(kwargs)) try: - obj = self.cached_obj_get(request=request, username=kwargs['username']) - logging.debug(pformat(obj)) + user = self.cached_obj_get(request=request, username=kwargs['username']) + logging.debug(pformat(user)) except ObjectDoesNotExist: return HttpGone() except MultipleObjectsReturned: return HttpMultipleChoices("More than one resource is found at this URI.") - membership_resource = MembershipResource() - return membership_resource.get_list(request, group__owner_id=obj.pk) + people_resource = PersonResource() + name_id = kwargs.pop('name_id') + name = get_object_or_404(Name,id=name_id) + return people_resource.get_list(request=request, memberships__name=name) def dispatch(self, request_type, request, **kwargs): if kwargs.has_key('username') and kwargs['username'] == '@me': diff --git a/coip/apps/opensocial/serializer.py b/coip/apps/opensocial/serializer.py index 14ac2df..df0dcc3 100644 --- a/coip/apps/opensocial/serializer.py +++ b/coip/apps/opensocial/serializer.py @@ -4,87 +4,101 @@ Created on Jun 19, 2011 @author: leifj ''' from tastypie.serializers import Serializer, get_type_string -from lxml.etree import Element from tastypie.bundle import Bundle -from tastypie.fields import ApiField, ToOneField, ToManyField +from django.utils import simplejson from django.utils.encoding import force_unicode +import string import logging from pprint import pformat +from django.core.exceptions import ImproperlyConfigured +from django.core.serializers import json + +try: + import lxml + from lxml.etree import parse as parse_xml + from lxml.etree import Element, tostring +except ImportError: + lxml = None class OpenSocialSerializer(Serializer): def __init__(self, formats=None, content_types=None, datetime_formatting=None): super(OpenSocialSerializer,self).__init__(formats,content_types,datetime_formatting) - def to_etree(self, data, options=None, name=None, depth=0): + def name_data(self,data): + name = 'unknown' + + if hasattr(data,"resource_name"): + name = data.resource_name() + + if isinstance(data,Bundle): + name = self.name_data(data.obj) + elif hasattr(data,"__class__"): + name = string.lower(data.__class__.__name__) - #logging.debug("--------") - #logging.debug(name) - #logging.debug(depth) - #logging.debug(pformat(data)) + return name + + def to_json(self, data, options=None): + """ + Given some Python data, produces JSON output. + """ + options = options or {} + data = self.to_simple(data, options) + return simplejson.dumps(data['response'], cls=json.DjangoJSONEncoder, sort_keys=True) + + def to_xml(self, data, options=None): + """ + Given some Python data, produces XML output. + """ + options = options or {} + + if lxml is None: + raise ImproperlyConfigured("Usage of the XML aspects requires lxml.") + + etree = self.to_etree(data, options) + etree.set("xmlns","http://ns.opensocial.org/2008/opensocial") + + return tostring(etree, xml_declaration=True, encoding='utf-8') + + def to_etree(self, data, options=None, name=None, depth=0, parent=None): """ Given some data, converts that data to an ``etree.Element`` suitable for use in the XML output. """ - + + if parent is not None: + logging.debug("+++++++++++ %d %s %s" % (depth,name,tostring(parent))) + else: + logging.debug("+++++++++++ %d %s <no parent>" % (depth,name)) + logging.debug(pformat(data)) + + if parent is None: + parent = Element(name or self.name_data(data)) + if isinstance(data, (list, tuple)): - element = Element(name or 'objects') - if name: - element = Element(name) - #element.set('type', 'list') - else: - element = Element('objects') for item in data: - element.append(self.to_etree(item, options, depth=depth+1)) + element = Element(name or 'item') + self.to_etree(item, options, depth=depth+1,parent=element) + parent.append(element) elif isinstance(data, dict): - if depth == 0: - element = Element(name or 'response',attrib={'xmlns': "http://ns.opensocial.org/2008/opensocial"} ) + if len(data) == 1 and depth == 0: + for (key,value) in data.iteritems(): + parent = self.to_etree(value, options, name=key, depth=depth+1,parent=None) else: - element = Element(name or 'object') - element.set('type', 'hash') - - if data.has_key('objects'): - if len(data['objects']) == 1: - return self.to_etree(data['objects'][0], options, name=None, depth=depth) - else: - for v in data['objects']: - element.append(self.to_etree(v, options, name='entry', depth=depth+1)) - else: - for (key, value) in data.iteritems(): - keyname = key - if keyname == 'user': - keyname = 'person' - element.append(self.to_etree(value, options, name=keyname, depth=depth+1)) - elif isinstance(data, Bundle): - element = Element(name or 'object') + for (key,value) in data.iteritems(): + parent.append(self.to_etree(value, options, name=key, depth=depth+1,parent=parent)) + elif isinstance(data, Bundle): + element = Element(self.name_data(data)) for field_name, field_object in data.data.items(): - keyname = field_name - if keyname == 'user': - keyname = 'person' - element.append(self.to_etree(field_object, options, name=keyname, depth=depth+1)) - elif isinstance(data, ApiField): - if isinstance(data, ToOneField): - if data.full: - return self.to_etree(data.fk_resource, options, name, depth+1) - else: - return self.to_etree(data.value, options, name, depth+1) - elif isinstance(data, ToManyField): - if data.full: - element = Element(name or 'objects') - for bundle in data.m2m_bundles: - element.append(self.to_etree(bundle, options, bundle.resource_name, depth+1)) - else: - element = Element(name or 'objects') - for value in data.value: - element.append(self.to_etree(value, options, name, depth=depth+1)) - else: - return self.to_etree(data.value, options, name) + self.to_etree(field_object, options, name=field_name, depth=depth+1, parent=element) + parent.append(element) else: element = Element(name or 'value') simple_data = self.to_simple(data, options) data_type = get_type_string(simple_data) - if data_type != 'string': - element.set('type', get_type_string(simple_data)) + #if data_type != 'string': + # element.set('type', get_type_string(simple_data)) if data_type != 'null': element.text = force_unicode(simple_data) - return element
\ No newline at end of file + parent.append(element) + return parent
\ No newline at end of file diff --git a/coip/apps/userprofile/models.py b/coip/apps/userprofile/models.py index b6c2234..40751fb 100644 --- a/coip/apps/userprofile/models.py +++ b/coip/apps/userprofile/models.py @@ -5,6 +5,7 @@ Created on Jul 5, 2010 ''' from django.db import models from django.contrib.auth.models import User +from coip.apps.name.models import Name class UserProfile(models.Model): user = models.ForeignKey(User,blank=True,null=True,related_name='profiles') @@ -15,6 +16,7 @@ class UserProfile(models.Model): identifier = models.CharField(max_length=1023,unique=True) timecreated = models.DateTimeField(auto_now_add=True) lastupdated = models.DateTimeField(auto_now=True) + home = models.ForeignKey(Name,blank=True,null=True,editable=False) def __unicode__(self): return "%s [%s] - %s" % (self.identifier,self.user.username,self.display_name) diff --git a/coip/apps/userprofile/views.py b/coip/apps/userprofile/views.py index 3ca4416..5829fc3 100644 --- a/coip/apps/userprofile/views.py +++ b/coip/apps/userprofile/views.py @@ -48,6 +48,7 @@ def home(request): profile = user_profile(request) home = lookup('user:'+request.user.username,autocreate=True) home.short = "%s (%s)" % (profile.display_name,profile.identifier) + profile.home = home home.save() add_member(home,profile.user,hidden=True) home.setacl(home,"rwlda") #don't allow users to delete or reset acls on their home, nor invite members - that would be confusing as hell |