diff --git a/kobo/apps/openrosa/apps/api/tests/viewsets/test_xform_submission_api.py b/kobo/apps/openrosa/apps/api/tests/viewsets/test_xform_submission_api.py index a4cacb3661..5c4c07ebd0 100644 --- a/kobo/apps/openrosa/apps/api/tests/viewsets/test_xform_submission_api.py +++ b/kobo/apps/openrosa/apps/api/tests/viewsets/test_xform_submission_api.py @@ -13,7 +13,10 @@ from kobo.apps.openrosa.apps.logger.models import Attachment from kobo.apps.openrosa.libs.constants import CAN_ADD_SUBMISSIONS from kobo.apps.openrosa.libs.utils.guardian import assign_perm -from kobo.apps.openrosa.libs.utils.logger_tools import OpenRosaTemporarilyUnavailable +from kobo.apps.openrosa.libs.utils.logger_tools import ( + OpenRosaResponseNotAllowed, + OpenRosaTemporarilyUnavailable, +) class TestXFormSubmissionApi(TestAbstractViewSet): @@ -377,6 +380,42 @@ def test_post_submission_json_without_submission_key(self): response = self.view(request) self.assertContains(response, 'No submission key provided.', status_code=400) + def test_submission_account_inactive(self): + """ + Verify that submissions are blocked when the owning user has + `is_active = False` + """ + self.xform.user.is_active = False + self.xform.user.save() + + # No need auth for this test + self.xform.require_auth = False + self.xform.save(update_fields=['require_auth']) + + s = self.surveys[0] + username = self.user.username + submission_path = os.path.join( + self.main_directory, + 'fixtures', + 'transportation', + 'instances', + s, + s + '.xml', + ) + with open(submission_path) as sf: + request = self.factory.post( + f'/{username}/submission', {'xml_submission_file': sf} + ) + request.user = AnonymousUser() + + # Ensure that submissions are not accepted since the owning user is + # inactive + response = self.view(request, username=username) + self.assertEqual( + response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED + ) + self.assertTrue(isinstance(response, OpenRosaResponseNotAllowed)) + def test_submission_blocking_flag(self): # Set 'submissions_suspended' True in the profile to test if # submission do fail with the flag set diff --git a/kobo/apps/openrosa/apps/logger/exceptions.py b/kobo/apps/openrosa/apps/logger/exceptions.py index d8b85c5c94..64c51e39ae 100644 --- a/kobo/apps/openrosa/apps/logger/exceptions.py +++ b/kobo/apps/openrosa/apps/logger/exceptions.py @@ -10,6 +10,10 @@ class BuildDbQueriesNoConfirmationProvidedError(Exception): pass +class AccountInactiveError(Exception): + pass + + class DuplicateUUIDError(Exception): pass diff --git a/kobo/apps/openrosa/apps/logger/models/instance.py b/kobo/apps/openrosa/apps/logger/models/instance.py index d9819ceeee..ef57d9f26b 100644 --- a/kobo/apps/openrosa/apps/logger/models/instance.py +++ b/kobo/apps/openrosa/apps/logger/models/instance.py @@ -12,6 +12,7 @@ from kobo.apps.kobo_auth.shortcuts import User from kobo.apps.openrosa.apps.logger.exceptions import ( + AccountInactiveError, FormInactiveError, TemporarilyUnavailableError, ) @@ -131,7 +132,9 @@ def check_active(self, force): profile, created = UserProfile.objects.get_or_create(user=self.xform.user) if not created and profile.submissions_suspended: raise TemporarilyUnavailableError() - return + + if not self.xform.user.is_active: + raise AccountInactiveError() def _set_geom(self): xform = self.xform diff --git a/kobo/apps/openrosa/libs/utils/logger_tools.py b/kobo/apps/openrosa/libs/utils/logger_tools.py index 9492e88f8e..10f0a6e194 100644 --- a/kobo/apps/openrosa/libs/utils/logger_tools.py +++ b/kobo/apps/openrosa/libs/utils/logger_tools.py @@ -38,6 +38,7 @@ from rest_framework.exceptions import NotAuthenticated from kobo.apps.openrosa.apps.logger.exceptions import ( + AccountInactiveError, DuplicateUUIDError, FormInactiveError, TemporarilyUnavailableError, @@ -310,6 +311,9 @@ def status_code(self): except TemporarilyUnavailableError: result.error = t('Temporarily unavailable') result.http_error_response = OpenRosaTemporarilyUnavailable(result.error) + except AccountInactiveError: + result.error = t('Account is not active') + result.http_error_response = OpenRosaResponseNotAllowed(result.error) except XForm.DoesNotExist: result.error = t('Form does not exist on this account') result.http_error_response = OpenRosaResponseNotFound(result.error)