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
=== modified file 'README'
--- README 2012-09-21 02:10:21 +0000
+++ README 2013-02-04 17:57:22 +0000
@@ -16,6 +16,31 @@
16 python-dev16 python-dev
17 build-essential17 build-essential
18 openjdk-6-jre-headless18 openjdk-6-jre-headless
19 python-tastypie
20
21To unit test the API that tastypie provides you need Django version of at least
221.4. If you have Django 1.3 the API will still work, but not be unit tested.
23
24If you are running Ubuntu 12.04 or earlier, you can install Django 1.4 in
25an isolated Python environment using http://www.virtualenv.org/en/latest/.
26These instructions are for the slightly friendlier interface offered by
27http://virtualenvwrapper.readthedocs.org/en/latest/.
28
29 First install virtualenv and virtualenv wrapper:
30 > pip install virtualenvwrapper
31
32 Create a virtual environment to work in:
33 > mkvirtualenv ciloops
34
35 Enable the virtual environment:
36 > workon ciloops
37
38 Install the required Python packages:
39 > pip install -r requirements.txt
40
41 If any new Python packages are required, they can be installed using pip then
42 a new requirements.txt generated:
43 > pip freeze > requirements.txt
1944
20Running the application45Running the application
21-----------------------46-----------------------
2247
=== added directory 'dashboard/frontend/api'
=== added file 'dashboard/frontend/api/__init__.py'
=== added file 'dashboard/frontend/api/api.py'
--- dashboard/frontend/api/api.py 1970-01-01 00:00:00 +0000
+++ dashboard/frontend/api/api.py 2013-02-04 17:57:22 +0000
@@ -0,0 +1,56 @@
1# Copyright (C) 2013 Linaro
2#
3# This file is part of linaro-ci-dashboard.
4#
5# linaro-ci-dashboard is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Affero General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# linaro-ci-dashboard is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
17
18from tastypie.resources import ModelResource
19from tastypie.authorization import DjangoAuthorization
20from tastypie.authentication import ApiKeyAuthentication
21from dashboard.frontend.models.loop import Loop
22
23"""
24Add API endpoint logic here. The documentation to do this can be found here:
25http://django-tastypie.readthedocs.org/en/latest/tutorial.html
26
27After creating a class here, make sure you register it in urls.py
28
29TODO: Handle loop creation and builds.
30"""
31
32
33class LoginTestResource(ModelResource):
34 class Meta:
35 """This exists just so a client can test its login data.
36
37 It must use the same authentication mechanism as other protected
38 classes so it will reject connections that aren't authenticated.
39
40 The return data doesn't matter. Ideally, it should put minimal load
41 on the server to generate the return data.
42 """
43
44 queryset = Loop.objects.none()
45 resource_name = 'login_test'
46 authorization = DjangoAuthorization()
47 authentication = ApiKeyAuthentication()
48
49
50class LoopsResource(ModelResource):
51 class Meta:
52 """Returns a list of all loops."""
53 queryset = Loop.objects.all()
54 resource_name = 'loops'
55 authorization = DjangoAuthorization()
56 authentication = ApiKeyAuthentication()
057
=== 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-04 17:57:22 +0000
@@ -0,0 +1,13 @@
1from django.conf.urls.defaults import patterns, include
2from dashboard.frontend.api.api import *
3from tastypie.api import Api
4
5v1_api = Api(api_name='dev')
6
7# Register new resources here (probably defined in api.py)
8v1_api.register(LoginTestResource())
9v1_api.register(LoopsResource())
10
11urlpatterns = patterns('',
12 (r'^api/', include(v1_api.urls)),
13)
014
=== added file 'dashboard/frontend/templates/api_key.html'
--- dashboard/frontend/templates/api_key.html 1970-01-01 00:00:00 +0000
+++ dashboard/frontend/templates/api_key.html 2013-02-04 17:57:22 +0000
@@ -0,0 +1,6 @@
1{% if request.user.username %}
2 <div>Your Linaro CI CLI login information is:</div>
3 <div class="data">User: {{ request.user }}</div>
4 <div class="data">API Key: {{ api_key }}</div>
5{% else %}
6{% endif %}
07
=== modified file 'dashboard/frontend/tests/__init__.py'
--- dashboard/frontend/tests/__init__.py 2012-09-14 08:15:50 +0000
+++ dashboard/frontend/tests/__init__.py 2013-02-04 17:57:22 +0000
@@ -1,9 +1,29 @@
1# Copyright (C) 2013 Linaro
2#
3# This file is part of linaro-ci-dashboard.
4#
5# linaro-ci-dashboard is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Affero General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# linaro-ci-dashboard is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
17
1from dashboard.frontend.tests.test_views import *18from dashboard.frontend.tests.test_views import *
2from dashboard.frontend.tests.test_models import *19from dashboard.frontend.tests.test_models import *
3from dashboard.frontend.tests.test_clientresponse import *20from dashboard.frontend.tests.test_clientresponse import *
4from dashboard.frontend.tests.test_custom_commands import *21from dashboard.frontend.tests.test_custom_commands import *
5from dashboard.frontend.tests.test_xml_to_dict import *22from dashboard.frontend.tests.test_xml_to_dict import *
623
24import django
25if not(django.VERSION[0] == 1 and django.VERSION[1] <= 3):
26 from dashboard.frontend.tests.test_api import *
727
8#starts the test suite28#starts the test suite
9__test__ = {29__test__ = {
@@ -15,3 +35,6 @@
15 'XmlToDictTest': XmlToDictTest,35 'XmlToDictTest': XmlToDictTest,
16 'DictToXmlTest': DictToXmlTest,36 'DictToXmlTest': DictToXmlTest,
17 }37 }
38
39if not(django.VERSION[0] == 1 and django.VERSION[1] <= 3):
40 __test__['ApiTests'] = ApiTests
1841
=== added file 'dashboard/frontend/tests/test_api.py'
--- dashboard/frontend/tests/test_api.py 1970-01-01 00:00:00 +0000
+++ dashboard/frontend/tests/test_api.py 2013-02-04 17:57:22 +0000
@@ -0,0 +1,95 @@
1# Copyright (C) 2013 Linaro
2#
3# This file is part of linaro-ci-dashboard.
4#
5# linaro-ci-dashboard is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Affero General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# linaro-ci-dashboard is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
17
18from django.contrib.auth.models import User
19from django.test import LiveServerTestCase
20from tastypie.models import ApiKey
21from dashboard.frontend.models.loop import Loop
22from dashboard.frontend.android_build.models.android_loop import AndroidLoop
23import requests
24from urlparse import urljoin
25
26
27class ApiTests(LiveServerTestCase):
28 # Use ``fixtures`` & ``urls`` as normal. See Django's ``TestCase``
29 # documentation for the gory details.
30 fixtures = ['test_entries.json']
31
32 def setUp(self):
33 super(ApiTests, self).setUp()
34
35 # Create a user.
36 self.username = 'daniel'
37 self.password = 'pass'
38 self.user = User.objects.create_user(
39 self.username, 'daniel@example.com', self.password)
40
41 self.api_key = "0"
42
43 # Add a couple of jobs to test against.
44 self.android_loop = AndroidLoop()
45 self.android_loop.name = "testjob_android"
46 self.android_loop.build_type = "build-android"
47 self.android_loop.save()
48
49 self.loop = Loop()
50 self.loop.name = 'a-loop'
51 self.loop.type = Loop.__class__.__name__
52 self.loop.save()
53
54 def get(self, url):
55 payload = {"username": self.username,
56 "api_key": self.api_key,
57 "format": "json"}
58 url = urljoin("http://localhost:8081", "/api/dev/" + url)
59 return requests.get(url, params=payload)
60
61 def login(self):
62 self.api_key = ApiKey.objects.create(user=self.user).key
63 #self.create_apikey(self.username, self.api_key)
64
65 def test_login_test_unauthorzied(self):
66 r = self.get("login_test")
67 self.assertEqual(r.status_code, requests.codes.unauthorized)
68
69 def test_loops_unauthorzied(self):
70 r = self.get("loops")
71 self.assertEqual(r.status_code, requests.codes.unauthorized)
72
73 def test_login_test_authorized(self):
74 self.login()
75 r = self.get("login_test")
76 self.assertEqual(r.status_code, requests.codes.ok)
77
78 def test_loops_authorized(self):
79 self.login()
80 r = self.get("loops")
81 self.assertEqual(r.status_code, requests.codes.ok)
82
83 def test_loops_list(self):
84 self.login()
85 r = self.get("loops")
86 self.assertEqual(r.status_code, requests.codes.ok)
87 json = r.json()['objects']
88
89 # 2 defined loops. Both should be returned.
90 self.assertEqual(len(json), 2)
91
92 # Make sure both loops contain the expected data.
93 api_test_names = {json[0]['name'], json[1]['name']}
94 test_names = {self.android_loop.name, self.loop.name}
95 self.assertEqual(api_test_names, test_names)
096
=== modified file 'dashboard/frontend/urls.py'
--- dashboard/frontend/urls.py 2012-09-24 19:09:05 +0000
+++ dashboard/frontend/urls.py 2013-02-04 17:57:22 +0000
@@ -24,6 +24,7 @@
24from frontend.views.loop_build_view import LoopBuildView24from frontend.views.loop_build_view import LoopBuildView
25from frontend.views.loop_get_chainable_view import LoopGetChainableView25from frontend.views.loop_get_chainable_view import LoopGetChainableView
26from frontend.views.loop_build_detail_view import LoopBuildDetailView26from frontend.views.loop_build_detail_view import LoopBuildDetailView
27from frontend.views.api_key import ApiKeyView
2728
2829
29urlpatterns = patterns('',30urlpatterns = patterns('',
@@ -40,4 +41,5 @@
40 LavaSelectView.as_view(), name='LavaSelectView'),41 LavaSelectView.as_view(), name='LavaSelectView'),
41 url(r'^lava/ajax/get-test-names/$',42 url(r'^lava/ajax/get-test-names/$',
42 LavaSelectTestNames.as_view(), name='LavaSelectTestsNames'),43 LavaSelectTestNames.as_view(), name='LavaSelectTestsNames'),
44 url(r'^api_key/$', ApiKeyView.as_view(), name='ApiKeyView'),
43)45)
4446
=== added file 'dashboard/frontend/views/api_key.py'
--- dashboard/frontend/views/api_key.py 1970-01-01 00:00:00 +0000
+++ dashboard/frontend/views/api_key.py 2013-02-04 17:57:22 +0000
@@ -0,0 +1,47 @@
1# Copyright (C) 2013 Linaro
2#
3# This file is part of linaro-ci-dashboard.
4#
5# linaro-ci-dashboard is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Affero General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# linaro-ci-dashboard is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU Affero General Public License for more details.
14#
15# You should have received a copy of the GNU Affero General Public License
16# along with linaro-ci-dashboard. If not, see <http://www.gnu.org/licenses/>.
17
18from django.views.generic.base import TemplateView
19from tastypie.models import ApiKey
20from django.contrib.auth.decorators import login_required
21from django.utils.decorators import method_decorator
22
23
24class ApiKeyView(TemplateView):
25 """Provide the user with their API key, generating one if required."""
26 template_name = "api_key.html"
27
28 @method_decorator(login_required)
29 def dispatch(self, *args, **kwargs):
30 return super(ApiKeyView, self).dispatch(*args, **kwargs)
31
32 def get_context_data(self, **kwargs):
33 context = super(ApiKeyView, self).get_context_data(**kwargs)
34 context['request'] = self.request
35
36 # TODO: Reset API key on request. This can be done by:
37 # api_key.key = None
38 # api_key.save() -- will generate a new key (won't accept None)
39
40 try:
41 api_key = ApiKey.objects.get(user=self.request.user)
42 except ApiKey.DoesNotExist:
43 api_key = ApiKey.objects.create(user=self.request.user)
44
45 context['api_key'] = api_key.key
46
47 return context
048
=== modified file 'dashboard/settings.py'
--- dashboard/settings.py 2012-10-04 15:39:41 +0000
+++ dashboard/settings.py 2013-02-04 17:57:22 +0000
@@ -18,6 +18,7 @@
1818
19import os19import os
20import sys20import sys
21import django
2122
22DEBUG = True23DEBUG = True
23TEMPLATE_DEBUG = DEBUG24TEMPLATE_DEBUG = DEBUG
@@ -127,11 +128,16 @@
127 'django.middleware.common.CommonMiddleware',128 'django.middleware.common.CommonMiddleware',
128 'django.contrib.sessions.middleware.SessionMiddleware',129 'django.contrib.sessions.middleware.SessionMiddleware',
129 'django.middleware.csrf.CsrfViewMiddleware',130 'django.middleware.csrf.CsrfViewMiddleware',
130 'django.middleware.csrf.CsrfResponseMiddleware',
131 'django.contrib.auth.middleware.AuthenticationMiddleware',131 'django.contrib.auth.middleware.AuthenticationMiddleware',
132 'django.contrib.messages.middleware.MessageMiddleware',132 'django.contrib.messages.middleware.MessageMiddleware',
133)133)
134134
135# The CSRF middleware moved in Django 1.4...
136if django.VERSION[0] == 1 and django.VERSION[1] <= 3:
137 MIDDLEWARE_CLASSES += ('django.middleware.csrf.CsrfResponseMiddleware',)
138else:
139 MIDDLEWARE_CLASSES += ('django.middleware.csrf.CsrfViewMiddleware',)
140
135ROOT_URLCONF = 'dashboard.urls'141ROOT_URLCONF = 'dashboard.urls'
136142
137INSTALLED_APPS = (143INSTALLED_APPS = (
@@ -151,9 +157,9 @@
151 'frontend.integration_loop',157 'frontend.integration_loop',
152 'frontend.android_textfield_loop',158 'frontend.android_textfield_loop',
153 'frontend.hwpack_loop',159 'frontend.hwpack_loop',
160 'frontend.api',
161 'tastypie',
154 'south',162 'south',
155 # Uncomment the next line to enable the admin:
156 # 'django.contrib.admin',
157 # Uncomment the next line to enable admin documentation:163 # Uncomment the next line to enable admin documentation:
158 # 'django.contrib.admindocs',164 # 'django.contrib.admindocs',
159)165)
160166
=== modified file 'dashboard/urls.py'
--- dashboard/urls.py 2012-09-24 19:09:05 +0000
+++ dashboard/urls.py 2013-02-04 17:57:22 +0000
@@ -39,4 +39,5 @@
39 url(r'^', include('dashboard.frontend.integration_loop.urls')),39 url(r'^', include('dashboard.frontend.integration_loop.urls')),
40 url(r'^', include('dashboard.frontend.android_textfield_loop.urls')),40 url(r'^', include('dashboard.frontend.android_textfield_loop.urls')),
41 url(r'^', include('dashboard.frontend.hwpack_loop.urls')),41 url(r'^', include('dashboard.frontend.hwpack_loop.urls')),
42 url(r'^', include('dashboard.frontend.api.urls')),
42)43)
4344
=== added file 'requirements.txt'
--- requirements.txt 1970-01-01 00:00:00 +0000
+++ requirements.txt 2013-02-04 17:57:22 +0000
@@ -0,0 +1,15 @@
1Django==1.4.3
2South==0.7.6
3argparse==1.2.1
4distribute==0.6.24
5django-openid-auth==0.4
6django-openid-consumer==0.1.1
7django-tastypie==0.9.11
8jenkins==1.0.2
9mimeparse==0.1.3
10mock==1.0.1
11python-dateutil==1.5
12python-jenkins==0.2
13python-openid==2.2.5
14requests==1.1.0
15wsgiref==0.1.2

Subscribers

People subscribed via source and target branches