Merge lp:~dooferlad/linaro-ci-dashboard/add_api_tastypie into lp:linaro-ci-dashboard

Proposed by James Tunnicliffe
Status: Merged
Merged at revision: 69
Proposed branch: lp:~dooferlad/linaro-ci-dashboard/add_api_tastypie
Merge into: lp:linaro-ci-dashboard
Diff against target: 410 lines (+292/-3)
11 files modified
README (+25/-0)
dashboard/frontend/api/api.py (+56/-0)
dashboard/frontend/api/urls.py (+13/-0)
dashboard/frontend/templates/api_key.html (+6/-0)
dashboard/frontend/tests/__init__.py (+23/-0)
dashboard/frontend/tests/test_api.py (+95/-0)
dashboard/frontend/urls.py (+2/-0)
dashboard/frontend/views/api_key.py (+47/-0)
dashboard/settings.py (+9/-3)
dashboard/urls.py (+1/-0)
requirements.txt (+15/-0)
To merge this branch: bzr merge lp:~dooferlad/linaro-ci-dashboard/add_api_tastypie
Reviewer Review Type Date Requested Status
Milo Casagrande (community) Approve
Stevan Radaković Approve
Review via email: mp+146101@code.launchpad.net

Description of the change

Adds a framework for a simple RESTful API using Tastypie (http://tastypieapi.org/). This is a new requirement, listed in the README.

The current API is very limited. The intent of this MP is to get some feedback on if this is a sensible way to implement the API. Future merges will fill it out.

If you are running Ubuntu 12.04 you can run the application, just not unit test the API because it relies on LiveServerTestCase, which was introduced with Django 1.4. To work around this, instructions are provided for setting up an isolated Python environment using virtualenvwrapper are included in the README.

To post a comment you must log in.
77. By James Tunnicliffe

Added / updated copyright notices.

Revision history for this message
Stevan Radaković (stevanr) wrote :

Hey James,

Nice work rly.. I've managed to run everything pretty much smooth, tests worked, and the code looks good as well, disregarding the problem with django version for unit testing, this is really unfortunate dependency :/

First thing that kinda bothers me is that we require 'v1/' in API links. I read the tastypie docs a bit but couldn't get quick answer if this is easy to remove or not.. If there's any special reason to keep it tho, I'd like to hear it.

Second thing is just a minor code block in tests that stung me in the eye, but nothing special:

280 + # One loop is of type AndroidLoop, the other ModelBase. Find which is
281 + # which.
282 + if json[0]['type'] == 'AndroidLoop':
283 + android_loop_index = 0
284 + base_loop_index = 1
285 + else:
286 + android_loop_index = 1
287 + base_loop_index = 0
288 +
289 + # Now test the contents of the loop data
290 + self.assertEqual(json[android_loop_index]['name'],
291 + self.android_loop.name)
292 + self.assertEqual(json[base_loop_index]['name'],
293 + self.loop.name)

Why not use sets here, like

api_test_names = {json[0]['name'], json[1]['name']}
test_names = {self.android_loop.name, self.loop.name}
self.assertEqual(api_test_names, test_names)

Revision history for this message
Milo Casagrande (milo) wrote :

Hello James!

Nice work here! :-)

On Fri, Feb 1, 2013 at 12:57 PM, James Tunnicliffe
<email address hidden> wrote:
>
> The current API is very limited. The intent of this MP is to get some feedback on if this is a sensible way to implement the API. Future merges will fill it out.

So, some feedback.
Keep in mind that I never created RESTful API with Python nor Django
(only worked with Java on this front).

Overall, it looks a good Django-nic way of creating RESTful API
without decorators. I hove no idea of the other frameworks around, but
docs for this are well written and seems also up-to-date (a big plus I
would say).

> If you are running Ubuntu 12.04 you can run the application, just not unit test the API because it relies on LiveServerTestCase, which was introduced with Django 1.4. To work around this, instructions are provided for setting up an isolated Python environment using virtualenvwrapper are included in the README.

Regarding this, since we will deploy or install this on a 12.04
server, how are we going to handle/maintain it?
Using virtualenv? Backport? Default backport channel for 12.04 does
not have any newest version of Django available... That is something
we need to keep in mind, because I think we will be using LTS versions
(and next one will be out in 1 year time).

Anyway, using virtualenvwrapper everything worked perfectly, and tests run fine.

> === added file 'dashboard/frontend/api/urls.py'
> --- dashboard/frontend/api/urls.py 1970-01-01 00:00:00 +0000
> +++ dashboard/frontend/api/urls.py 2013-02-01 11:56:24 +0000
> @@ -0,0 +1,13 @@
> +from django.conf.urls.defaults import patterns, include
> +from dashboard.frontend.api.api import *
> +from tastypie.api import Api
> +
> +v1_api = Api(api_name='v1')
> +
> +# Register new resources here (probably defined in api.py)
> +v1_api.register(LoginTestResource())
> +v1_api.register(LoopsResource())
> +
> +urlpatterns = patterns('',
> + (r'^api/', include(v1_api.urls)),
> +)

I have to say I'm more in favor of using a normal numbering scheme
(like "1.0") for API versions (at least for stable ones, maybe a "dev"
one for bleeding-edge stuff).
I guess that if we need to change API version and bump the number, it
would be as easy as this piece of code, as long as Djano does not
complain for the double entry with the same search-pattern (r'^api/').
Did you try if it works? Can't remember out of my mind now...

Ciao!

--
Milo Casagrande | Infrastructure Team
Linaro.org <www.linaro.org> │ Open source software for ARM SoCs

Revision history for this message
James Tunnicliffe (dooferlad) wrote :

On 4 February 2013 16:09, Stevan Radaković <email address hidden> wrote:
> Hey James,
>
> Nice work rly.. I've managed to run everything pretty much smooth, tests worked, and the code looks good as well, disregarding the problem with django version for unit testing, this is really unfortunate dependency :/
>
> First thing that kinda bothers me is that we require 'v1/' in API links.
> I read the tastypie docs a bit but couldn't get quick answer if this is
> easy to remove or not.. If there's any special reason to keep it tho,
> I'd like to hear it.

I haven't looked into that much, but versioning is probably a good
idea. so incompatible changes can be rolled out without breaking old
clients (well, we will phase out old clients eventually). I don't care
what the version string is though. I like Milo's comment about just
having a number or "dev". My vote is for major.minor version as stable
API versions and dev, which will always point to the latest API.

> Second thing is just a minor code block in tests that stung me in the eye, but nothing special:
>
> 280 + # One loop is of type AndroidLoop, the other ModelBase. Find which is
> 281 + # which.
> 282 + if json[0]['type'] == 'AndroidLoop':
> 283 + android_loop_index = 0
> 284 + base_loop_index = 1
> 285 + else:
> 286 + android_loop_index = 1
> 287 + base_loop_index = 0
> 288 +
> 289 + # Now test the contents of the loop data
> 290 + self.assertEqual(json[android_loop_index]['name'],
> 291 + self.android_loop.name)
> 292 + self.assertEqual(json[base_loop_index]['name'],
> 293 + self.loop.name)
>
> Why not use sets here, like
>
> api_test_names = {json[0]['name'], json[1]['name']}
> test_names = {self.android_loop.name, self.loop.name}
> self.assertEqual(api_test_names, test_names)

I like your version. I clearly ran out of Python at that point :-)

Thanks,

--
James Tunnicliffe

Revision history for this message
James Tunnicliffe (dooferlad) wrote :
Download full text (3.2 KiB)

On 4 February 2013 16:31, Milo Casagrande <email address hidden> wrote:
> Hello James!
>
> Nice work here! :-)
>
> On Fri, Feb 1, 2013 at 12:57 PM, James Tunnicliffe
> <email address hidden> wrote:
>>
>> The current API is very limited. The intent of this MP is to get some feedback on if this is a sensible way to implement the API. Future merges will fill it out.
>
> So, some feedback.
> Keep in mind that I never created RESTful API with Python nor Django
> (only worked with Java on this front).
>
> Overall, it looks a good Django-nic way of creating RESTful API
> without decorators. I hove no idea of the other frameworks around, but
> docs for this are well written and seems also up-to-date (a big plus I
> would say).
>
>> If you are running Ubuntu 12.04 you can run the application, just not unit test the API because it relies on LiveServerTestCase, which was introduced with Django 1.4. To work around this, instructions are provided for setting up an isolated Python environment using virtualenvwrapper are included in the README.
>
> Regarding this, since we will deploy or install this on a 12.04
> server, how are we going to handle/maintain it?
> Using virtualenv? Backport? Default backport channel for 12.04 does
> not have any newest version of Django available... That is something
> we need to keep in mind, because I think we will be using LTS versions
> (and next one will be out in 1 year time).

It is only the testing that requires Django 1.4, not running the API
library. Using LiveServerTestCase instead of TestCase starts up a
server per-test that the test can interact with. This was introducted
with 1.4. It shouldn't change the functionality of the API at all. Of
course, there is a risk that a bug will be present running under 1.3
that we don't see with 1.4, but so far I haven't encountered any.

> Anyway, using virtualenvwrapper everything worked perfectly, and tests run fine.
>
>> === added file 'dashboard/frontend/api/urls.py'
>> --- dashboard/frontend/api/urls.py 1970-01-01 00:00:00 +0000
>> +++ dashboard/frontend/api/urls.py 2013-02-01 11:56:24 +0000
>> @@ -0,0 +1,13 @@
>> +from django.conf.urls.defaults import patterns, include
>> +from dashboard.frontend.api.api import *
>> +from tastypie.api import Api
>> +
>> +v1_api = Api(api_name='v1')
>> +
>> +# Register new resources here (probably defined in api.py)
>> +v1_api.register(LoginTestResource())
>> +v1_api.register(LoopsResource())
>> +
>> +urlpatterns = patterns('',
>> + (r'^api/', include(v1_api.urls)),
>> +)
>
> I have to say I'm more in favor of using a normal numbering scheme
> (like "1.0") for API versions (at least for stable ones, maybe a "dev"
> one for bleeding-edge stuff).
> I guess that if we need to change API version and bump the number, it
> would be as easy as this piece of code, as long as Djano does not
> complain for the double entry with the same search-pattern (r'^api/').
> Did you try if it works? Can't remember out of my mind now...

I haven't tried it. I am sure we can find something that works and we
all like. For now I will change the api_name to "dev" and when we
release we can create a duplicate interface under 1.0, v1.0 or
whatev...

Read more...

78. By James Tunnicliffe

Changes as suggested from merge proposal:
 * Name API version "dev" for the moment
 * Tidy up tests

Revision history for this message
Stevan Radaković (stevanr) wrote :

Thanks for the changes!

Approve +1

review: Approve
Revision history for this message
Milo Casagrande (milo) wrote :

> I haven't looked into that much, but versioning is probably a good
> idea. so incompatible changes can be rolled out without breaking old
> clients (well, we will phase out old clients eventually). I don't care
> what the version string is though. I like Milo's comment about just
> having a number or "dev". My vote is for major.minor version as stable
> API versions and dev, which will always point to the latest API.

I'm in favor of introducing some sort of versioning too: major.minor numbering and a "dev" one looks OK.
Anyway, MP looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'README'
2--- README 2012-09-21 02:10:21 +0000
3+++ README 2013-02-04 17:57:22 +0000
4@@ -16,6 +16,31 @@
5 python-dev
6 build-essential
7 openjdk-6-jre-headless
8+ python-tastypie
9+
10+To unit test the API that tastypie provides you need Django version of at least
11+1.4. If you have Django 1.3 the API will still work, but not be unit tested.
12+
13+If you are running Ubuntu 12.04 or earlier, you can install Django 1.4 in
14+an isolated Python environment using http://www.virtualenv.org/en/latest/.
15+These instructions are for the slightly friendlier interface offered by
16+http://virtualenvwrapper.readthedocs.org/en/latest/.
17+
18+ First install virtualenv and virtualenv wrapper:
19+ > pip install virtualenvwrapper
20+
21+ Create a virtual environment to work in:
22+ > mkvirtualenv ciloops
23+
24+ Enable the virtual environment:
25+ > workon ciloops
26+
27+ Install the required Python packages:
28+ > pip install -r requirements.txt
29+
30+ If any new Python packages are required, they can be installed using pip then
31+ a new requirements.txt generated:
32+ > pip freeze > requirements.txt
33
34 Running the application
35 -----------------------
36
37=== added directory 'dashboard/frontend/api'
38=== added file 'dashboard/frontend/api/__init__.py'
39=== added file 'dashboard/frontend/api/api.py'
40--- dashboard/frontend/api/api.py 1970-01-01 00:00:00 +0000
41+++ dashboard/frontend/api/api.py 2013-02-04 17:57:22 +0000
42@@ -0,0 +1,56 @@
43+# Copyright (C) 2013 Linaro
44+#
45+# This file is part of linaro-ci-dashboard.
46+#
47+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
48+# it under the terms of the GNU Affero General Public License as published by
49+# the Free Software Foundation, either version 3 of the License, or
50+# (at your option) any later version.
51+#
52+# linaro-ci-dashboard is distributed in the hope that it will be useful,
53+# but WITHOUT ANY WARRANTY; without even the implied warranty of
54+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55+# GNU Affero General Public License for more details.
56+#
57+# You should have received a copy of the GNU Affero General Public License
58+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
59+
60+from tastypie.resources import ModelResource
61+from tastypie.authorization import DjangoAuthorization
62+from tastypie.authentication import ApiKeyAuthentication
63+from dashboard.frontend.models.loop import Loop
64+
65+"""
66+Add API endpoint logic here. The documentation to do this can be found here:
67+http://django-tastypie.readthedocs.org/en/latest/tutorial.html
68+
69+After creating a class here, make sure you register it in urls.py
70+
71+TODO: Handle loop creation and builds.
72+"""
73+
74+
75+class LoginTestResource(ModelResource):
76+ class Meta:
77+ """This exists just so a client can test its login data.
78+
79+ It must use the same authentication mechanism as other protected
80+ classes so it will reject connections that aren't authenticated.
81+
82+ The return data doesn't matter. Ideally, it should put minimal load
83+ on the server to generate the return data.
84+ """
85+
86+ queryset = Loop.objects.none()
87+ resource_name = 'login_test'
88+ authorization = DjangoAuthorization()
89+ authentication = ApiKeyAuthentication()
90+
91+
92+class LoopsResource(ModelResource):
93+ class Meta:
94+ """Returns a list of all loops."""
95+ queryset = Loop.objects.all()
96+ resource_name = 'loops'
97+ authorization = DjangoAuthorization()
98+ authentication = ApiKeyAuthentication()
99
100=== added file 'dashboard/frontend/api/urls.py'
101--- dashboard/frontend/api/urls.py 1970-01-01 00:00:00 +0000
102+++ dashboard/frontend/api/urls.py 2013-02-04 17:57:22 +0000
103@@ -0,0 +1,13 @@
104+from django.conf.urls.defaults import patterns, include
105+from dashboard.frontend.api.api import *
106+from tastypie.api import Api
107+
108+v1_api = Api(api_name='dev')
109+
110+# Register new resources here (probably defined in api.py)
111+v1_api.register(LoginTestResource())
112+v1_api.register(LoopsResource())
113+
114+urlpatterns = patterns('',
115+ (r'^api/', include(v1_api.urls)),
116+)
117
118=== added file 'dashboard/frontend/templates/api_key.html'
119--- dashboard/frontend/templates/api_key.html 1970-01-01 00:00:00 +0000
120+++ dashboard/frontend/templates/api_key.html 2013-02-04 17:57:22 +0000
121@@ -0,0 +1,6 @@
122+{% if request.user.username %}
123+ <div>Your Linaro CI CLI login information is:</div>
124+ <div class="data">User: {{ request.user }}</div>
125+ <div class="data">API Key: {{ api_key }}</div>
126+{% else %}
127+{% endif %}
128
129=== modified file 'dashboard/frontend/tests/__init__.py'
130--- dashboard/frontend/tests/__init__.py 2012-09-14 08:15:50 +0000
131+++ dashboard/frontend/tests/__init__.py 2013-02-04 17:57:22 +0000
132@@ -1,9 +1,29 @@
133+# Copyright (C) 2013 Linaro
134+#
135+# This file is part of linaro-ci-dashboard.
136+#
137+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
138+# it under the terms of the GNU Affero General Public License as published by
139+# the Free Software Foundation, either version 3 of the License, or
140+# (at your option) any later version.
141+#
142+# linaro-ci-dashboard is distributed in the hope that it will be useful,
143+# but WITHOUT ANY WARRANTY; without even the implied warranty of
144+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
145+# GNU Affero General Public License for more details.
146+#
147+# You should have received a copy of the GNU Affero General Public License
148+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
149+
150 from dashboard.frontend.tests.test_views import *
151 from dashboard.frontend.tests.test_models import *
152 from dashboard.frontend.tests.test_clientresponse import *
153 from dashboard.frontend.tests.test_custom_commands import *
154 from dashboard.frontend.tests.test_xml_to_dict import *
155
156+import django
157+if not(django.VERSION[0] == 1 and django.VERSION[1] <= 3):
158+ from dashboard.frontend.tests.test_api import *
159
160 #starts the test suite
161 __test__ = {
162@@ -15,3 +35,6 @@
163 'XmlToDictTest': XmlToDictTest,
164 'DictToXmlTest': DictToXmlTest,
165 }
166+
167+if not(django.VERSION[0] == 1 and django.VERSION[1] <= 3):
168+ __test__['ApiTests'] = ApiTests
169
170=== added file 'dashboard/frontend/tests/test_api.py'
171--- dashboard/frontend/tests/test_api.py 1970-01-01 00:00:00 +0000
172+++ dashboard/frontend/tests/test_api.py 2013-02-04 17:57:22 +0000
173@@ -0,0 +1,95 @@
174+# Copyright (C) 2013 Linaro
175+#
176+# This file is part of linaro-ci-dashboard.
177+#
178+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
179+# it under the terms of the GNU Affero General Public License as published by
180+# the Free Software Foundation, either version 3 of the License, or
181+# (at your option) any later version.
182+#
183+# linaro-ci-dashboard is distributed in the hope that it will be useful,
184+# but WITHOUT ANY WARRANTY; without even the implied warranty of
185+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
186+# GNU Affero General Public License for more details.
187+#
188+# You should have received a copy of the GNU Affero General Public License
189+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
190+
191+from django.contrib.auth.models import User
192+from django.test import LiveServerTestCase
193+from tastypie.models import ApiKey
194+from dashboard.frontend.models.loop import Loop
195+from dashboard.frontend.android_build.models.android_loop import AndroidLoop
196+import requests
197+from urlparse import urljoin
198+
199+
200+class ApiTests(LiveServerTestCase):
201+ # Use ``fixtures`` & ``urls`` as normal. See Django's ``TestCase``
202+ # documentation for the gory details.
203+ fixtures = ['test_entries.json']
204+
205+ def setUp(self):
206+ super(ApiTests, self).setUp()
207+
208+ # Create a user.
209+ self.username = 'daniel'
210+ self.password = 'pass'
211+ self.user = User.objects.create_user(
212+ self.username, 'daniel@example.com', self.password)
213+
214+ self.api_key = "0"
215+
216+ # Add a couple of jobs to test against.
217+ self.android_loop = AndroidLoop()
218+ self.android_loop.name = "testjob_android"
219+ self.android_loop.build_type = "build-android"
220+ self.android_loop.save()
221+
222+ self.loop = Loop()
223+ self.loop.name = 'a-loop'
224+ self.loop.type = Loop.__class__.__name__
225+ self.loop.save()
226+
227+ def get(self, url):
228+ payload = {"username": self.username,
229+ "api_key": self.api_key,
230+ "format": "json"}
231+ url = urljoin("http://localhost:8081", "/api/dev/" + url)
232+ return requests.get(url, params=payload)
233+
234+ def login(self):
235+ self.api_key = ApiKey.objects.create(user=self.user).key
236+ #self.create_apikey(self.username, self.api_key)
237+
238+ def test_login_test_unauthorzied(self):
239+ r = self.get("login_test")
240+ self.assertEqual(r.status_code, requests.codes.unauthorized)
241+
242+ def test_loops_unauthorzied(self):
243+ r = self.get("loops")
244+ self.assertEqual(r.status_code, requests.codes.unauthorized)
245+
246+ def test_login_test_authorized(self):
247+ self.login()
248+ r = self.get("login_test")
249+ self.assertEqual(r.status_code, requests.codes.ok)
250+
251+ def test_loops_authorized(self):
252+ self.login()
253+ r = self.get("loops")
254+ self.assertEqual(r.status_code, requests.codes.ok)
255+
256+ def test_loops_list(self):
257+ self.login()
258+ r = self.get("loops")
259+ self.assertEqual(r.status_code, requests.codes.ok)
260+ json = r.json()['objects']
261+
262+ # 2 defined loops. Both should be returned.
263+ self.assertEqual(len(json), 2)
264+
265+ # Make sure both loops contain the expected data.
266+ api_test_names = {json[0]['name'], json[1]['name']}
267+ test_names = {self.android_loop.name, self.loop.name}
268+ self.assertEqual(api_test_names, test_names)
269
270=== modified file 'dashboard/frontend/urls.py'
271--- dashboard/frontend/urls.py 2012-09-24 19:09:05 +0000
272+++ dashboard/frontend/urls.py 2013-02-04 17:57:22 +0000
273@@ -24,6 +24,7 @@
274 from frontend.views.loop_build_view import LoopBuildView
275 from frontend.views.loop_get_chainable_view import LoopGetChainableView
276 from frontend.views.loop_build_detail_view import LoopBuildDetailView
277+from frontend.views.api_key import ApiKeyView
278
279
280 urlpatterns = patterns('',
281@@ -40,4 +41,5 @@
282 LavaSelectView.as_view(), name='LavaSelectView'),
283 url(r'^lava/ajax/get-test-names/$',
284 LavaSelectTestNames.as_view(), name='LavaSelectTestsNames'),
285+ url(r'^api_key/$', ApiKeyView.as_view(), name='ApiKeyView'),
286 )
287
288=== added file 'dashboard/frontend/views/api_key.py'
289--- dashboard/frontend/views/api_key.py 1970-01-01 00:00:00 +0000
290+++ dashboard/frontend/views/api_key.py 2013-02-04 17:57:22 +0000
291@@ -0,0 +1,47 @@
292+# Copyright (C) 2013 Linaro
293+#
294+# This file is part of linaro-ci-dashboard.
295+#
296+# linaro-ci-dashboard is free software: you can redistribute it and/or modify
297+# it under the terms of the GNU Affero General Public License as published by
298+# the Free Software Foundation, either version 3 of the License, or
299+# (at your option) any later version.
300+#
301+# linaro-ci-dashboard is distributed in the hope that it will be useful,
302+# but WITHOUT ANY WARRANTY; without even the implied warranty of
303+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304+# GNU Affero General Public License for more details.
305+#
306+# You should have received a copy of the GNU Affero General Public License
307+# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
308+
309+from django.views.generic.base import TemplateView
310+from tastypie.models import ApiKey
311+from django.contrib.auth.decorators import login_required
312+from django.utils.decorators import method_decorator
313+
314+
315+class ApiKeyView(TemplateView):
316+ """Provide the user with their API key, generating one if required."""
317+ template_name = "api_key.html"
318+
319+ @method_decorator(login_required)
320+ def dispatch(self, *args, **kwargs):
321+ return super(ApiKeyView, self).dispatch(*args, **kwargs)
322+
323+ def get_context_data(self, **kwargs):
324+ context = super(ApiKeyView, self).get_context_data(**kwargs)
325+ context['request'] = self.request
326+
327+ # TODO: Reset API key on request. This can be done by:
328+ # api_key.key = None
329+ # api_key.save() -- will generate a new key (won't accept None)
330+
331+ try:
332+ api_key = ApiKey.objects.get(user=self.request.user)
333+ except ApiKey.DoesNotExist:
334+ api_key = ApiKey.objects.create(user=self.request.user)
335+
336+ context['api_key'] = api_key.key
337+
338+ return context
339
340=== modified file 'dashboard/settings.py'
341--- dashboard/settings.py 2012-10-04 15:39:41 +0000
342+++ dashboard/settings.py 2013-02-04 17:57:22 +0000
343@@ -18,6 +18,7 @@
344
345 import os
346 import sys
347+import django
348
349 DEBUG = True
350 TEMPLATE_DEBUG = DEBUG
351@@ -127,11 +128,16 @@
352 'django.middleware.common.CommonMiddleware',
353 'django.contrib.sessions.middleware.SessionMiddleware',
354 'django.middleware.csrf.CsrfViewMiddleware',
355- 'django.middleware.csrf.CsrfResponseMiddleware',
356 'django.contrib.auth.middleware.AuthenticationMiddleware',
357 'django.contrib.messages.middleware.MessageMiddleware',
358 )
359
360+# The CSRF middleware moved in Django 1.4...
361+if django.VERSION[0] == 1 and django.VERSION[1] <= 3:
362+ MIDDLEWARE_CLASSES += ('django.middleware.csrf.CsrfResponseMiddleware',)
363+else:
364+ MIDDLEWARE_CLASSES += ('django.middleware.csrf.CsrfViewMiddleware',)
365+
366 ROOT_URLCONF = 'dashboard.urls'
367
368 INSTALLED_APPS = (
369@@ -151,9 +157,9 @@
370 'frontend.integration_loop',
371 'frontend.android_textfield_loop',
372 'frontend.hwpack_loop',
373+ 'frontend.api',
374+ 'tastypie',
375 'south',
376- # Uncomment the next line to enable the admin:
377- # 'django.contrib.admin',
378 # Uncomment the next line to enable admin documentation:
379 # 'django.contrib.admindocs',
380 )
381
382=== modified file 'dashboard/urls.py'
383--- dashboard/urls.py 2012-09-24 19:09:05 +0000
384+++ dashboard/urls.py 2013-02-04 17:57:22 +0000
385@@ -39,4 +39,5 @@
386 url(r'^', include('dashboard.frontend.integration_loop.urls')),
387 url(r'^', include('dashboard.frontend.android_textfield_loop.urls')),
388 url(r'^', include('dashboard.frontend.hwpack_loop.urls')),
389+ url(r'^', include('dashboard.frontend.api.urls')),
390 )
391
392=== added file 'requirements.txt'
393--- requirements.txt 1970-01-01 00:00:00 +0000
394+++ requirements.txt 2013-02-04 17:57:22 +0000
395@@ -0,0 +1,15 @@
396+Django==1.4.3
397+South==0.7.6
398+argparse==1.2.1
399+distribute==0.6.24
400+django-openid-auth==0.4
401+django-openid-consumer==0.1.1
402+django-tastypie==0.9.11
403+jenkins==1.0.2
404+mimeparse==0.1.3
405+mock==1.0.1
406+python-dateutil==1.5
407+python-jenkins==0.2
408+python-openid==2.2.5
409+requests==1.1.0
410+wsgiref==0.1.2

Subscribers

People subscribed via source and target branches