Revision eee0487e

b/settings.d/00-apps.conf
17 17
    'synnefo.logic',
18 18
    'synnefo.invitations',
19 19
    'synnefo.helpdesk',
20
    'synnefo.userdata',
21

  
20 22
    'south'
21 23
)
22 24

  
b/userdata/migrations/0001_initial.py
1
# encoding: utf-8
2
import datetime
3
from south.db import db
4
from south.v2 import SchemaMigration
5
from django.db import models
6

  
7
class Migration(SchemaMigration):
8

  
9
    def forwards(self, orm):
10
        
11
        # Adding model 'PublicKeyPair'
12
        db.create_table('userdata_publickeypair', (
13
            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
14
            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['db.SynnefoUser'])),
15
            ('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
16
            ('content', self.gf('django.db.models.fields.TextField')()),
17
        ))
18
        db.send_create_signal('userdata', ['PublicKeyPair'])
19

  
20

  
21
    def backwards(self, orm):
22
        
23
        # Deleting model 'PublicKeyPair'
24
        db.delete_table('userdata_publickeypair')
25

  
26

  
27
    models = {
28
        'db.synnefouser': {
29
            'Meta': {'object_name': 'SynnefoUser'},
30
            'auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
31
            'auth_token_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
32
            'auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
33
            'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
34
            'credit': ('django.db.models.fields.IntegerField', [], {}),
35
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
36
            'max_invitations': ('django.db.models.fields.IntegerField', [], {'null': 'True'}),
37
            'name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
38
            'realname': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255'}),
39
            'state': ('django.db.models.fields.CharField', [], {'default': "'ACTIVE'", 'max_length': '30'}),
40
            'tmp_auth_token': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
41
            'tmp_auth_token_expires': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
42
            'type': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
43
            'uniq': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
44
            'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
45
        },
46
        'userdata.publickeypair': {
47
            'Meta': {'object_name': 'PublicKeyPair'},
48
            'content': ('django.db.models.fields.TextField', [], {}),
49
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
50
            'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
51
            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['db.SynnefoUser']"})
52
        }
53
    }
54

  
55
    complete_apps = ['userdata']
b/userdata/models.py
1
from django.db import models
2
from synnefo.db import models as synnefo_models
3

  
4
User = synnefo_models.SynnefoUser
5

  
6
class ProfileModel(models.Model):
7
    """
8
    Abstract model, provides a basic interface for models that store
9
    user specific information
10
    """
11

  
12
    user = models.ForeignKey(User)
13

  
14
    class Meta:
15
        abstract = True
16

  
17

  
18
class PublicKeyPair(ProfileModel):
19
    """
20
    Public key model
21
    """
22
    name = models.CharField(max_length=255, null=False, blank=False)
23
    content = models.TextField()
24

  
b/userdata/rest.py
1
from django import http
2
from django.template import RequestContext, loader
3
from django.utils import simplejson as json
4
from django.core import serializers
5

  
6
# base view class
7
# https://github.com/bfirsh/django-class-based-views/blob/master/class_based_views/base.py
8
class View(object):
9
    """
10
    Intentionally simple parent class for all views. Only implements
11
    dispatch-by-method and simple sanity checking.
12
    """
13

  
14
    method_names = ['GET', 'POST', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE']
15

  
16
    def __init__(self, *args, **kwargs):
17
        """
18
        Constructor. Called in the URLconf; can contain helpful extra
19
        keyword arguments, and other things.
20
        """
21
        # Go through keyword arguments, and either save their values to our
22
        # instance, or raise an error.
23
        for key, value in kwargs.items():
24
            if key in self.method_names:
25
                raise TypeError(u"You tried to pass in the %s method name as a "
26
                                u"keyword argument to %s(). Don't do that."
27
                                % (key, self.__class__.__name__))
28
            if hasattr(self, key):
29
                setattr(self, key, value)
30
            else:
31
                raise TypeError(u"%s() received an invalid keyword %r" % (
32
                    self.__class__.__name__,
33
                    key,
34
                ))
35

  
36
    def instance_to_dict(self, i, exclude_fields=[]):
37
        """
38
        Convert model instance to python dict
39
        """
40
        d = {}
41
        for field in i._meta.get_all_field_names():
42
            if field in exclude_fields:
43
                continue
44

  
45
            d[field] = i.__getattribute__(field)
46
        return d
47

  
48
    def qs_to_dict_iter(self, qs, exclude_fields=[]):
49
        """
50
        Convert queryset to an iterator of model instances dicts
51
        """
52
        for i in qs:
53
            yield self.instance_to_dict(i, exclude_fields)
54

  
55
    def json_response(self, data):
56
        return http.HttpResponse(json.dumps(data))
57

  
58
    @classmethod
59
    def as_view(cls, *initargs, **initkwargs):
60
        """
61
        Main entry point for a request-response process.
62
        """
63
        def view(request, *args, **kwargs):
64
            self = cls(*initargs, **initkwargs)
65
            return self.dispatch(request, *args, **kwargs)
66
        return view
67

  
68
    def dispatch(self, request, *args, **kwargs):
69
        # Try to dispatch to the right method for that; if it doesn't exist,
70
        # raise a big error.
71
        if hasattr(self, request.method.upper()):
72
            self.request = request
73
            self.args = args
74
            self.kwargs = kwargs
75
            data = request.raw_post_data
76

  
77
            if request.method.upper() in ['POST', 'PUT']:
78
                # Expect json data
79
                if request.META.get('CONTENT_TYPE').startswith('application/json'):
80
                    try:
81
                        data = json.loads(data)
82
                    except ValueError:
83
                        raise http.HttpResponseServerError('Invalid JSON data.')
84
                else:
85
                    raise http.HttpResponseServerError('Unsupported Content-Type.')
86

  
87
            return getattr(self, request.method.upper())(request, data, *args, **kwargs)
88
        else:
89
            allowed_methods = [m for m in self.method_names if hasattr(self, m)]
90
            return http.HttpResponseNotAllowed(allowed_methods)
91

  
92

  
93
class ResourceView(View):
94
    method_names = ['GET', 'POST', 'PUT', 'DELETE']
95

  
96
    model = None
97
    exclude_fields = []
98

  
99
    def queryset(self):
100
        return self.model.objects.all()
101

  
102
    def instance(self):
103
        """
104
        Retrieve selected instance based on url parameter
105

  
106
        id parameter should be set in urlpatterns expression
107
        """
108
        try:
109
            return self.queryset().get(pk=self.kwargs.get("id"))
110
        except self.model.DoesNotExist:
111
            raise http.Http404
112

  
113
    def GET(self, request, data, *args, **kwargs):
114
        return self.json_response(self.instance_to_dict(self.instance(),
115
            self.exclude_fields))
116

  
117
    def POST(self, request, data, *args, **kwargs):
118
        pass
119

  
120
    def DELETE(self, request, data, *args, **kwargs):
121
        self.instance().delete()
122
        return HttpResponse()
123

  
124

  
125
class CollectionView(View):
126
    method_names = ['GET', 'POST', 'PUT', 'DELETE']
127

  
128
    model = None
129
    exclude_fields = []
130

  
131
    def queryset(self):
132
        return self.model.objects.all()
133

  
134
    def GET(self, request, data, *args, **kwargs):
135
        return self.json_response(list(self.qs_to_dict_iter(self.queryset(),
136
            self.exclude_fields)))
137

  
138
    def PUT(self, request, data, *args, **kwargs):
139
        pass
140

  
141
    def DELETE(self, request, data, *args, **kwargs):
142
        pass
143

  
144
class UserResourceView(ResourceView):
145
    """
146
    Filter resource queryset for request user entries
147
    """
148
    def queryset(self):
149
        return super(UserResourceView,
150
                self).queryset().filter(user=self.request.user)
151

  
152
class UserCollectionView(CollectionView):
153
    """
154
    Filter collection queryset for request user entries
155
    """
156
    def queryset(self):
157
        return super(UserCollectionView, self).queryset().filter(user=self.request.user)
158

  
b/userdata/tests.py
1
"""
2
This file demonstrates two different styles of tests (one doctest and one
3
unittest). These will both pass when you run "manage.py test".
4

  
5
Replace these with more appropriate tests for your application.
6
"""
7

  
8
from django.test import TestCase
9
from django.conf import settings
10
from django.test.client import Client
11
from django.core.urlresolvers import clear_url_caches
12

  
13
from synnefo.userdata.models import User
14
from synnefo.userdata.models import *
15

  
16
class AaiClient(Client):
17

  
18
    def request(self, **request):
19
        request['HTTP_X_AUTH_TOKEN'] = '46e427d657b20defe352804f0eb6f8a2'
20
        return super(AaiClient, self).request(**request)
21

  
22
class TestRestViews(TestCase):
23

  
24
    fixtures = ['users']
25

  
26
    def setUp(self):
27
        settings.ROOT_URLCONF = 'synnefo.userdata.urls'
28
        clear_url_caches()
29
        self.client = AaiClient()
30
        self.user = User.objects.get(pk=1)
31

  
32
    def test_keys_collection_get(self):
33
        resp = self.client.get("/keys/")
34
        self.assertEqual(resp.content, "[]")
35

  
36
        PublicKeyPair.objects.create(user=self.user, name="key pair 1",
37
                content="content1")
38

  
39
        resp = self.client.get("/keys/")
40
        self.assertEqual(resp.content, """[{"content": "content1", "id": 1, "name": "key pair 1"}]""")
41

  
42
        PublicKeyPair.objects.create(user=self.user, name="key pair 2",
43
                content="content2")
44

  
45
        resp = self.client.get("/keys/")
46
        self.assertEqual(resp.content, """[{"content": "content1", "id": 1, "name": "key pair 1"}, {"content": "content2", "id": 2, "name": "key pair 2"}]""")
47

  
48
    def test_keys_resourse_get(self):
49
        pass
b/userdata/urls.py
1
from django.conf.urls.defaults import *
2
from synnefo.userdata import views
3

  
4
urlpatterns = patterns('',
5
    (r'^keys/$', views.PublicKeyPairCollectionView.as_view()),
6
    (r'^keys/(?P<id>\d+)/$', views.PublicKeyPairResourceView.as_view()),
7
)
b/userdata/views.py
1
from django import http
2
from django.template import RequestContext, loader
3
from django.utils import simplejson as json
4

  
5
from synnefo.userdata import rest
6
from synnefo.userdata.models import PublicKeyPair
7

  
8
class PublicKeyPairResourceView(rest.UserResourceView):
9
    model = PublicKeyPair
10
    exclude_fields = ["user"]
11

  
12
class PublicKeyPairCollectionView(rest.UserCollectionView):
13
    model = PublicKeyPair
14
    exclude_fields = ["user"]

Also available in: Unified diff