Example #1
0
    def _handle_basic_failure_modes(self):
        if timezone_migration_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503), None, []

        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message), None, []
    def _handle_basic_failure_modes(self):
        if timezone_migration_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503), None, []

        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message), None, []
Example #3
0
    def run(self):
        if timezone_migration_in_progress(self.domain):
            # keep submissions on the phone
            # until ready to start accepting again
            return HttpResponse(status=503), None, []

        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

        if isinstance(self.instance, BadRequest):
            return HttpResponseBadRequest(self.instance.message), None, []

        def process(xform):
            self._attach_shared_props(xform)
            if xform.doc_type != 'SubmissionErrorLog':
                found_old = scrub_meta(xform)
                legacy_soft_assert(not found_old, 'Form with old metadata submitted', xform._id)

        try:
            lock_manager = process_xform(self.instance,
                                         attachments=self.attachments,
                                         process=process,
                                         domain=self.domain)
        except SubmissionError as e:
            logging.exception(
                u"Problem receiving submission to %s. %s" % (
                    self.path,
                    unicode(e),
                )
            )
            return self.get_exception_response(e.error_log), None, []
        else:
            from casexml.apps.case.models import CommCareCase
            from casexml.apps.case.xform import (
                get_and_check_xform_domain, CaseDbCache, process_cases_with_casedb
            )
            from casexml.apps.case.signals import case_post_save
            from casexml.apps.case.exceptions import IllegalCaseId, UsesReferrals
            from corehq.apps.commtrack.processing import process_stock
            from corehq.apps.commtrack.exceptions import MissingProductId

            cases = []
            responses = []
            errors = []
            known_errors = (IllegalCaseId, UsesReferrals, MissingProductId,
                            PhoneDateValueError)
            with lock_manager as xforms:
                instance = xforms[0]
                if instance.doc_type == 'XFormInstance':
                    if len(xforms) > 1:
                        assert len(xforms) == 2
                        assert is_deprecation(xforms[1])
                    domain = get_and_check_xform_domain(instance)
                    with CaseDbCache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db:
                        try:
                            case_result = process_cases_with_casedb(xforms, case_db)
                            stock_result = process_stock(xforms, case_db)
                        except known_errors as e:
                            # errors we know about related to the content of the form
                            # log the error and respond with a success code so that the phone doesn't
                            # keep trying to send the form
                            instance = _handle_known_error(e, instance)
                            xforms[0] = instance
                            # this is usually just one document, but if an edit errored we want
                            # to save the deprecated form as well
                            XFormInstance.get_db().bulk_save(xforms)
                            response = self._get_open_rosa_response(
                                instance, None)
                            return response, instance, cases
                        except Exception as e:
                            # handle / log the error and reraise so the phone knows to resubmit
                            # note that in the case of edit submissions this won't flag the previous
                            # submission as having been edited. this is intentional, since we should treat
                            # this use case as if the edit "failed"
                            error_message = u'{}: {}'.format(type(e).__name__, unicode(e))
                            instance = _handle_unexpected_error(instance, error_message)
                            instance.save()
                            raise
                        now = datetime.datetime.utcnow()
                        unfinished_submission_stub = UnfinishedSubmissionStub(
                            xform_id=instance.get_id,
                            timestamp=now,
                            saved=False,
                            domain=domain,
                        )
                        unfinished_submission_stub.save()
                        cases = case_db.get_changed()
                        # todo: this property is only used by the MVPFormIndicatorPillow
                        instance.initial_processing_complete = True

                        # in saving the cases, we have to do all the things
                        # done in CommCareCase.save()
                        for case in cases:
                            legacy_soft_assert(case.version == "2.0", "v1.0 case updated", case.case_id)
                            case.initial_processing_complete = True
                            case.server_modified_on = now
                            try:
                                rev = CommCareCase.get_db().get_rev(case.case_id)
                            except ResourceNotFound:
                                pass
                            else:
                                assert rev == case.get_rev, (
                                    "Aborting because there would have been "
                                    "a document update conflict. {} {} {}".format(
                                        case.get_id, case.get_rev, rev
                                    )
                                )

                        # verify that these DB's are the same so that we can save them with one call to bulk_save
                        assert XFormInstance.get_db().uri == CommCareCase.get_db().uri
                        docs = xforms + cases
                        try:
                            XFormInstance.get_db().bulk_save(docs)
                        except BulkSaveError as e:
                            logging.error('BulkSaveError saving forms', exc_info=1,
                                          extra={'details': {'errors': e.errors}})
                            raise
                        except Exception as e:
                            docs_being_saved = [doc['_id'] for doc in docs]
                            error_message = u'Unexpected error bulk saving docs {}: {}, doc_ids: {}'.format(
                                type(e).__name__,
                                unicode(e),
                                ', '.join(docs_being_saved)
                            )
                            instance = _handle_unexpected_error(instance, error_message)
                            instance.save()
                            raise
                        unfinished_submission_stub.saved = True
                        unfinished_submission_stub.save()
                        case_result.commit_dirtiness_flags()
                        stock_result.commit()
                        for case in cases:
                            case_post_save.send(CommCareCase, case=case)

                    errors = self.process_signals(instance)
                    if errors:
                        # .problems was added to instance
                        instance.save()
                    unfinished_submission_stub.delete()
                elif instance.doc_type == 'XFormDuplicate':
                    assert len(xforms) == 1
                    instance.save()
            response = self._get_open_rosa_response(instance, errors)
            return response, instance, cases