Merge lp:~cjohnston/ubuntu-ci-services-itself/people-write-api into lp:ubuntu-ci-services-itself

Proposed by Chris Johnston
Status: Merged
Approved by: Francis Ginther
Approved revision: 27
Merged at revision: 33
Proposed branch: lp:~cjohnston/ubuntu-ci-services-itself/people-write-api
Merge into: lp:ubuntu-ci-services-itself
Diff against target: 226 lines (+112/-16)
4 files modified
ci-utils/ci_utils/tastypie/test.py (+8/-2)
docs/components/ticket-system.rst (+46/-3)
ticket_system/people/api.py (+5/-3)
ticket_system/people/tests.py (+53/-8)
To merge this branch: bzr merge lp:~cjohnston/ubuntu-ci-services-itself/people-write-api
Reviewer Review Type Date Requested Status
Francis Ginther Approve
Andy Doan (community) Approve
Review via email: mp+198778@code.launchpad.net

Commit message

Add a write API for adding people, update docs with API examples

Description of the change

- Made changes to ci_utils.tastypie.test to use assertHttpCreated/assertHttpAccepted instead of assertEqual and a status_code
- Added a delete helper to ci_utils.tastypie.test
- Added write API to people app
- Updated docs to include API calls

RTD can be viewed at: http://162.213.34.2/rtd/components/ticket-system.html

To post a comment you must log in.
Revision history for this message
Andy Doan (doanac) :
review: Approve
Revision history for this message
Francis Ginther (fginther) wrote :

Approve.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ci-utils/ci_utils/tastypie/test.py'
2--- ci-utils/ci_utils/tastypie/test.py 2013-12-10 18:29:34 +0000
3+++ ci-utils/ci_utils/tastypie/test.py 2013-12-12 16:53:25 +0000
4@@ -52,7 +52,7 @@
5 resource = self._resource(resource)
6 resp = self.client.post(
7 resource, data=params, authentication=self.auth)
8- self.assertEqual(201, resp.status_code)
9+ self.assertHttpCreated(resp)
10 return resp['location']
11
12 def patch(self, resource, params):
13@@ -60,7 +60,7 @@
14 resource = self._resource(resource)
15 resp = self.client.patch(
16 resource, data=params, authentication=self.auth)
17- self.assertEqual(202, resp.status_code)
18+ self.assertHttpAccepted(resp)
19
20 def getResource(self, resource, params={}):
21 '''Grab a single resource and return it as a dict.'''
22@@ -74,3 +74,9 @@
23 '''Create a resource, get it, and return the dict.'''
24 loc = self.post(resource, params)
25 return self.getResource(loc)
26+
27+ def delete(self, resource):
28+ '''Delete an existing resource.'''
29+ resource = self._resource(resource)
30+ resp = self.client.delete(resource, authentication=self.auth)
31+ return resp
32
33=== modified file 'docs/components/ticket-system.rst'
34--- docs/components/ticket-system.rst 2013-12-09 21:45:15 +0000
35+++ docs/components/ticket-system.rst 2013-12-12 16:53:25 +0000
36@@ -138,7 +138,7 @@
37 List all open tickets.
38
39
40-te_ticket
41+create_ticket
42 ~~~~~~~~~~~~~
43
44 Create a ticket from one or more source package uploads.
45@@ -169,12 +169,55 @@
46 add_person
47 ~~~~~~~~~~
48
49-Add a person to the database.
50+Add a person (or a team) to the database.
51+
52+*person*
53+
54+::
55+
56+ curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "Chris Johnston", "email": "chris.johnston@canonical.com", "is_team": "False"}' http://localhost:8000/api/v1/person/
57+
58+
59+*team*
60+
61+::
62+
63+ curl --dump-header - -H "Content-Type: application/json" -X POST --data '{"name": "Canonical CI Engineering", "email": "canonical-ci-engineering@lists.launchpad.net", "is_team": "True"}' http://localhost:8000/api/v1/person/
64+
65
66 get_person
67 ~~~~~~~~~~
68
69-Return a person from the database, given it's nickname/email.
70+*Return all persons*
71+
72+::
73+
74+ curl http://localhost:8000/api/v1/person/
75+
76+*search by name*
77+
78+::
79+
80+ curl --dump-header - http://localhost:8000/api/v1/person/?name__exact=Chris%20Johnston
81+ curl --dump-header - http://localhost:8000/api/v1/person/?name__iexact=chris%20johnston
82+ curl --dump-header - http://localhost:8000/api/v1/person/?name__startswith=Chris
83+ curl --dump-header - http://localhost:8000/api/v1/person/?name__istartswith=chris
84+
85+*search by email*
86+
87+::
88+
89+ curl --dump-header - http://localhost:8000/api/v1/person/?email__exact=chris.johnston@canonical.com
90+ curl --dump-header - http://localhost:8000/api/v1/person/?email__iexact=Chris.Johnston@canonical.com
91+ curl --dump-header - http://localhost:8000/api/v1/person/?email__startswith=chris
92+ curl --dump-header - http://localhost:8000/api/v1/person/?email__istartswith=Chris
93+
94+*show/don't show teams*
95+
96+::
97+
98+ curl --dump-header - http://localhost:8000/api/v1/person/?is_team=True
99+ curl --dump-header - http://localhost:8000/api/v1/person/?is_team=False
100
101 Models
102 ******
103
104=== modified file 'ticket_system/people/api.py'
105--- ticket_system/people/api.py 2013-12-10 20:32:31 +0000
106+++ ticket_system/people/api.py 2013-12-12 16:53:25 +0000
107@@ -13,6 +13,7 @@
108 # You should have received a copy of the GNU Affero General Public License
109 # along with this program. If not, see <http://www.gnu.org/licenses/>.
110
111+from tastypie.authorization import Authorization
112 from tastypie.resources import ModelResource
113 from tastypie.constants import ALL
114 from people.models import Person
115@@ -21,9 +22,10 @@
116 class PersonResource(ModelResource):
117 class Meta:
118 queryset = Person.objects.all()
119- allowed_methods = ['get']
120+ allowed_methods = ['get', 'post', 'patch']
121+ authorization = Authorization()
122 filtering = {
123- "name": ('exact', 'startswith'),
124- "email": ('exact', 'startswith'),
125+ "name": ('exact', 'iexact', 'startswith', 'istartswith'),
126+ "email": ('exact', 'iexact', 'startswith', 'istartswith'),
127 "is_team": ALL,
128 }
129
130=== modified file 'ticket_system/people/tests.py'
131--- ticket_system/people/tests.py 2013-12-11 19:05:24 +0000
132+++ ticket_system/people/tests.py 2013-12-12 16:53:25 +0000
133@@ -18,8 +18,8 @@
134 from people.models import Person
135
136
137-def create_person(name="Chris Johnston",
138- email="chris.johnston@canonical.com", is_team=False):
139+def create_person(name="Johnny Test",
140+ email="johnny.test@example.com", is_team=False):
141 person = Person()
142 person.name = name
143 person.email = email
144@@ -37,9 +37,9 @@
145 only_person_in_database = people_in_database[0]
146 self.assertEquals(only_person_in_database, person)
147
148- self.assertEquals(only_person_in_database.name, "Chris Johnston")
149+ self.assertEquals(only_person_in_database.name, "Johnny Test")
150 self.assertEquals(only_person_in_database.email,
151- "chris.johnston@canonical.com")
152+ "johnny.test@example.com")
153
154
155 class PersonResourceTest(TastypieTestCase):
156@@ -47,16 +47,25 @@
157 def setUp(self):
158 super(PersonResourceTest, self).setUp('/api/v1')
159 create_person()
160- self.person_1 = Person.objects.get(name='Chris Johnston')
161+ self.person_1 = Person.objects.get(name='Johnny Test')
162 self.detail_url = 'person/{0}/'.format(self.person_1.pk)
163+ self.post_person_data = {
164+ 'name': 'Judy Test',
165+ 'email': 'judy.test@example.com',
166+ }
167+ self.post_team_data = {
168+ 'name': 'CI Test Team',
169+ 'email': 'ci.team@example.com',
170+ 'is_team': 'True',
171+ }
172
173 def test_get_person_list_json(self):
174 obj = self.getResource('person/')
175 self.assertEqual(obj['objects'][0], {
176- u'email': u'chris.johnston@canonical.com',
177+ u'email': u'johnny.test@example.com',
178 u'id': self.person_1.pk,
179 u'is_team': False,
180- u'name': u'Chris Johnston',
181+ u'name': u'Johnny Test',
182 u'resource_uri': u'/api/v1/person/{0}/'.format(self.person_1.pk)
183 })
184
185@@ -65,4 +74,40 @@
186
187 self.assertKeys(obj,
188 ['email', 'id', 'is_team', 'name', 'resource_uri'])
189- self.assertEqual(obj['name'], 'Chris Johnston')
190+ self.assertEqual(obj['name'], 'Johnny Test')
191+
192+ def test_post_person_list(self):
193+ # Check how many are there first.
194+ self.assertEqual(Person.objects.count(), 1)
195+ self.post(resource='person/', params=self.post_person_data)
196+ # Verify a new one has been added.
197+ self.assertEqual(Person.objects.count(), 2)
198+
199+ def test_post_team_list(self):
200+ # Check how many are there first.
201+ self.assertEqual(Person.objects.filter(is_team=True).count(), 0)
202+ self.post(resource='person/', params=self.post_team_data)
203+ # Verify a new one has been added.
204+ self.assertEqual(Person.objects.filter(is_team=True).count(), 1)
205+
206+ def test_put_detail(self):
207+ # Grab the current data & modify it slightly.
208+ original_data = self.getResource(self.detail_url)
209+ new_data = original_data.copy()
210+ new_data['email'] = 'jtest@example.com'
211+
212+ self.assertEqual(Person.objects.count(), 1)
213+ self.patch(resource=self.detail_url, params=new_data)
214+ # Make sure the count hasn't changed & we did an update.
215+ self.assertEqual(Person.objects.count(), 1)
216+ # Check for updated data.
217+ self.assertEqual(Person.objects.get(pk=self.person_1.pk).name,
218+ 'Johnny Test')
219+ self.assertEqual(Person.objects.get(pk=self.person_1.pk).email,
220+ 'jtest@example.com')
221+ self.assertEqual(Person.objects.get(pk=self.person_1.pk).is_team,
222+ False)
223+
224+ def test_delete_person_not_allowed(self):
225+ resp = self.delete(resource=self.detail_url)
226+ self.assertHttpMethodNotAllowed(resp)

Subscribers

People subscribed via source and target branches