diff options
Diffstat (limited to 'coip')
-rw-r--r-- | coip/apps/api/__init__.py | 6 | ||||
-rw-r--r-- | coip/apps/api/resources.py | 16 | ||||
-rw-r--r-- | coip/apps/membership/models.py | 4 | ||||
-rw-r--r-- | coip/apps/opensocial/__init__.py | 6 | ||||
-rw-r--r-- | coip/apps/opensocial/people.py | 77 | ||||
-rw-r--r-- | coip/apps/opensocial/serializer.py | 90 | ||||
-rw-r--r-- | coip/settings.py | 7 | ||||
-rw-r--r-- | coip/urls.py | 10 | ||||
-rw-r--r-- | coip/uuidfield.py | 61 |
9 files changed, 270 insertions, 7 deletions
diff --git a/coip/apps/api/__init__.py b/coip/apps/api/__init__.py new file mode 100644 index 0000000..3dd6dd2 --- /dev/null +++ b/coip/apps/api/__init__.py @@ -0,0 +1,6 @@ +from tastypie.api import Api +from coip.apps.api.resources import UserResource, NameResource + +v1_api = Api(api_name="1.0") +v1_api.register(UserResource()) +v1_api.register(NameResource())
\ No newline at end of file diff --git a/coip/apps/api/resources.py b/coip/apps/api/resources.py new file mode 100644 index 0000000..974b146 --- /dev/null +++ b/coip/apps/api/resources.py @@ -0,0 +1,16 @@ +''' +Created on Jun 18, 2011 + +@author: leifj +''' +from tastypie.resources import ModelResource +from django.contrib.auth.models import User +from coip.apps.name.models import Name + +class UserResource(ModelResource): + class Meta: + queryset = User.objects.all() + +class NameResource(ModelResource): + class Meta: + queryset = Name.objects.all()
\ No newline at end of file diff --git a/coip/apps/membership/models.py b/coip/apps/membership/models.py index 0884cd1..b19c04a 100644 --- a/coip/apps/membership/models.py +++ b/coip/apps/membership/models.py @@ -17,8 +17,8 @@ class Membership(models.Model): ''' Membership in a namespace/group ''' - user = models.ForeignKey(User,blank=True,null=True,related_name='user') - entity = models.ForeignKey(Entity,blank=True,null=True,related_name='entity') + user = models.ForeignKey(User,blank=True,null=True,related_name='memberships') + entity = models.ForeignKey(Entity,blank=True,null=True,related_name='entity') # XXX should this be memberships too? name = models.ForeignKey(Name,related_name='memberships') enabled = models.BooleanField() hidden = models.BooleanField() diff --git a/coip/apps/opensocial/__init__.py b/coip/apps/opensocial/__init__.py new file mode 100644 index 0000000..289f68c --- /dev/null +++ b/coip/apps/opensocial/__init__.py @@ -0,0 +1,6 @@ +from tastypie.api import Api +from coip.apps.opensocial.people import PersonResource, MembershipResource + +opensocial_v1 = Api(api_name = "1.0") +opensocial_v1.register(PersonResource()) +opensocial_v1.register(MembershipResource())
\ No newline at end of file diff --git a/coip/apps/opensocial/people.py b/coip/apps/opensocial/people.py new file mode 100644 index 0000000..128b2c7 --- /dev/null +++ b/coip/apps/opensocial/people.py @@ -0,0 +1,77 @@ +''' +Created on Jun 19, 2011 + +@author: leifj +''' +from tastypie.resources import ModelResource +from coip.apps.userprofile.models import UserProfile, last_used_profile +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.utils.urls import trailing_slash +from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned +from tastypie.http import HttpGone, HttpMultipleChoices +import logging +from tastypie.serializers import Serializer +from pprint import pformat + +class MembershipResource(ModelResource): + + user = ToOneField("coip.apps.opensocial.people.PersonResource",'user',full=True) + + class Meta: + queryset = Membership.objects.all() + serializer = OpenSocialSerializer() + resource_name = 'membership' + fields = ['user'] + + def dehydrate(self,bundle): + bundle = super(MembershipResource,self).dehydrate(bundle) + del bundle.data['resource_uri'] + return bundle + +class PersonResource(ModelResource): + + #memberships = ToManyField(MembershipResource,'memberships',full=True) + + class Meta: + queryset = User.objects.all() + fields = ['username'] + resource_name = 'people' + serializer = OpenSocialSerializer() + + 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()), + 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"), + ] + + 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)) + 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) + + def dispatch(self, request_type, request, **kwargs): + if kwargs.has_key('username') and kwargs['username'] == '@me': + kwargs['username'] = request.user.username + return super(PersonResource, self).dispatch(request_type, request, **kwargs) + + def dehydrate(self,bundle): + bundle = super(PersonResource,self).dehydrate(bundle) + bundle.data['id'] = bundle.data['username'] + bundle.data['displayName'] = last_used_profile(bundle.obj).display_name + del bundle.data['resource_uri'] + del bundle.data['username'] + return bundle
\ No newline at end of file diff --git a/coip/apps/opensocial/serializer.py b/coip/apps/opensocial/serializer.py new file mode 100644 index 0000000..14ac2df --- /dev/null +++ b/coip/apps/opensocial/serializer.py @@ -0,0 +1,90 @@ +''' +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.encoding import force_unicode +import logging +from pprint import pformat + +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): + + #logging.debug("--------") + #logging.debug(name) + #logging.debug(depth) + #logging.debug(pformat(data)) + """ + Given some data, converts that data to an ``etree.Element`` suitable + for use in the XML output. + """ + + 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)) + elif isinstance(data, dict): + if depth == 0: + element = Element(name or 'response',attrib={'xmlns': "http://ns.opensocial.org/2008/opensocial"} ) + 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 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) + 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 != 'null': + element.text = force_unicode(simple_data) + return element
\ No newline at end of file diff --git a/coip/settings.py b/coip/settings.py index 8c43689..2a8297f 100644 --- a/coip/settings.py +++ b/coip/settings.py @@ -58,6 +58,7 @@ ADMIN_MEDIA_PREFIX = '/admin-media/' # Make this unique, and don't share it with anybody. SECRET_KEY = '!=ren*@$dklhfm$3#$h=a2g4r3)ra#+al)9kwi4&rpylr$3xnf' +SESSION_ENGINE = "django.contrib.sessions.backends.cache" # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( @@ -67,13 +68,13 @@ TEMPLATE_LOADERS = ( ) MIDDLEWARE_CLASSES = ( - 'django.middleware.cache.UpdateCacheMiddleware', + #'django.middleware.cache.UpdateCacheMiddleware', 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'coip.middleware.UserMappingMiddleware', 'django.contrib.auth.middleware.RemoteUserMiddleware', - 'django.middleware.cache.FetchFromCacheMiddleware' + #'django.middleware.cache.FetchFromCacheMiddleware' ) AUTHENTICATION_BACKENDS = ( @@ -99,6 +100,8 @@ INSTALLED_APPS = ( 'django.contrib.humanize', 'django_extensions', 'tagging', + 'tastypie', + 'oauth_provider', 'coip.extensions', 'coip.apps.name', 'coip.apps.membership', diff --git a/coip/urls.py b/coip/urls.py index 637bfa8..4b1bc6f 100644 --- a/coip/urls.py +++ b/coip/urls.py @@ -1,12 +1,13 @@ -from django.conf.urls.defaults import * - -# Uncomment the next two lines to enable the admin: +from django.conf.urls.defaults import patterns,include from django.contrib import admin from django.contrib.auth.views import login from settings import ADMIN_MEDIA_ROOT from settings import MEDIA_ROOT from django.http import HttpResponseRedirect from coip.apps.auth.views import logout +from coip.apps.opensocial import opensocial_v1 +from coip.apps.api import v1_api + admin.autodiscover() def welcome(request): @@ -64,4 +65,7 @@ urlpatterns = patterns('', (r'^ctree/(?P<id>[0-9]+).json$', 'coip.apps.name.views.ctree'), (r'^rtree.json$', 'coip.apps.name.views.rtree'), (r'^rtree/(?P<id>[0-9]+).json$', 'coip.apps.name.views.rtree'), + # APIs + (r'^api/', include(v1_api.urls)), + (r'^opensocial/', include(opensocial_v1.urls)) ) diff --git a/coip/uuidfield.py b/coip/uuidfield.py new file mode 100644 index 0000000..44a789c --- /dev/null +++ b/coip/uuidfield.py @@ -0,0 +1,61 @@ +''' +Created on Jun 19, 2011 + +@author: leifj +''' + +from django.db.models import CharField + +try: + import uuid +except ImportError: + from django.utils import uuid + +class UUIDVersionError(Exception): + pass + +class UUIDField(CharField): + """ UUIDField for Django, supports all uuid versions which are natively + suported by the uuid python module. + """ + + def __init__(self, verbose_name=None, name=None, auto=True, version=1, node=None, clock_seq=None, namespace=None, **kwargs): + kwargs['maxlength'] = 36 + if auto: + kwargs['blank'] = True + kwargs['editable'] = kwargs.get('editable', False) + self.version = version + if version==1: + self.node, self.clock_seq = node, clock_seq + elif version==3 or version==5: + self.namespace, self.name = namespace, name + CharField.__init__(self, verbose_name, name, **kwargs) + + def get_internal_type(self): + return "UUIDField" + + def create_uuid(self): + if not self.version or self.version==4: + return uuid.uuid4() + elif self.version==1: + return uuid.uuid1(self.node, self.clock_seq) + elif self.version==2: + raise UUIDVersionError("UUID version 2 is not supported.") + elif self.version==3: + return uuid.uuid3(self.namespace, self.name) + elif self.version==5: + return uuid.uuid5(self.namespace, self.name) + else: + raise UUIDVersionError("UUID version %s is not valid." % self.version) + + def pre_save(self, model_instance, add): + if self.auto and add: + value = unicode(self.create_uuid()) + setattr(model_instance, self.attname, value) + return value + else: + value = super(UUIDField, self).pre_save(model_instance, add) + if self.auto and not value: + value = unicode(self.create_uuid()) + setattr(model_instance, self.attname, value) + return value
\ No newline at end of file |