Skip to content

Commit 5b73c97

Browse files
committed
Merge pull request tobami#115 from a8/add_api
Add api - added ApiKeyAuthentication and DjangoAuthorization
2 parents d9477b2 + e413dab commit 5b73c97

6 files changed

Lines changed: 806 additions & 180 deletions

File tree

codespeed/api.py

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
from tastypie.resources import ModelResource, Resource
4444
from tastypie import fields
4545
from tastypie.authorization import Authorization, DjangoAuthorization
46-
from tastypie.authentication import ApiKeyAuthentication
46+
from tastypie.authentication import Authentication, ApiKeyAuthentication, MultiAuthentication
4747
from tastypie.models import create_api_key
4848
from tastypie.utils.dict import dict_strip_unicode_keys
4949
from codespeed.models import (Environment, Project, Result, Branch, Revision,
@@ -63,17 +63,18 @@ class Meta:
6363
allowed_methods = ['get']
6464
#excludes = ['email', 'password', 'is_superuser']
6565
# Add it here.
66-
#authorization = DjangoAuthorization()
67-
authorization = Authorization()
68-
#authentication = ApiKeyAuthentication()
66+
authorization = DjangoAuthorization()
67+
authentication = ApiKeyAuthentication()
6968

7069

7170
class ProjectResource(ModelResource):
7271
"""Resource for Project()"""
7372

7473
class Meta:
7574
queryset = Project.objects.all()
76-
authorization = Authorization()
75+
authorization = DjangoAuthorization()
76+
# Note, the order for MultiAuthentication matters!
77+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
7778

7879

7980
class BranchResource(ModelResource):
@@ -83,7 +84,8 @@ class BranchResource(ModelResource):
8384

8485
class Meta:
8586
queryset = Branch.objects.all()
86-
authorization = Authorization()
87+
authorization = DjangoAuthorization()
88+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
8789

8890

8991
class RevisionResource(ModelResource):
@@ -94,7 +96,8 @@ class RevisionResource(ModelResource):
9496

9597
class Meta:
9698
queryset = Revision.objects.all()
97-
authorization = Authorization()
99+
authorization = DjangoAuthorization()
100+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
98101

99102

100103
class ExecutableResource(ModelResource):
@@ -104,15 +107,17 @@ class ExecutableResource(ModelResource):
104107

105108
class Meta:
106109
queryset = Executable.objects.all()
107-
authorization = Authorization()
110+
authorization = DjangoAuthorization()
111+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
108112

109113

110114
class BenchmarkResource(ModelResource):
111115
"""Resource for Benchmark()"""
112116

113117
class Meta:
114118
queryset = Benchmark.objects.all()
115-
authorization = Authorization()
119+
authorization = DjangoAuthorization()
120+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
116121

117122

118123
class EnvironmentResource(ModelResource):
@@ -121,15 +126,22 @@ class EnvironmentResource(ModelResource):
121126
class Meta:
122127
queryset = Environment.objects.all()
123128
resource_name = 'environment'
124-
authorization = Authorization()
129+
authorization = DjangoAuthorization()
130+
authentication = ApiKeyAuthentication()
131+
#authentication = MultiAuthentication(Authentication(), ApiKeyAuthentication())
125132

126133

127134
class ResultResource(ModelResource):
128135
"""Resource for Result()"""
136+
revision = fields.ToOneField(RevisionResource, 'revision')
137+
executable = fields.ToOneField(ExecutableResource, 'executable')
138+
benchmark = fields.ToOneField(BenchmarkResource, 'benchmark')
139+
environment = fields.ToOneField(EnvironmentResource, 'environment')
129140

130141
class Meta:
131142
queryset = Result.objects.all()
132-
authorization = Authorization()
143+
authorization = DjangoAuthorization()
144+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
133145

134146

135147
class ReportResource(ModelResource):
@@ -142,7 +154,8 @@ class ReportResource(ModelResource):
142154
class Meta:
143155
queryset = Report.objects.all()
144156
allowed_methods = ['get']
145-
authorization = Authorization()
157+
authorization = DjangoAuthorization()
158+
authentication = MultiAuthentication(ApiKeyAuthentication(), Authentication())
146159

147160

148161
class ResultBundle(Bundle):
@@ -198,19 +211,18 @@ def _populate_obj_by_data(self):
198211
get everything except the result, 2nd try reverse lookup
199212
"""
200213
def populate(key):
201-
return {
202-
'project': lambda: Project.objects.get_or_create(
203-
name=self.data['project']),
204-
'executable': lambda: Executable.objects.get_or_create(
205-
name=self.data['executable'], project=self.obj.project
206-
),
207-
'benchmark': lambda: Benchmark.objects.get_or_create(
208-
name=self.data['benchmark']),
209-
'environment': lambda: (Environment.objects.get(
210-
name=self.data['environment']), False),
211-
'branch': lambda: Branch.objects.get_or_create(
212-
name=self.data['branch'], project=self.obj.project),
213-
}.get(key, (None, None))()
214+
return {'project': lambda: ProjectResource().get_via_uri(
215+
self.data['project']),
216+
'executable': lambda: ExecutableResource().get_via_uri(
217+
self.data['executable']),
218+
'benchmark': lambda: BenchmarkResource().get_via_uri(
219+
self.data['benchmark']),
220+
'environment': lambda: EnvironmentResource().get_via_uri(
221+
self.data['environment']),
222+
'branch': lambda: BranchResource().get_via_uri(
223+
self.data['branch']),
224+
'revision': lambda: RevisionResource().get_via_uri(
225+
self.data['commitid']),}.get(key, None)()
214226

215227
try:
216228
self.obj.value = float(self.data['result_value'])
@@ -222,10 +234,10 @@ def populate(key):
222234
raise ImmediateHttpResponse(
223235
response=HttpBadRequest(u"Value needs to be a number"))
224236
for key in [k for k in self.mandatory_keys \
225-
if k not in ('result_value', 'revision')]:
237+
if k not in ('result_value',)]:
226238
try:
227239
#populate
228-
(item, created) = populate(key)
240+
item = populate(key)
229241
setattr(self.obj, key, item)
230242
except Exception, error:
231243
logging.error("Data for field %s: %s not found. %s" % (
@@ -234,13 +246,6 @@ def populate(key):
234246
response=HttpBadRequest(u"Error finding: {0}={1}".format(
235247
key, self.data[key]
236248
)))
237-
238-
# find the revision
239-
self.obj.revision, created = Revision.objects.get_or_create(
240-
commitid=self.data['commitid'],
241-
project=self.obj.project,
242-
branch=self.obj.branch,
243-
)
244249
# populate optional data
245250
for key in [k for k in self.optional_keys \
246251
if k not in ('date')]:
@@ -261,10 +266,6 @@ def _populate_by_obj(self):
261266
self.obj.branch = self.obj.revision.branch
262267
#self.obj.result = self.obj
263268
setattr(self.obj, 'result', self.obj)
264-
# TODO (a8): add user to models
265-
setattr(self.obj, 'user', User.objects.get(pk=1))
266-
#setattr(self.obj, 'user', None)
267-
setattr(self.obj, 'notify', None)
268269

269270
def _check_data(self):
270271
"""See if all mandatory data is there"""
@@ -284,8 +285,8 @@ def _check_data(self):
284285

285286
# Check that the Environment exists
286287
try:
287-
self.obj.environment = Environment.objects.get(
288-
name=self.data['environment'])
288+
self.obj.environment = EnvironmentResource().get_via_uri(
289+
self.data['environment'])
289290
except Environment.DoesNotExist:
290291
error_text = 'Environment: {0} not found in database.'.format(
291292
self.data['environment'])
@@ -327,13 +328,13 @@ def _check_data(self):
327328
raise ImmediateHttpResponse(
328329
response=HttpBadRequest(error_text))
329330

330-
def save(self):
331-
"""Save self.obj which is an instance of Result()
331+
def hydrate_and_save(self):
332+
"""Save self.obj which is an instance of Result()
332333
333-
First populate the Result() instance with self.data
334-
"""
335-
self._populate_obj_by_data()
336-
self.obj.save()
334+
First populate the Result() instance with self.data
335+
"""
336+
self._populate_obj_by_data()
337+
self.obj.save()
337338

338339

339340
class ResultBundleResource(Resource):
@@ -352,7 +353,7 @@ class ResultBundleResource(Resource):
352353
353354
not mandatory data
354355
'notify' - Send notification to registered user if result varies from
355-
previous results
356+
previous results, currently not implemented
356357
"""
357358

358359
revision = fields.ToOneField(RevisionResource, 'revision')
@@ -362,12 +363,13 @@ class ResultBundleResource(Resource):
362363
benchmark = fields.ToOneField(BenchmarkResource, 'benchmark')
363364
environment = fields.ToOneField(EnvironmentResource, 'environment')
364365
result = fields.ToOneField(ResultResource, 'result')
365-
user = fields.ToOneField(UserResource, 'user', null=True)
366-
notify = fields.CharField(attribute='notify', null=True)
367366

368367
class Meta:
369368
resource_name = 'benchmark-result'
370-
authorization = Authorization()
369+
object_class = Result
370+
authorization = DjangoAuthorization()
371+
authentication = MultiAuthentication(ApiKeyAuthentication(),
372+
Authentication())
371373
allowed_methods = ['get', 'post', 'put', 'delete']
372374

373375
def get_resource_uri(self, bundle_or_obj):
@@ -383,7 +385,6 @@ def get_resource_uri(self, bundle_or_obj):
383385
if self._meta.api_name is not None:
384386
kwargs['api_name'] = self._meta.api_name
385387

386-
#FIXME (a8): reverse url should point to ResultResource()
387388
return self._build_reverse_url("api_dispatch_detail", kwargs=kwargs)
388389

389390
def get_object_list(self, request):
@@ -402,16 +403,14 @@ def obj_get(self, request=None, **kwargs):
402403
result.project = result.executable.project
403404
result.branch = result.revision.branch
404405
setattr(result, 'result', result)
405-
# TODO (a8): add user to models
406-
#setattr(result, 'user', User.objects.get(pk=1))
407-
setattr(result, 'user', None)
408-
#setattr(result, 'notify', None)
409406
return result
410407

411408
def obj_create(self, bundle, request=None, **kwargs):
412-
# FIXME (a8): Make full_hydrate work
409+
# not calling hydrate here since bundle.save() has that functionality
410+
# self.full_hydrate(bundle) will try to hydrate result which is not
411+
# there yet
413412
#bundle = self.full_hydrate(bundle)
414-
bundle.save()
413+
bundle.hydrate_and_save()
415414
return bundle
416415

417416
def obj_update(self, bundle, request=None, **kwargs):
@@ -457,3 +456,6 @@ def obj_delete(self, request=None, **kwargs):
457456

458457
def rollback(self, bundles):
459458
pass
459+
460+
def detail_uri_kwargs(self):
461+
pass

0 commit comments

Comments
 (0)