Browse files

add API Key for mobile API

  • Loading branch information...
1 parent cdd4b35 commit 556b49716f923f1990289c3bff4f946e1d938891 @visiblegovernment committed Jul 8, 2011
View
11 mainapp/fixtures/test_rest.json → mainapp/fixtures/test_mobile.json
@@ -1,6 +1,17 @@
[
{
"pk": 1,
+ "model": "mainapp.apikey",
+ "fields": {
+ "organization": "Test Mobile API",
+ "key": "test_mobile_api_key",
+ "type": 1,
+ "approved": true,
+ "contact_email": "test@yahoo.ca"
+ }
+ },
+ {
+ "pk": 1,
"model": "mainapp.report",
"fields": {
"category": 5,
View
2 mainapp/models.py
@@ -320,7 +320,7 @@ class Report(models.Model):
is_confirmed = models.BooleanField(default=False)
# what API did the report come in on?
- api = models.ForeignKey(ApiKey,null=True,blank=True)
+ api_key = models.ForeignKey(ApiKey,null=True,blank=True)
# this this report come in from a particular mobile app?
device_id = models.CharField(max_length=100,null=True,blank=True)
View
38 mainapp/tests/open311/v2.py
@@ -1,14 +1,16 @@
from django.test import TestCase
from django.test.client import Client
import os
-from mainapp.models import Report
+from mainapp.models import Report,ApiKey
import xml.dom.minidom
from django.core import mail
PATH = os.path.dirname(__file__)
ANON_CREATE_PARAMS = { 'lat': '45.4198266',
'lon': '-75.6943189',
+ 'api_key': 'test_mobile_api_key',
+ 'device_id': '411',
'service_code': 5,
'location': 'Some Street',
'first_name': 'John',
@@ -20,6 +22,8 @@
}
LOGGEDIN_CREATE_PARAMS = { 'title': 'A report from our API from a logged in user',
+ 'api_key': 'test_mobile_api_key',
+ 'device_id': '411',
'lat': '45.4301269580000024',
'lon': '-75.6824648380000014',
'location': 'Some Street',
@@ -36,11 +40,12 @@
'title': None,
'description': ['description:This field is required.'],
'email': ['email:This field is required.'],
- 'phone': None }
+ 'phone': None,
+ 'api_key': [ 'description:This field is required.' ] }
class Open311v2(TestCase):
- fixtures = ['test_rest.json']
+ fixtures = ['test_mobile.json']
c = Client()
def test_get_report(self):
@@ -79,23 +84,26 @@ def test_get_by_start_date(self):
response = self.c.get(url)
self._expectXML(response, 'get_report_4.xml' )
- def _create_request(self, params,expected_errors=None, anon=True):
-
+ def _create_request(self, params,expected_errors=None, anon=True, error_code=400):
+ api_key = ApiKey.objects.get(key='test_mobile_api_key')
response = self.c.post(self._reportsUrl(), params, **{ "wsgi.url_scheme" : "https" } )
doc = xml.dom.minidom.parseString(response.content)
if not expected_errors:
self.assertEquals( response.status_code, 200 )
- self.assertEqual(Report.objects.filter(desc=ANON_CREATE_PARAMS['description']).count(), 1 )
+ self.assertEqual(Report.objects.filter(api_key=api_key,device_id=ANON_CREATE_PARAMS['device_id'],desc=ANON_CREATE_PARAMS['description']).count(), 1 )
self.assertEquals(len(mail.outbox), 1, 'an email was sent')
if anon:
self.assertEquals(mail.outbox[0].to, ['testuser@hotmail.com'])
self.assertEqual(len(doc.getElementsByTagName('service_request_id')), 1, "there is a request id in the resposne")
request_id = doc.getElementsByTagName('service_request_id')[0].childNodes[0].data
self.assertEquals( request_id, '6', "we've created a new request" )
else:
- self.assertEquals( response.status_code, 400 )
- errors = doc.getElementsByTagName('error')
+ self.assertEquals( response.status_code, error_code )
+ errors = doc.getElementsByTagName('description')
+ if len(errors) != len(expected_errors):
+ for error in errors:
+ print error.childNodes[0].data
self.assertEquals(len(errors),len(expected_errors))
for error in errors:
error_text = error.childNodes[0].data
@@ -104,10 +112,10 @@ def _create_request(self, params,expected_errors=None, anon=True):
def test_anon_report_post(self):
self._create_request(ANON_CREATE_PARAMS)
- def _test_post_missing(self, field ):
+ def _test_post_missing(self, field, error_code=400 ):
params = ANON_CREATE_PARAMS.copy()
del( params[field])
- self._create_request(params,expected_errors=EXPECTED_ERRORS[field])
+ self._create_request(params,expected_errors=EXPECTED_ERRORS[field],error_code=error_code)
def test_post_missing_title(self):
self._test_post_missing('title')
@@ -147,6 +155,16 @@ def test_bad_latlon(self):
expect = ['__all__:lat/lon not supported']
self._create_request(params,expected_errors=expect)
+ def test_post_missing_api_key(self):
+ params = ANON_CREATE_PARAMS.copy()
+ del(params[ 'api_key' ])
+ self._create_request(params,["403:Invalid api_key received -- can't proceed with create_request."],error_code=403)
+
+ def test_bad_api_key(self):
+ params = ANON_CREATE_PARAMS.copy()
+ params[ 'api_key' ] = 'bad api key'
+ self._create_request(params,["403:Invalid api_key received -- can't proceed with create_request."],error_code=403)
+
def _url(self, url):
return('/open311/v2/' + url )
View
50 mainapp/views/mobile/open311v2.py
@@ -3,11 +3,32 @@
from django.shortcuts import render,render_to_response, get_object_or_404
from django.template import Context, RequestContext
from django.http import HttpResponse, HttpResponseBadRequest
-from mainapp.models import Report,ReportCategory,DictToPoint
+from mainapp.models import ApiKey,Report,ReportCategory,DictToPoint
from django.conf.urls.defaults import patterns, url, include
from mainapp.forms import ReportForm
from django.conf import settings
from django import forms
+from django.core.exceptions import ObjectDoesNotExist
+
+
+class InvalidAPIKey(Exception):
+
+ def __init__(self):
+ super(InvalidAPIKey,self).__init__("Invalid api_key received -- can't proceed with create_request.")
+
+
+class ApiKeyField(forms.fields.CharField):
+
+ def __init__(self,required=True, widget=None, label=None,
+ initial=None, help_text=None, *args, **kwargs):
+ super(ApiKeyField,self).__init__(required=required,widget=widget,label=label,initial=initial,help_text=help_text,*args,**kwargs)
+
+ def clean(self, value):
+ try:
+ api_key = ApiKey.objects.get(key=value)
+ except ObjectDoesNotExist:
+ raise InvalidAPIKey()
+ return api_key
class Open311ReportForm(ReportForm):
@@ -16,17 +37,19 @@ class Open311ReportForm(ReportForm):
description = forms.fields.CharField()
first_name = forms.fields.CharField(required=False)
last_name = forms.fields.CharField()
-
+ api_key = ApiKeyField()
+
class Meta:
model = Report
- fields = ('service_code','description','lat','lon','title', 'category', 'photo')
+ fields = ('service_code','description','lat','lon','title', 'category', 'photo','device_id','api_key')
def __init__(self,data=None,files=None,initial=None, freeze_email=False):
if data:
data['desc'] = data.get('description','')
data['category'] = data.get('service_code','1')
data['author'] = (data.get('first_name','') + " " + data.get('last_name','')).strip()
super(Open311ReportForm,self).__init__(data,files, initial=initial,freeze_email=freeze_email)
+ self.fields['device_id'].required = True
self.fields['category'].required = False
self.fields['title'].required = False
self.update_form.fields['author'].required = False
@@ -39,7 +62,8 @@ def _get_category(self):
if len(categories) == 0:
return None
return(categories[0])
-
+
+
def clean_title(self):
data = self.cleaned_data.get('title',None)
if data:
@@ -76,11 +100,19 @@ def reports(self,request):
# creating a new report
data = request.POST.copy()
report_form = Open311ReportForm( data, request.FILES )
- if report_form.is_valid():
- report = report_form.save(request.user.is_authenticated())
- if report:
- return( self._render_reports(request, [ report ] ) )
- return( self._render_errors(request, report_form.all_errors()))
+ try:
+ if report_form.is_valid():
+ report = report_form.save(request.user.is_authenticated())
+ if report:
+ return( self._render_reports(request, [ report ] ) )
+ return( self._render_errors(request, report_form.all_errors()))
+ except Exception, e:
+ return render( request,
+ 'open311/v2/_errors.%s' % (self.content_type),
+ { 'errors' : {'403' : str(e) } },
+ content_type = 'text/%s' % ( self.content_type ),
+ context_instance=RequestContext(request),
+ status = 403 )
def services(self,request):
services = ReportCategory.objects.all()
View
4 templates/open311/v2/_errors.xml
@@ -1,3 +1,5 @@
<errors>{% for key,value in errors.items %}
- <error>{{key}}:{{value}}</error>
+ <error>
+ <description>{{key}}:{{value|safe}}</description>
+ </error>
{% endfor %}</errors>

0 comments on commit 556b497

Please sign in to comment.