Skip to content

Commit eb59c04

Browse files
committed
Raise tastypie.NotFound in couch mixin helper
Ensures that a 404 is returned when a couch resource that uses this helper is not found
1 parent d30c334 commit eb59c04

4 files changed

Lines changed: 56 additions & 6 deletions

File tree

corehq/apps/api/resources/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22

3-
from django.core.exceptions import ValidationError
3+
from django.core.exceptions import ObjectDoesNotExist, ValidationError
44
from django.http import HttpResponse
55
from django.urls import NoReverseMatch, include, re_path
66

@@ -16,7 +16,7 @@
1616
from corehq.apps.accounting.utils import domain_has_privilege
1717
from corehq.apps.analytics.tasks import track_workflow_noop
1818
from corehq.apps.api.cors import add_cors_headers_to_response
19-
from corehq.apps.api.util import get_obj
19+
from corehq.apps.api.util import get_obj, get_object_or_not_exist
2020
from corehq.apps.users.util import is_dimagi_email
2121

2222

@@ -356,3 +356,12 @@ def detail_uri_kwargs(self, bundle_or_obj):
356356
return {
357357
'pk': get_obj(bundle_or_obj)._id
358358
}
359+
360+
def get_document_for_update(self, doc_id, domain):
361+
"""
362+
Converts ``ObjectDoesNotExist`` into ``tastypie.NotFound``
363+
"""
364+
try:
365+
return get_object_or_not_exist(self._meta.object_class, doc_id, domain)
366+
except ObjectDoesNotExist as err:
367+
raise NotFound(str(err))

corehq/apps/api/resources/v0_5.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,7 @@ def validate_new_user_input(require_account_confirmation, send_confirmation_emai
349349
raise BadRequest(_("You must require account confirmation to send a confirmation email."))
350350

351351
def obj_update(self, bundle, **kwargs):
352-
bundle.obj = CommCareUser.get(kwargs['pk'])
353-
assert bundle.obj.domain == kwargs['domain']
352+
bundle.obj = self.get_document_for_update(kwargs['pk'], kwargs['domain'])
354353
send_confirmation_email = string_to_boolean(bundle.data.pop('send_confirmation_email_now', False))
355354
user_change_logger = self._get_user_change_logger(bundle)
356355
errors = self._update(bundle, user_change_logger)
@@ -760,8 +759,7 @@ def obj_create(self, bundle, request=None, **kwargs):
760759
return bundle
761760

762761
def obj_update(self, bundle, **kwargs):
763-
bundle.obj = Group.get(kwargs['pk'])
764-
assert bundle.obj.domain == kwargs['domain']
762+
bundle.obj = self.get_document_for_update(kwargs['pk'], kwargs['domain'])
765763
if self._update(bundle):
766764
assert bundle.obj.domain == kwargs['domain']
767765
bundle.obj.save()

corehq/apps/api/tests/group_resources.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import uuid
23

34
from corehq.apps.api.resources import v0_5
45
from corehq.apps.es.groups import group_adapter
@@ -140,6 +141,25 @@ def test_update(self):
140141
self.assertTrue(modified.case_sharing)
141142
self.assertEqual(modified.metadata["localization"], "Ghana")
142143

144+
def test_cant_update_missing_group(self):
145+
response = self._assert_auth_post_resource(self.single_endpoint(uuid.uuid4().hex),
146+
json.dumps({"name": "test group"}),
147+
content_type='application/json',
148+
method='PUT')
149+
150+
assert response.status_code == 404, response.content
151+
152+
def test_cant_update_group_in_another_domain(self):
153+
not_my_group = self._add_group(Group({"name": "theirs", "domain": "not-my-project"}))
154+
155+
response = self._assert_auth_post_resource(self.single_endpoint(not_my_group._id),
156+
json.dumps({"name": "mine now"}),
157+
content_type='application/json',
158+
method='PUT')
159+
160+
assert response.status_code == 404, response.content
161+
assert Group.get(not_my_group._id).name == "theirs"
162+
143163
def test_delete_group(self):
144164

145165
group = self._add_group(Group({"name": "test", "domain": self.domain.name}))

corehq/apps/api/tests/test_user_resources.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import json
2+
import uuid
23
from unittest.mock import Mock, patch, call
34

45
from django.test import TestCase
@@ -458,6 +459,28 @@ def test_update(self):
458459
self.assertEqual(user_history.change_messages['password'], UserChangeMessage.password_reset()['password'])
459460
self.assertEqual(user_history.changed_via, USER_CHANGE_VIA_API)
460461

462+
def test_cant_update_missing_user(self):
463+
response = self._assert_auth_post_resource(self.single_endpoint(uuid.uuid4().hex),
464+
json.dumps({"first_name": "test"}),
465+
content_type='application/json',
466+
method='PUT')
467+
468+
assert response.status_code == 404, response.content
469+
470+
def test_cant_update_user_in_another_domain(self):
471+
not_my_user = CommCareUser.create(domain='not-my-project', username="theirs",
472+
password="qwer1234", created_by=None, created_via=None)
473+
self.addCleanup(not_my_user.delete, 'not-my-project', deleted_by=None)
474+
first_name_before = not_my_user.first_name
475+
476+
response = self._assert_auth_post_resource(self.single_endpoint(not_my_user._id),
477+
json.dumps({"first_name": "mine now"}),
478+
content_type='application/json',
479+
method='PUT')
480+
481+
assert response.status_code == 404, response.content
482+
assert CommCareUser.get(not_my_user._id).first_name == first_name_before
483+
461484
def test_update_fails(self):
462485
user = CommCareUser.create(domain=self.domain.name, username="test", password="qwer1234",
463486
created_by=None, created_via=None, phone_number="50253311398")

0 commit comments

Comments
 (0)