Example #1
0
def reprocess_form_cases(form, config=None, case_db=None):
    """
    For a given form, reprocess all case elements inside it. This operation
    should be a no-op if the form was sucessfully processed, but should
    correctly inject the update into the case history if the form was NOT
    successfully processed.
    """
    from casexml.apps.case import process_cases, process_cases_with_casedb

    if case_db:
        process_cases_with_casedb(form, case_db, config=config)
    else:
        process_cases(form, config)
    # mark cleaned up now that we've reprocessed it
    if form.doc_type != 'XFormInstance':
        form = XFormInstance.get(form._id)
        form.doc_type = 'XFormInstance'
        form.save()
Example #2
0
    def run(self):
        if not self.auth_context.is_valid():
            return self.failed_auth_response, None, []

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

        def process(xform):
            self._attach_shared_props(xform)
            scrub_meta(xform)

        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 import process_cases_with_casedb
            from casexml.apps.case.models import CommCareCase
            from casexml.apps.case.xform import get_and_check_xform_domain, CaseDbCache
            from casexml.apps.case.signals import case_post_save
            from casexml.apps.case.exceptions import IllegalCaseId
            from corehq.apps.commtrack.processing import process_stock

            cases = []
            responses = []
            errors = []
            with lock_manager as xforms:
                instance = xforms[0]
                if instance.doc_type == "XFormInstance":
                    domain = get_and_check_xform_domain(instance)
                    with CaseDbCache(domain=domain, lock=True, deleted_ok=True) as case_db:
                        try:
                            process_cases_with_casedb(instance, case_db)
                            process_stock(instance, case_db)
                        except IllegalCaseId as e:
                            error_message = '{}: {}'.format(
                                type(e).__name__, unicode(e))
                            logging.exception((
                                u"Warning in case or stock processing "
                                u"for form {}: {}."
                            ).format(instance._id, error_message))
                            instance.__class__ = XFormError
                            instance.problem = error_message
                            instance.save()
                            response = self._get_open_rosa_response(instance,
                                                                    None, None)
                            return response, instance, cases
                        except Exception as e:
                            # Some things to consider here
                            # The following code saves the xform instance
                            # as an XFormError, with a different ID.
                            # That's because if you save with the original ID
                            # and then resubmit, the new submission never has a
                            # chance to get reprocessed; it'll just get saved as
                            # a duplicate.
                            error_message = '{}: {}'.format(
                                type(e).__name__, unicode(e))
                            new_id = XFormError.get_db().server.next_uuid()
                            logging.exception((
                                u"Error in case or stock processing "
                                u"for form {}: {}.\n"
                                u"Error saved as {}"
                            ).format(instance._id, error_message, new_id))
                            instance.__class__ = XFormError
                            instance.orig_id = instance._id
                            instance._id = new_id
                            instance.problem = 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 useless now
                        instance.initial_processing_complete = True
                        assert XFormInstance.get_db().uri == CommCareCase.get_db().uri
                        docs = xforms + cases

                        # in saving the cases, we have to do all the things
                        # done in CommCareCase.save()
                        for case in cases:
                            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
                                    )
                                )
                        try:
                            XFormInstance.get_db().bulk_save(docs)
                        except BulkSaveError as e:
                            logging.exception('BulkSaveError saving forms', extra={'errors': e.errors})
                            raise
                        unfinished_submission_stub.saved = True
                        unfinished_submission_stub.save()
                        for case in cases:
                            case_post_save.send(CommCareCase, case=case)
                        responses, 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, responses, errors)
            return response, instance, cases