summaryrefslogtreecommitdiff
path: root/coip
diff options
context:
space:
mode:
Diffstat (limited to 'coip')
-rw-r--r--coip/apps/opensocial/__init__.py6
-rw-r--r--coip/apps/opensocial/people.py107
-rw-r--r--coip/apps/opensocial/serializer.py130
-rw-r--r--coip/apps/userprofile/models.py2
-rw-r--r--coip/apps/userprofile/views.py1
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