root / snf-cyclades-app / synnefo / ui / userdata / rest.py @ 3ec71573
History | View | Annotate | Download (8.6 kB)
1 | 49f50673 | Vangelis Koukis | #
|
---|---|---|---|
2 | 49f50673 | Vangelis Koukis | # Copyright 2011 GRNET S.A. All rights reserved.
|
3 | 49f50673 | Vangelis Koukis | #
|
4 | 49f50673 | Vangelis Koukis | # Redistribution and use in source and binary forms, with or
|
5 | 49f50673 | Vangelis Koukis | # without modification, are permitted provided that the following
|
6 | 49f50673 | Vangelis Koukis | # conditions are met:
|
7 | 49f50673 | Vangelis Koukis | #
|
8 | 49f50673 | Vangelis Koukis | # 1. Redistributions of source code must retain the above
|
9 | 49f50673 | Vangelis Koukis | # copyright notice, this list of conditions and the following
|
10 | 49f50673 | Vangelis Koukis | # disclaimer.
|
11 | 49f50673 | Vangelis Koukis | #
|
12 | 49f50673 | Vangelis Koukis | # 2. Redistributions in binary form must reproduce the above
|
13 | 49f50673 | Vangelis Koukis | # copyright notice, this list of conditions and the following
|
14 | 49f50673 | Vangelis Koukis | # disclaimer in the documentation and/or other materials
|
15 | 49f50673 | Vangelis Koukis | # provided with the distribution.
|
16 | 49f50673 | Vangelis Koukis | #
|
17 | 49f50673 | Vangelis Koukis | # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
|
18 | 49f50673 | Vangelis Koukis | # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
19 | 49f50673 | Vangelis Koukis | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
20 | 49f50673 | Vangelis Koukis | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
|
21 | 49f50673 | Vangelis Koukis | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
22 | 49f50673 | Vangelis Koukis | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
23 | 49f50673 | Vangelis Koukis | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
24 | 49f50673 | Vangelis Koukis | # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
25 | 49f50673 | Vangelis Koukis | # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
26 | 49f50673 | Vangelis Koukis | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
27 | 49f50673 | Vangelis Koukis | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
28 | 49f50673 | Vangelis Koukis | # POSSIBILITY OF SUCH DAMAGE.
|
29 | 49f50673 | Vangelis Koukis | #
|
30 | 49f50673 | Vangelis Koukis | # The views and conclusions contained in the software and
|
31 | 49f50673 | Vangelis Koukis | # documentation are those of the authors and should not be
|
32 | 49f50673 | Vangelis Koukis | # interpreted as representing official policies, either expressed
|
33 | 49f50673 | Vangelis Koukis | # or implied, of GRNET S.A.
|
34 | 49f50673 | Vangelis Koukis | |
35 | eee0487e | Kostas Papadimitriou | from django import http |
36 | eee0487e | Kostas Papadimitriou | from django.template import RequestContext, loader |
37 | eee0487e | Kostas Papadimitriou | from django.utils import simplejson as json |
38 | eee0487e | Kostas Papadimitriou | from django.core import serializers |
39 | b896d198 | Kostas Papadimitriou | from django.core.urlresolvers import reverse |
40 | 3ec71573 | Kostas Papadimitriou | from django.http import HttpResponse |
41 | eee0487e | Kostas Papadimitriou | |
42 | c72a830d | Kostas Papadimitriou | from django.core.exceptions import ValidationError, NON_FIELD_ERRORS |
43 | c72a830d | Kostas Papadimitriou | |
44 | 5facd191 | Kostas Papadimitriou | from synnefo.lib.astakos import get_user |
45 | 5facd191 | Kostas Papadimitriou | from django.conf import settings |
46 | 5facd191 | Kostas Papadimitriou | |
47 | eee0487e | Kostas Papadimitriou | # base view class
|
48 | eee0487e | Kostas Papadimitriou | # https://github.com/bfirsh/django-class-based-views/blob/master/class_based_views/base.py
|
49 | 49f50673 | Vangelis Koukis | |
50 | 49f50673 | Vangelis Koukis | |
51 | eee0487e | Kostas Papadimitriou | class View(object): |
52 | eee0487e | Kostas Papadimitriou | """
|
53 | eee0487e | Kostas Papadimitriou | Intentionally simple parent class for all views. Only implements
|
54 | eee0487e | Kostas Papadimitriou | dispatch-by-method and simple sanity checking.
|
55 | eee0487e | Kostas Papadimitriou | """
|
56 | eee0487e | Kostas Papadimitriou | |
57 | eee0487e | Kostas Papadimitriou | method_names = ['GET', 'POST', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE'] |
58 | eee0487e | Kostas Papadimitriou | |
59 | eee0487e | Kostas Papadimitriou | def __init__(self, *args, **kwargs): |
60 | eee0487e | Kostas Papadimitriou | """
|
61 | eee0487e | Kostas Papadimitriou | Constructor. Called in the URLconf; can contain helpful extra
|
62 | eee0487e | Kostas Papadimitriou | keyword arguments, and other things.
|
63 | eee0487e | Kostas Papadimitriou | """
|
64 | eee0487e | Kostas Papadimitriou | # Go through keyword arguments, and either save their values to our
|
65 | eee0487e | Kostas Papadimitriou | # instance, or raise an error.
|
66 | eee0487e | Kostas Papadimitriou | for key, value in kwargs.items(): |
67 | eee0487e | Kostas Papadimitriou | if key in self.method_names: |
68 | 49f50673 | Vangelis Koukis | raise TypeError(u"You tried to pass in the %s method name as a" |
69 | 49f50673 | Vangelis Koukis | u" keyword argument to %s(). Don't do that."
|
70 | eee0487e | Kostas Papadimitriou | % (key, self.__class__.__name__))
|
71 | eee0487e | Kostas Papadimitriou | if hasattr(self, key): |
72 | eee0487e | Kostas Papadimitriou | setattr(self, key, value) |
73 | eee0487e | Kostas Papadimitriou | else:
|
74 | eee0487e | Kostas Papadimitriou | raise TypeError(u"%s() received an invalid keyword %r" % ( |
75 | eee0487e | Kostas Papadimitriou | self.__class__.__name__,
|
76 | eee0487e | Kostas Papadimitriou | key, |
77 | eee0487e | Kostas Papadimitriou | )) |
78 | eee0487e | Kostas Papadimitriou | |
79 | eee0487e | Kostas Papadimitriou | @classmethod
|
80 | eee0487e | Kostas Papadimitriou | def as_view(cls, *initargs, **initkwargs): |
81 | eee0487e | Kostas Papadimitriou | """
|
82 | eee0487e | Kostas Papadimitriou | Main entry point for a request-response process.
|
83 | eee0487e | Kostas Papadimitriou | """
|
84 | eee0487e | Kostas Papadimitriou | def view(request, *args, **kwargs): |
85 | 3ec71573 | Kostas Papadimitriou | user = get_user(request, settings.ASTAKOS_URL) |
86 | 3ec71573 | Kostas Papadimitriou | if not request.user_uniq: |
87 | 3ec71573 | Kostas Papadimitriou | return HttpResponse(status=401) |
88 | eee0487e | Kostas Papadimitriou | self = cls(*initargs, **initkwargs)
|
89 | eee0487e | Kostas Papadimitriou | return self.dispatch(request, *args, **kwargs) |
90 | eee0487e | Kostas Papadimitriou | return view
|
91 | eee0487e | Kostas Papadimitriou | |
92 | eee0487e | Kostas Papadimitriou | def dispatch(self, request, *args, **kwargs): |
93 | eee0487e | Kostas Papadimitriou | # Try to dispatch to the right method for that; if it doesn't exist,
|
94 | eee0487e | Kostas Papadimitriou | # raise a big error.
|
95 | eee0487e | Kostas Papadimitriou | if hasattr(self, request.method.upper()): |
96 | eee0487e | Kostas Papadimitriou | self.request = request
|
97 | eee0487e | Kostas Papadimitriou | self.args = args
|
98 | eee0487e | Kostas Papadimitriou | self.kwargs = kwargs
|
99 | eee0487e | Kostas Papadimitriou | data = request.raw_post_data |
100 | eee0487e | Kostas Papadimitriou | |
101 | eee0487e | Kostas Papadimitriou | if request.method.upper() in ['POST', 'PUT']: |
102 | eee0487e | Kostas Papadimitriou | # Expect json data
|
103 | eee0487e | Kostas Papadimitriou | if request.META.get('CONTENT_TYPE').startswith('application/json'): |
104 | eee0487e | Kostas Papadimitriou | try:
|
105 | eee0487e | Kostas Papadimitriou | data = json.loads(data) |
106 | eee0487e | Kostas Papadimitriou | except ValueError: |
107 | 3ec71573 | Kostas Papadimitriou | return http.HttpResponseServerError('Invalid JSON data.') |
108 | eee0487e | Kostas Papadimitriou | else:
|
109 | 3ec71573 | Kostas Papadimitriou | return http.HttpResponseServerError('Unsupported Content-Type.') |
110 | c72a830d | Kostas Papadimitriou | try:
|
111 | c72a830d | Kostas Papadimitriou | return getattr(self, request.method.upper())(request, data, *args, **kwargs) |
112 | c72a830d | Kostas Papadimitriou | except ValidationError, e:
|
113 | c72a830d | Kostas Papadimitriou | # specific response for validation errors
|
114 | c72a830d | Kostas Papadimitriou | return http.HttpResponseServerError(json.dumps({'errors': |
115 | c72a830d | Kostas Papadimitriou | e.message_dict, 'non_field_key':
|
116 | c72a830d | Kostas Papadimitriou | NON_FIELD_ERRORS })) |
117 | eee0487e | Kostas Papadimitriou | |
118 | eee0487e | Kostas Papadimitriou | else:
|
119 | eee0487e | Kostas Papadimitriou | allowed_methods = [m for m in self.method_names if hasattr(self, m)] |
120 | eee0487e | Kostas Papadimitriou | return http.HttpResponseNotAllowed(allowed_methods)
|
121 | eee0487e | Kostas Papadimitriou | |
122 | 49f50673 | Vangelis Koukis | |
123 | b896d198 | Kostas Papadimitriou | class JSONRestView(View): |
124 | b896d198 | Kostas Papadimitriou | """
|
125 | b896d198 | Kostas Papadimitriou | Class that provides helpers to produce a json response
|
126 | b896d198 | Kostas Papadimitriou | """
|
127 | eee0487e | Kostas Papadimitriou | |
128 | b896d198 | Kostas Papadimitriou | url_name = None
|
129 | b896d198 | Kostas Papadimitriou | def __init__(self, url_name, *args, **kwargs): |
130 | b896d198 | Kostas Papadimitriou | self.url_name = url_name
|
131 | b896d198 | Kostas Papadimitriou | return super(JSONRestView, self).__init__(*args, **kwargs) |
132 | b896d198 | Kostas Papadimitriou | |
133 | 69836bca | Kostas Papadimitriou | def update_instance(self, i, data, exclude_fields=[]): |
134 | b896d198 | Kostas Papadimitriou | update_keys = data.keys() |
135 | b896d198 | Kostas Papadimitriou | for field in i._meta.get_all_field_names(): |
136 | 69836bca | Kostas Papadimitriou | if field in update_keys and (field not in exclude_fields): |
137 | b896d198 | Kostas Papadimitriou | i.__setattr__(field, data[field]) |
138 | b896d198 | Kostas Papadimitriou | |
139 | b896d198 | Kostas Papadimitriou | return i
|
140 | b896d198 | Kostas Papadimitriou | |
141 | b896d198 | Kostas Papadimitriou | def instance_to_dict(self, i, exclude_fields=[]): |
142 | b896d198 | Kostas Papadimitriou | """
|
143 | b896d198 | Kostas Papadimitriou | Convert model instance to python dict
|
144 | b896d198 | Kostas Papadimitriou | """
|
145 | b896d198 | Kostas Papadimitriou | d = {} |
146 | b896d198 | Kostas Papadimitriou | d['uri'] = reverse(self.url_name, kwargs={'id': i.pk}) |
147 | b896d198 | Kostas Papadimitriou | |
148 | b896d198 | Kostas Papadimitriou | for field in i._meta.get_all_field_names(): |
149 | b896d198 | Kostas Papadimitriou | if field in exclude_fields: |
150 | b896d198 | Kostas Papadimitriou | continue
|
151 | b896d198 | Kostas Papadimitriou | |
152 | b896d198 | Kostas Papadimitriou | d[field] = i.__getattribute__(field) |
153 | b896d198 | Kostas Papadimitriou | return d
|
154 | b896d198 | Kostas Papadimitriou | |
155 | b896d198 | Kostas Papadimitriou | def qs_to_dict_iter(self, qs, exclude_fields=[]): |
156 | b896d198 | Kostas Papadimitriou | """
|
157 | b896d198 | Kostas Papadimitriou | Convert queryset to an iterator of model instances dicts
|
158 | b896d198 | Kostas Papadimitriou | """
|
159 | b896d198 | Kostas Papadimitriou | for i in qs: |
160 | b896d198 | Kostas Papadimitriou | yield self.instance_to_dict(i, exclude_fields) |
161 | b896d198 | Kostas Papadimitriou | |
162 | b896d198 | Kostas Papadimitriou | def json_response(self, data): |
163 | b896d198 | Kostas Papadimitriou | return http.HttpResponse(json.dumps(data), mimetype="application/json") |
164 | b896d198 | Kostas Papadimitriou | |
165 | 49f50673 | Vangelis Koukis | |
166 | b896d198 | Kostas Papadimitriou | class ResourceView(JSONRestView): |
167 | eee0487e | Kostas Papadimitriou | method_names = ['GET', 'POST', 'PUT', 'DELETE'] |
168 | eee0487e | Kostas Papadimitriou | |
169 | eee0487e | Kostas Papadimitriou | model = None
|
170 | eee0487e | Kostas Papadimitriou | exclude_fields = [] |
171 | eee0487e | Kostas Papadimitriou | |
172 | eee0487e | Kostas Papadimitriou | def queryset(self): |
173 | eee0487e | Kostas Papadimitriou | return self.model.objects.all() |
174 | eee0487e | Kostas Papadimitriou | |
175 | eee0487e | Kostas Papadimitriou | def instance(self): |
176 | eee0487e | Kostas Papadimitriou | """
|
177 | eee0487e | Kostas Papadimitriou | Retrieve selected instance based on url parameter
|
178 | eee0487e | Kostas Papadimitriou |
|
179 | eee0487e | Kostas Papadimitriou | id parameter should be set in urlpatterns expression
|
180 | eee0487e | Kostas Papadimitriou | """
|
181 | eee0487e | Kostas Papadimitriou | try:
|
182 | eee0487e | Kostas Papadimitriou | return self.queryset().get(pk=self.kwargs.get("id")) |
183 | eee0487e | Kostas Papadimitriou | except self.model.DoesNotExist: |
184 | eee0487e | Kostas Papadimitriou | raise http.Http404
|
185 | eee0487e | Kostas Papadimitriou | |
186 | eee0487e | Kostas Papadimitriou | def GET(self, request, data, *args, **kwargs): |
187 | eee0487e | Kostas Papadimitriou | return self.json_response(self.instance_to_dict(self.instance(), |
188 | eee0487e | Kostas Papadimitriou | self.exclude_fields))
|
189 | eee0487e | Kostas Papadimitriou | |
190 | 69836bca | Kostas Papadimitriou | def PUT(self, request, data, *args, **kwargs): |
191 | b896d198 | Kostas Papadimitriou | instance = self.instance()
|
192 | 69836bca | Kostas Papadimitriou | self.update_instance(instance, data, self.exclude_fields) |
193 | c72a830d | Kostas Papadimitriou | instance.full_clean() |
194 | b896d198 | Kostas Papadimitriou | instance.save() |
195 | b896d198 | Kostas Papadimitriou | return self.GET(request, data, *args, **kwargs) |
196 | eee0487e | Kostas Papadimitriou | |
197 | eee0487e | Kostas Papadimitriou | def DELETE(self, request, data, *args, **kwargs): |
198 | eee0487e | Kostas Papadimitriou | self.instance().delete()
|
199 | b896d198 | Kostas Papadimitriou | return self.json_response("") |
200 | eee0487e | Kostas Papadimitriou | |
201 | eee0487e | Kostas Papadimitriou | |
202 | b896d198 | Kostas Papadimitriou | class CollectionView(JSONRestView): |
203 | b896d198 | Kostas Papadimitriou | method_names = ['GET', 'POST'] |
204 | eee0487e | Kostas Papadimitriou | |
205 | eee0487e | Kostas Papadimitriou | model = None
|
206 | eee0487e | Kostas Papadimitriou | exclude_fields = [] |
207 | eee0487e | Kostas Papadimitriou | |
208 | eee0487e | Kostas Papadimitriou | def queryset(self): |
209 | eee0487e | Kostas Papadimitriou | return self.model.objects.all() |
210 | eee0487e | Kostas Papadimitriou | |
211 | eee0487e | Kostas Papadimitriou | def GET(self, request, data, *args, **kwargs): |
212 | eee0487e | Kostas Papadimitriou | return self.json_response(list(self.qs_to_dict_iter(self.queryset(), |
213 | eee0487e | Kostas Papadimitriou | self.exclude_fields)))
|
214 | eee0487e | Kostas Papadimitriou | |
215 | b896d198 | Kostas Papadimitriou | def POST(self, request, data, *args, **kwargs): |
216 | 69836bca | Kostas Papadimitriou | instance = self.model()
|
217 | 69836bca | Kostas Papadimitriou | self.update_instance(instance, data, self.exclude_fields) |
218 | c72a830d | Kostas Papadimitriou | instance.full_clean() |
219 | 69836bca | Kostas Papadimitriou | instance.save() |
220 | 69836bca | Kostas Papadimitriou | return self.json_response(self.instance_to_dict(instance, |
221 | 69836bca | Kostas Papadimitriou | self.exclude_fields))
|
222 | eee0487e | Kostas Papadimitriou | |
223 | 49f50673 | Vangelis Koukis | |
224 | eee0487e | Kostas Papadimitriou | class UserResourceView(ResourceView): |
225 | eee0487e | Kostas Papadimitriou | """
|
226 | eee0487e | Kostas Papadimitriou | Filter resource queryset for request user entries
|
227 | eee0487e | Kostas Papadimitriou | """
|
228 | eee0487e | Kostas Papadimitriou | def queryset(self): |
229 | eee0487e | Kostas Papadimitriou | return super(UserResourceView, |
230 | 3ec71573 | Kostas Papadimitriou | self).queryset().filter(user=self.request.user_uniq) |
231 | eee0487e | Kostas Papadimitriou | |
232 | 49f50673 | Vangelis Koukis | |
233 | eee0487e | Kostas Papadimitriou | class UserCollectionView(CollectionView): |
234 | eee0487e | Kostas Papadimitriou | """
|
235 | eee0487e | Kostas Papadimitriou | Filter collection queryset for request user entries
|
236 | eee0487e | Kostas Papadimitriou | """
|
237 | eee0487e | Kostas Papadimitriou | def queryset(self): |
238 | 4b3b8688 | Giorgos Verigakis | return super(UserCollectionView, self).queryset().filter(user=self.request.user_uniq) |
239 | eee0487e | Kostas Papadimitriou | |
240 | 69836bca | Kostas Papadimitriou | def POST(self, request, data, *args, **kwargs): |
241 | 69836bca | Kostas Papadimitriou | instance = self.model()
|
242 | 69836bca | Kostas Papadimitriou | self.update_instance(instance, data, self.exclude_fields) |
243 | 3ec71573 | Kostas Papadimitriou | instance.user = request.user_uniq |
244 | c72a830d | Kostas Papadimitriou | instance.full_clean() |
245 | 69836bca | Kostas Papadimitriou | instance.save() |
246 | 69836bca | Kostas Papadimitriou | return self.json_response(self.instance_to_dict(instance, |
247 | 69836bca | Kostas Papadimitriou | self.exclude_fields)) |