示例#1
0
def property_changed_in_action(domain, case_transaction, case_id, case_property_name):
    from casexml.apps.case.xform import get_case_updates
    PropertyChangedInfo = namedtuple("PropertyChangedInfo", 'transaction new_value modified_on')
    include_create_fields = case_property_name in ['owner_id', 'name', 'external_id']

    if not should_use_sql_backend(domain):
        # couch domains return 2 transactions for case properties created in a create form
        if case_transaction.is_case_create and not include_create_fields:
            return False

    case_updates = get_case_updates(case_transaction.form)

    actions = []
    for update in case_updates:
        if update.id == case_id:
            actions.append((update.modified_on_str, update.get_update_action(), case_transaction))
            if include_create_fields and case_transaction.is_case_create:
                actions.append((update.modified_on_str, update.get_create_action(), case_transaction))

    for (modified_on, action, case_transaction) in actions:
        if action:
            property_changed = action.dynamic_properties.get(case_property_name)
            if include_create_fields and not property_changed:
                property_changed = getattr(action, case_property_name, None)

            if property_changed is not None:
                return PropertyChangedInfo(case_transaction, property_changed, modified_on)

    return False
示例#2
0
def create_case(case_id, files, patient_case_id=None):
    """
    Handle case submission for the sonosite endpoint
    """
    # we already parsed what we need from this, so can just remove it
    # without worrying we will need it later
    files.pop('PT_PPS.XML', '')

    xform = render_sonosite_xform(files, case_id, patient_case_id)

    file_dict = {}
    for f in files:
        file_dict[f] = UploadedFile(files[f], f)

    submit_form_locally(
        instance=xform,
        attachments=file_dict,
        domain=UTH_DOMAIN,
    )
    # this is a bit of a hack / abstraction violation
    # would be nice if submit_form_locally returned info about cases updated
    case_ids = {
        case_update.id
        for case_update in get_case_updates(convert_xform_to_json(xform))
    }
    return [CommCareCase.get(case_id) for case_id in case_ids]
示例#3
0
def safe_hard_delete(case):
    """
    Hard delete a case - by deleting the case itself as well as all forms associated with it
    permanently from the database.

    Will fail hard if the case has any reverse indices or if any of the forms associated with
    the case also touch other cases.

    This is used primarily for cleaning up system cases/actions (e.g. the location delegate case).
    """
    if not settings.UNIT_TESTING:
        from corehq.apps.commtrack.const import USER_LOCATION_OWNER_MAP_TYPE

        if not (case.is_deleted or case.type == USER_LOCATION_OWNER_MAP_TYPE):
            raise CommCareCaseError("Attempt to hard delete a live case whose type isn't white listed")

    if case.reverse_indices:
        raise CommCareCaseError("You can't hard delete a case that has other dependencies ({})!".format(case.case_id))
    interface = FormProcessorInterface(case.domain)
    forms = interface.get_case_forms(case.case_id)
    for form in forms:
        case_updates = get_case_updates(form)
        if any([c.id != case.case_id for c in case_updates]):
            raise CommCareCaseError("You can't hard delete a case that has shared forms with other cases!")

    interface.hard_delete_case_and_forms(case, forms)
示例#4
0
def create_case(case_id, files, patient_case_id=None):
    """
    Handle case submission for the sonosite endpoint
    """
    # we already parsed what we need from this, so can just remove it
    # without worrying we will need it later
    files.pop('PT_PPS.XML', '')

    xform = render_sonosite_xform(files, case_id, patient_case_id)

    file_dict = {}
    for f in files:
        file_dict[f] = UploadedFile(files[f], f)

    submit_form_locally(
        instance=xform,
        attachments=file_dict,
        domain=UTH_DOMAIN,
    )
    # this is a bit of a hack / abstraction violation
    # would be nice if submit_form_locally returned info about cases updated
    case_ids = {
        case_update.id
        for case_update in get_case_updates(convert_xform_to_json(xform))
    }
    return [CommCareCase.get(case_id) for case_id in case_ids]
示例#5
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        touched_cases = {}
        if len(xforms) > 1:
            domain = xforms[0].domain
            affected_cases = set()
            deprecated_form = None
            for xform in xforms:
                if xform.is_deprecated:
                    deprecated_form = xform
                affected_cases.update(case_update.id for case_update in get_case_updates(xform))

            rebuild_detail = FormEditRebuild(deprecated_form_id=deprecated_form.form_id)
            for case_id in affected_cases:
                case = case_db.get(case_id)
                is_creation = False
                if not case:
                    case = CommCareCaseSQL(domain=domain, case_id=case_id)
                    is_creation = True
                    case_db.set(case_id, case)
                previous_owner = case.owner_id
                case = FormProcessorSQL._rebuild_case_from_transactions(case, rebuild_detail, updated_xforms=xforms)
                if case:
                    touched_cases[case.case_id] = CaseUpdateMetadata(
                        case=case, is_creation=is_creation, previous_owner_id=previous_owner,
                    )
 def _fetch_case_ids_to_rebuild(self):
     case_ids_to_rebuild = set()
     for form in with_progress_bar(self.forms):
         form_case_ids = set(cu.id for cu in get_case_updates(form))
         if form_case_ids:
             case_ids_to_rebuild.update(form_case_ids)
     return list(case_ids_to_rebuild)
示例#7
0
def property_changed_in_action(case_transaction, case_id, case_property_name):
    from casexml.apps.case.xform import get_case_updates
    PropertyChangedInfo = namedtuple("PropertyChangedInfo",
                                     'transaction new_value modified_on')
    include_create_fields = case_property_name in [
        'owner_id', 'name', 'external_id'
    ]
    case_updates = get_case_updates(case_transaction.form)

    actions = []
    for update in case_updates:
        if update.id == case_id:
            actions.append((update.modified_on_str, update.get_update_action(),
                            case_transaction))
            if include_create_fields and case_transaction.is_case_create:
                actions.append((update.modified_on_str,
                                update.get_create_action(), case_transaction))

    for (modified_on, action, case_transaction) in actions:
        if action:
            property_changed = action.dynamic_properties.get(
                case_property_name)
            if include_create_fields:
                property_changed = getattr(action, case_property_name, None)

            if property_changed:
                return PropertyChangedInfo(case_transaction, property_changed,
                                           modified_on)

    return False
示例#8
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        touched_cases = {}
        if len(xforms) > 1:
            domain = xforms[0].domain
            affected_cases = set()
            deprecated_form = None
            for xform in xforms:
                if xform.is_deprecated:
                    deprecated_form = xform
                if not (xform.is_deprecated and xform.problem):
                    # don't process deprecatd forms which have errors.
                    # see http://manage.dimagi.com/default.asp?243382 for context.
                    # note that we have to use .problem instead of .is_error because applying
                    # the state=DEPRECATED overrides state=ERROR
                    affected_cases.update(case_update.id for case_update in get_case_updates(xform))

            rebuild_detail = FormEditRebuild(deprecated_form_id=deprecated_form.form_id)
            for case_id in affected_cases:
                case = case_db.get(case_id)
                is_creation = False
                if not case:
                    case = CommCareCaseSQL(domain=domain, case_id=case_id)
                    is_creation = True
                    case_db.set(case_id, case)
                previous_owner = case.owner_id
                case = FormProcessorSQL._rebuild_case_from_transactions(case, rebuild_detail, updated_xforms=xforms)
                if case:
                    touched_cases[case.case_id] = CaseUpdateMetadata(
                        case=case, is_creation=is_creation, previous_owner_id=previous_owner,
                    )
示例#9
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        # have to apply the deprecations before the updates
        sorted_forms = sorted(xforms,
                              key=lambda f: 0 if f.is_deprecated else 1)
        # don't process error forms which are being deprecated since they were never processed in the first place.
        # see http://manage.dimagi.com/default.asp?243382
        filtered_sorted_forms = [
            form for form in sorted_forms
            if not (form.is_deprecated and form.problem)
        ]
        touched_cases = {}
        for xform in filtered_sorted_forms:
            for case_update in get_case_updates(xform):
                case_update_meta = case_db.get_case_from_case_update(
                    case_update, xform)
                if case_update_meta.case:
                    touched_cases[
                        case_update_meta.case.case_id] = case_update_meta
                else:
                    logging.error(
                        "XForm %s had a case block that wasn't able to create a case! "
                        "This usually means it had a missing ID" %
                        xform.get_id)

        return touched_cases
示例#10
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        touched_cases = {}
        if len(xforms) > 1:
            domain = xforms[0].domain
            affected_cases = set()
            deprecated_form = None
            for xform in xforms:
                if xform.is_deprecated:
                    deprecated_form = xform
                if not (xform.is_deprecated and xform.problem):
                    # don't process deprecatd forms which have errors.
                    # see http://manage.dimagi.com/default.asp?243382 for context.
                    # note that we have to use .problem instead of .is_error because applying
                    # the state=DEPRECATED overrides state=ERROR
                    affected_cases.update(case_update.id for case_update in get_case_updates(xform))

            rebuild_detail = FormEditRebuild(deprecated_form_id=deprecated_form.form_id)
            for case_id in affected_cases:
                case = case_db.get(case_id)
                is_creation = False
                if not case:
                    case = CommCareCaseSQL(domain=domain, case_id=case_id)
                    is_creation = True
                    case_db.set(case_id, case)
                previous_owner = case.owner_id
                case, _ = FormProcessorSQL._rebuild_case_from_transactions(
                    case, rebuild_detail, updated_xforms=xforms
                )
                if case:
                    touched_cases[case.case_id] = CaseUpdateMetadata(
                        case=case, is_creation=is_creation, previous_owner_id=previous_owner,
                    )
        else:
            xform = xforms[0]
            for case_update in get_case_updates(xform):
                case_update_meta = case_db.get_case_from_case_update(case_update, xform)
                if case_update_meta.case:
                    touched_cases[case_update_meta.case.case_id] = case_update_meta
                else:
                    logging.error(
                        "XForm %s had a case block that wasn't able to create a case! "
                        "This usually means it had a missing ID" % xform.get_id
                    )

        return touched_cases
示例#11
0
def rebuild_case(case_id):
    """
    Given a case ID, rebuild the entire case state based on all existing forms
    referencing it. Useful when things go wrong or when you need to manually
    rebuild a case after archiving / deleting it
    """

    try:
        case = CommCareCase.get(case_id)
        found = True
    except ResourceNotFound:
        case = CommCareCase()
        case._id = case_id
        found = False

    # clear actions, xform_ids, close state, and all dynamic properties
    dynamic_properties = set([k for action in case.actions for k in action.updated_unknown_properties.keys()])
    for k in dynamic_properties:
        try:
            delattr(case, k)
        except KeyError:
            pass

    # already deleted means it was explicitly set to "deleted",
    # as opposed to getting set to that because it has no actions
    already_deleted = case.doc_type == 'CommCareCase-Deleted' and primary_actions(case)
    if not already_deleted:
        case.doc_type = 'CommCareCase'
    case.xform_ids = []
    case.actions = []
    case.closed = False
    case.closed_on = None
    case.closed_by = ''

    form_ids = get_case_xform_ids(case_id)
    forms = [fetch_and_wrap_form(id) for id in form_ids]
    filtered_forms = [f for f in forms if f.doc_type == "XFormInstance"]
    sorted_forms = sorted(filtered_forms, key=lambda f: f.received_on)
    for form in sorted_forms:
        if not found and case.domain is None:
            case.domain = form.domain
        assert form.domain == case.domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case.update_from_case_update(u, form)

    case.xform_ids = [f._id for f in sorted_forms]
    if not case.xform_ids:
        if not found:
            return None
        # there were no more forms. 'delete' the case
        case.doc_type = 'CommCareCase-Deleted'

    # add a "rebuild" action
    case.actions.append(_rebuild_action())
    case.save()
    return case
示例#12
0
    def handle(self, log_file, **options):
        to_archive = []
        cases_affected = set()
        episode_case_ids = CaseAccessors(domain).get_case_ids_in_domain(
            "episode")
        if options.get('limit'):
            episode_case_ids = episode_case_ids[:options.get('limit')]
        for episode_case_id in with_progress_bar(episode_case_ids):
            nikshay_to_archive = []
            dots_99_to_archvie = []
            case_forms = FormProcessorInterface(domain).get_case_forms(
                episode_case_id)
            for form in case_forms:
                if form.user_id in ("system", "", None
                                    ) and form.metadata.username == "system":
                    updates = get_case_updates(form)
                    update_actions = [
                        update.get_update_action() for update in updates
                        if update.id == episode_case_id
                    ]
                    for action in update_actions:
                        if isinstance(action, CaseUpdateAction):
                            if set(action.dynamic_properties.keys()) == {
                                    "nikshay_registered", "nikshay_error"
                            }:
                                nikshay_to_archive.append(form)
                                cases_affected.add(episode_case_id)
                            elif set(action.dynamic_properties.keys()) == {
                                    "dots_99_registered", "dots_99_error"
                            }:
                                cases_affected.add(episode_case_id)
                                dots_99_to_archvie.append(form)

            # get_case_updates() returns the forms in the correct order, but sorting is probably a good idea in case
            # get_case_updates ever changes.
            nikshay_to_archive.sort(key=lambda f: f.received_on)
            dots_99_to_archvie.sort(key=lambda f: f.received_on)
            nikshay_to_archive = nikshay_to_archive[:-1]
            dots_99_to_archvie = dots_99_to_archvie[:-1]

            to_archive.extend(nikshay_to_archive)
            to_archive.extend(dots_99_to_archvie)

        print("Will archive {} forms".format(len(to_archive)))

        xform_archived.disconnect(rebuild_form_cases)
        with open(log_file, "w") as f:
            for form in with_progress_bar(to_archive):
                f.write(form.form_id + "\n")
                f.flush()
                if options['commit']:
                    form.archive(user_id="remove_duplicate_forms_script")
        xform_archived.connect(rebuild_form_cases)

        print("Will rebuild {} cases".format(len(cases_affected)))
        for case_id in with_progress_bar(cases_affected):
            rebuild_case_from_forms(
                domain, case_id,
                UserRequestedRebuild(user_id="remove_duplicate_forms_script"))
示例#13
0
 def _property_changed_in_action(self, action, case_property):
     update_actions = [(update.modified_on_str, update.get_update_action())
                       for update in get_case_updates(action.form)]
     for (modified_on, action) in update_actions:
         property_changed = action.dynamic_properties.get(case_property)
         if property_changed:
             return PropertyChangedInfo(property_changed, modified_on)
     return False
示例#14
0
 def _apply_form_transaction(self, transaction):
     form = transaction.form
     if form:
         assert form.domain == self.case.domain
         case_updates = get_case_updates(form)
         filtered_updates = [u for u in case_updates if u.id == self.case.case_id]
         for case_update in filtered_updates:
             self._apply_case_update(case_update, form)
 def _get_result_recorded_form(test):
     """get last form that set result_recorded to yes"""
     for action in reversed(test.actions):
         for update in get_case_updates(action.form):
             if (update.id == test.case_id and update.get_update_action()
                     and update.get_update_action().dynamic_properties.get(
                         'result_recorded') == 'yes'):
                 return action.form.form_data
示例#16
0
def undo_form_edits(form_tuples, logger):
    cases_to_rebuild = defaultdict(set)
    ledgers_to_rebuild = defaultdict(set)
    operation_date = datetime.utcnow()
    for live_form, deprecated_form in form_tuples:
        # undo corehq.form_processor.parsers.form.apply_deprecation
        case_cache = CaseDbCacheSQL(live_form.domain,
                                    load_src="undo_form_edits")
        live_case_updates = get_case_updates(live_form)
        deprecated_case_updates = get_case_updates(deprecated_form)
        case_cache.populate(
            set(cu.id for cu in live_case_updates)
            | set(cu.id for cu in deprecated_case_updates))

        deprecated_form.form_id = new_id_in_same_dbalias(
            deprecated_form.form_id)
        deprecated_form.state = XFormInstanceSQL.NORMAL
        deprecated_form.orig_id = None
        deprecated_form.edited_on = None

        live_form.deprecated_form_id = None
        live_form.received_on = live_form.edited_on
        live_form.edited_on = None

        affected_cases, affected_ledgers = update_case_transactions_for_form(
            case_cache, live_case_updates, deprecated_case_updates, live_form,
            deprecated_form)

        for form in (live_form, deprecated_form):
            form.track_create(
                XFormOperationSQL(user_id='system',
                                  operation=XFormOperationSQL.UUID_DATA_FIX,
                                  date=operation_date))
            FormAccessorSQL.update_form(form)

        logger.log('Form edit undone: {}, {}({})'.format(
            live_form.form_id, deprecated_form.form_id,
            deprecated_form.original_form_id))
        cases_to_rebuild[live_form.domain].update(affected_cases)
        ledgers_to_rebuild[live_form.domain].update(affected_ledgers)
        logger.log('Cases to rebuild: {}'.format(','.join(affected_cases)))
        logger.log('Ledgers to rebuild: {}'.format(','.join(
            [l.as_id() for l in affected_ledgers])))

    return cases_to_rebuild, ledgers_to_rebuild
示例#17
0
    def _fetch_case_transaction_forms(self, transactions, updated_xforms=None):
        """
        Fetch the forms for a list of transactions, caching them on each transaction

        :param transactions: list of ``CaseTransaction`` objects:
        :param updated_xforms: optional list of forms that have been changed.
        """
        form_ids = {tx.form_id for tx in transactions if tx.form_id}
        updated_xforms_map = {
            xform.form_id: xform
            for xform in updated_xforms if not xform.is_deprecated
        } if updated_xforms else {}

        updated_xform_ids = set(updated_xforms_map)
        form_ids_to_fetch = list(form_ids - updated_xform_ids)
        form_load_counter("rebuild_case",
                          self.case.domain)(len(form_ids_to_fetch))
        xform_map = {
            form.form_id: form
            for form in XFormInstance.objects.get_forms_with_attachments_meta(
                form_ids_to_fetch)
        }

        forms_missing_transactions = list(updated_xform_ids - form_ids)
        for form_id in forms_missing_transactions:
            # Add in any transactions that aren't already present
            form = updated_xforms_map[form_id]
            case_updates = [
                update for update in get_case_updates(form)
                if update.id == self.case.case_id
            ]
            types = [
                CaseTransaction.type_from_action_type_slug(a.action_type_slug)
                for case_update in case_updates for a in case_update.actions
            ]
            modified_on = case_updates[0].guess_modified_on()
            new_transaction = CaseTransaction.form_transaction(
                self.case, form, modified_on, types)
            transactions.append(new_transaction)

        def get_form(form_id):
            if form_id in updated_xforms_map:
                return updated_xforms_map[form_id]

            try:
                return xform_map[form_id]
            except KeyError:
                raise XFormNotFound(form_id)

        for case_transaction in transactions:
            if case_transaction.form_id:
                try:
                    case_transaction.cached_form = get_form(
                        case_transaction.form_id)
                except XFormNotFound:
                    logging.error('Form not found during rebuild: %s',
                                  case_transaction.form_id)
示例#18
0
def _noauth_post(request, domain, app_id=None):
    """
    This is explictly called for a submission that has secure submissions enabled, but is manually
    overriding the submit URL to not specify auth context. It appears to be used by demo mode.

    It mainly just checks that we are touching test data only in the right domain and submitting
    as demo_user.
    """
    instance, _ = couchforms.get_instance_and_attachment(request)
    form_json = convert_xform_to_json(instance)
    case_updates = get_case_updates(form_json)

    def form_ok(form_json):
        try:
            # require new-style meta/userID (reject Meta/chw_id)
            if form_json['meta']['userID'] == 'demo_user':
                return True
        except (KeyError, ValueError):
            pass
        if is_device_report(form_json):
            return True
        return False

    def case_block_ok(case_updates):
        """
        Check for all cases that we are submitting as demo_user and that the domain we
        are submitting against for any previously existing cases matches the submission
        domain.
        """
        allowed_ids = ('demo_user', 'demo_user_group_id', None)
        case_ids = set()
        for case_update in case_updates:
            case_ids.add(case_update.id)
            create_action = case_update.get_create_action()
            update_action = case_update.get_update_action()
            index_action = case_update.get_index_action()
            if create_action:
                if create_action.user_id not in allowed_ids:
                    return False
                if create_action.owner_id not in allowed_ids:
                    return False
            if update_action:
                if update_action.owner_id not in allowed_ids:
                    return False
            if index_action:
                for index in index_action.indices:
                    case_ids.add(index.referenced_id)

        # todo: consider whether we want to remove this call, and/or pass the result
        # through to the next function so we don't have to get the cases again later
        cases = CommCareCase.bulk_get_lite(list(case_ids))
        for case in cases:
            if case.domain != domain:
                return False
            if case.owner_id or case.user_id not in allowed_ids:
                return False
示例#19
0
def undo_form_edits(form_tuples, logger):
    cases_to_rebuild = defaultdict(set)
    ledgers_to_rebuild = defaultdict(set)
    operation_date = datetime.utcnow()
    for live_form, deprecated_form in form_tuples:
        # undo corehq.form_processor.parsers.form.apply_deprecation
        case_cache = CaseDbCacheSQL(live_form.domain)
        live_case_updates = get_case_updates(live_form)
        deprecated_case_updates = get_case_updates(deprecated_form)
        case_cache.populate(
            set(cu.id for cu in live_case_updates) | set(cu.id for cu in deprecated_case_updates)
        )

        deprecated_form.form_id = new_id_in_same_dbalias(deprecated_form.form_id)
        deprecated_form.state = XFormInstanceSQL.NORMAL
        deprecated_form.orig_id = None
        deprecated_form.edited_on = None

        live_form.deprecated_form_id = None
        live_form.received_on = live_form.edited_on
        live_form.edited_on = None

        affected_cases, affected_ledgers = update_case_transactions_for_form(
            case_cache, live_case_updates, deprecated_case_updates, live_form, deprecated_form
        )

        for form in (live_form, deprecated_form):
            form.track_create(XFormOperationSQL(
                user_id='system',
                operation=XFormOperationSQL.UUID_DATA_FIX,
                date=operation_date)
            )
            FormAccessorSQL.update_form(form)

        logger.log('Form edit undone: {}, {}({})'.format(
            live_form.form_id, deprecated_form.form_id, deprecated_form.original_form_id
        ))
        cases_to_rebuild[live_form.domain].update(affected_cases)
        ledgers_to_rebuild[live_form.domain].update(affected_ledgers)
        logger.log('Cases to rebuild: {}'.format(','.join(affected_cases)))
        logger.log('Ledgers to rebuild: {}'.format(','.join([l.as_id() for l in affected_ledgers])))

    return cases_to_rebuild, ledgers_to_rebuild
示例#20
0
def _cases_referenced_by_xform(esxform):
    """Get a list of cases referenced by ESXFormInstance

    Note: this does not load cases referenced in stock transactions
    because ESXFormInstance does not have access to form XML, which
    is needed to find stock transactions.
    """
    assert esxform.domain, esxform.form_id
    case_ids = set(cu.id for cu in get_case_updates(esxform))
    return CaseAccessors(esxform.domain).get_cases(list(case_ids))
示例#21
0
def get_case_ids(form):
    """Get a set of case ids referenced in form

    Gracefully handles missing XML, but will omit case ids referenced in
    ledger updates if XML is missing.
    """
    try:
        return get_case_ids_from_form(form)
    except MissingFormXml:
        return {update.id for update in get_case_updates(form)}
 def _get_diagnosis_update(episode):
     """get first form that set diagnosis_test_type to a value """
     for action in episode.actions:
         if action.form is not None:
             for update in get_case_updates(action.form):
                 if (update.id == episode.case_id
                         and update.get_update_action() and
                         update.get_update_action().dynamic_properties.get(
                             'diagnosis_test_type', '')):
                     return update
示例#23
0
def person_hiv_status_changed(case):
    last_case_action = case.actions[-1]
    if last_case_action.is_case_create:
        return False

    last_update_actions = [update.get_update_action() for update in get_case_updates(last_case_action.form)]
    value_changed = any(
        action for action in last_update_actions
        if isinstance(action, CaseUpdateAction) and 'hiv_status' in action.dynamic_properties
    )
    return value_changed
示例#24
0
 def property_changed_in_action(action, case_property_name):
     update_actions = [(update.modified_on_str, update.get_update_action())
                       for update in get_case_updates(action.form)
                       if update.id == case.case_id]
     for (modified_on, action) in update_actions:
         if action:
             property_changed = action.dynamic_properties.get(
                 case_property_name)
             if property_changed:
                 return PropertyChangedInfo(property_changed, modified_on)
     return False
示例#25
0
def _noauth_post(request, domain, app_id=None):
    instance, _ = couchforms.get_instance_and_attachment(request)
    form_json = convert_xform_to_json(instance)
    case_updates = get_case_updates(form_json)

    def form_ok(form_json):
        try:
            # require new-style meta/userID (reject Meta/chw_id)
            if form_json['meta']['userID'] == 'demo_user':
                return True
        except (KeyError, ValueError):
            pass
        if is_device_report(form_json):
            return True
        return False

    def case_block_ok(case_updates):
        case_ids = set()
        for case_update in case_updates:
            case_ids.add(case_update.id)
            create_action = case_update.get_create_action()
            update_action = case_update.get_update_action()
            index_action = case_update.get_index_action()
            if create_action:
                if create_action.user_id not in ('demo_user', None):
                    return False
                if create_action.owner_id not in ('demo_user', None):
                    return False
            if update_action:
                if update_action.owner_id not in ('demo_user', None):
                    return False
            if index_action:
                for index in index_action.indices:
                    case_ids.add(index.referenced_id)
        cases = CommCareCase.bulk_get_lite(list(case_ids))
        for case in cases:
            if case.domain != domain:
                return False
            if case.owner_id or case.user_id != 'demo_user':
                return False
        return True

    if not (form_ok(form_json) and case_block_ok(case_updates)):
        return HttpResponseForbidden()

    return _process_form(
        request=request,
        domain=domain,
        app_id=app_id,
        user_id=None,
        authenticated=False,
        auth_cls=WaivedAuthContext,
    )
示例#26
0
def phone_number_changed(case):
    last_case_action = case.actions[-1]
    if last_case_action.is_case_create:
        return False

    update_actions = [update.get_update_action() for update in get_case_updates(last_case_action.form)]
    phone_number_changed = any(
        action for action in update_actions
        if 'phone_number' in action.dynamic_properties or
        'backup_number' in action.dynamic_properties
    )
    return phone_number_changed
示例#27
0
 def get_actions_for_form(self, xform):
     from casexml.apps.case.xform import get_case_updates
     updates = [u for u in get_case_updates(xform) if u.id == self.case_id]
     actions = [a for update in updates for a in update.actions]
     normalized_actions = [
         CaseAction(
             action_type=a.action_type_slug,
             updated_known_properties=a.get_known_properties(),
             indices=a.indices
         ) for a in actions
     ]
     return normalized_actions
示例#28
0
 def get_actions_for_form(self, xform):
     from casexml.apps.case.xform import get_case_updates
     updates = [u for u in get_case_updates(xform) if u.id == self.case_id]
     actions = [a for update in updates for a in update.actions]
     normalized_actions = [
         CaseAction(
             action_type=a.action_type_slug,
             updated_known_properties=a.get_known_properties(),
             indices=a.indices
         ) for a in actions
     ]
     return normalized_actions
示例#29
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        touched_cases = {}
        if len(xforms) > 1:
            domain = xforms[0].domain
            affected_cases = set()
            deprecated_form = None
            for xform in xforms:
                if xform.is_deprecated:
                    deprecated_form = xform
                affected_cases.update(case_update.id for case_update in get_case_updates(xform))

            rebuild_detail = FormEditRebuild(deprecated_form_id=deprecated_form.form_id)
            for case_id in affected_cases:
                case = case_db.get(case_id)
                is_creation = False
                if not case:
                    case = CommCareCaseSQL(domain=domain, case_id=case_id)
                    is_creation = True
                    case_db.set(case_id, case)
                previous_owner = case.owner_id
                case = FormProcessorSQL._rebuild_case_from_transactions(case, rebuild_detail, updated_xforms=xforms)
                if case:
                    touched_cases[case.case_id] = CaseUpdateMetadata(
                        case=case, is_creation=is_creation, previous_owner_id=previous_owner,
                    )
        else:
            xform = xforms[0]
            for case_update in get_case_updates(xform):
                case_update_meta = case_db.get_case_from_case_update(case_update, xform)
                if case_update_meta.case:
                    touched_cases[case_update_meta.case.case_id] = case_update_meta
                else:
                    logging.error(
                        "XForm %s had a case block that wasn't able to create a case! "
                        "This usually means it had a missing ID" % xform.get_id
                    )

        return touched_cases
示例#30
0
def _noauth_post(request, domain, app_id=None):
    """
    This is explicitly called for a submission that has secure submissions enabled, but is manually
    overriding the submit URL to not specify auth context. It appears to be used by demo mode.

    It mainly just checks that we are touching test data only in the right domain and submitting
    as demo_user.
    """
    try:
        instance, _ = couchforms.get_instance_and_attachment(request)
    except BadSubmissionRequest as e:
        return HttpResponseBadRequest(e.message)

    form_json = convert_xform_to_json(instance)
    case_updates = get_case_updates(form_json)

    def form_ok(form_json):
        return (from_demo_user(form_json) or is_device_report(form_json))

    def case_block_ok(case_updates):
        """
        Check for all cases that we are submitting as demo_user and that the domain we
        are submitting against for any previously existing cases matches the submission
        domain.
        """
        allowed_ids = ('demo_user', 'demo_user_group_id', None)
        case_ids = set()
        for case_update in case_updates:
            case_ids.add(case_update.id)
            create_action = case_update.get_create_action()
            update_action = case_update.get_update_action()
            index_action = case_update.get_index_action()
            if create_action:
                if create_action.user_id not in allowed_ids:
                    return False
                if create_action.owner_id not in allowed_ids:
                    return False
            if update_action:
                if update_action.owner_id not in allowed_ids:
                    return False
            if index_action:
                for index in index_action.indices:
                    case_ids.add(index.referenced_id)

        # todo: consider whether we want to remove this call, and/or pass the result
        # through to the next function so we don't have to get the cases again later
        cases = CommCareCase.objects.get_cases(list(case_ids), domain)
        for case in cases:
            if case.domain != domain:
                return False
            if case.owner_id or case.user_id not in allowed_ids:
                return False
示例#31
0
def _get_actions_from_forms(sorted_forms, case_id):
    case_actions = []
    domain = None
    for form in sorted_forms:
        if domain is None:
            domain = form.domain
        assert form.domain == domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case_actions.extend(u.get_case_actions(form))
    return case_actions, domain
示例#32
0
 def _apply_form_transaction(self, transaction):
     form = transaction.form
     if form:
         assert form.domain == self.case.domain
         case_updates = get_case_updates(form)
         filtered_updates = [u for u in case_updates if u.id == self.case.case_id]
         # TODO: stock
         # stock_actions = get_stock_actions(form)
         # case_actions.extend([intent.action
         #                      for intent in stock_actions.case_action_intents
         #                      if not intent.is_deprecation])
         for case_update in filtered_updates:
             self._apply_case_update(case_update, form)
示例#33
0
def _get_actions_from_forms(sorted_forms, case_id):
    case_actions = []
    domain = None
    for form in sorted_forms:
        if domain is None:
            domain = form.domain
        assert form.domain == domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case_actions.extend(u.get_case_actions(form))
    return case_actions, domain
示例#34
0
 def _get_owner_id_from_transaction(self, transaction):
     case_updates = get_case_updates(transaction.form)
     update_actions = [(update.modified_on_str, update.get_update_action())
                       for update in case_updates]
     create_actions = [(update.modified_on_str, update.get_create_action())
                       for update in case_updates]
     all_actions = update_actions + create_actions  # look through updates first, as these trump creates
     for modified_on, action in all_actions:
         if action:
             owner_id = action.get_known_properties().get('owner_id')
             if owner_id:
                 return PropertyChangedInfo(owner_id, modified_on)
     return None
示例#35
0
    def process_change(self, change):
        domain = change.metadata.domain
        if not CASE_DEDUPE.enabled(domain):
            return

        if is_dedupe_xmlns(change.get_document().get('xmlns')):
            return

        rules = self._get_rules(domain)
        if not rules:
            return

        for case_update in get_case_updates(change.get_document()):
            self._process_case_update(domain, case_update)
示例#36
0
def rebuild_case(case_id):
    """
    Given a case ID, rebuild the entire case state based on all existing forms
    referencing it. Useful when things go wrong or when you need to manually
    rebuild a case after archiving / deleting it
    """

    try:
        case = CommCareCase.get(case_id)
        found = True
    except ResourceNotFound:
        case = CommCareCase()
        case._id = case_id
        found = False

    reset_state(case)
    # in addition to resetting the state, also manually clear xform_ids and actions
    # since we're going to rebuild these from the forms
    case.xform_ids = []
    case.actions = []

    forms = get_case_forms(case_id)
    filtered_forms = [f for f in forms if f.doc_type == "XFormInstance"]
    sorted_forms = sorted(filtered_forms, key=lambda f: f.received_on)
    for form in sorted_forms:
        if not found and case.domain is None:
            case.domain = form.domain
        assert form.domain == case.domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case.actions.extend(u.get_case_actions(form))

    # call "rebuild" on the case, which should populate xform_ids
    # and re-sort actions if necessary
    case.rebuild(strict=False, xforms={f._id: f for f in sorted_forms})
    case.xform_ids = case.xform_ids + [f._id for f in sorted_forms if f._id not in case.xform_ids]

    # todo: should this move to case.rebuild?
    if not case.xform_ids:
        if not found:
            return None
        # there were no more forms. 'delete' the case
        case.doc_type = 'CommCareCase-Deleted'

    # add a "rebuild" action
    case.actions.append(_rebuild_action())
    case.save()
    return case
示例#37
0
def raise_events(xform, cases):
    supply_points = [SupplyPointCase.wrap(c._doc) for c in cases if c.type == const.SUPPLY_POINT_CASE_TYPE]
    case_updates = get_case_updates(xform)
    for sp in supply_points:
        created = any(filter(lambda update: update.id == sp._id and update.creates_case(), case_updates))
        supply_point_modified.send(sender=None, supply_point=sp, created=created)
    requisition_cases = [RequisitionCase.wrap(c._doc) for c in cases if c.type == const.REQUISITION_CASE_TYPE]
    if requisition_cases and requisition_cases[0].requisition_status == RequisitionStatus.APPROVED:
        requisition_approved.send(sender=None, requisitions=requisition_cases)
    if requisition_cases and requisition_cases[0].requisition_status == RequisitionStatus.RECEIVED:
        requisition_receipt.send(sender=None, requisitions=requisition_cases)

    if requisition_cases and requisition_cases[0].requisition_status == RequisitionStatus.REQUESTED:
        requisition_modified.send(sender=None, cases=requisition_cases)
示例#38
0
def related_dates_changed(case):
    last_case_action = case.actions[-1]
    if last_case_action.is_case_create:
        return False

    last_update_actions = [
        update.get_update_action()
        for update in get_case_updates(last_case_action.form)
    ]
    value_changed = any(action for action in last_update_actions
                        if isinstance(action, CaseUpdateAction) and (
                            'art_initiation_date' in action.dynamic_properties
                            or 'cpt_1_date' in action.dynamic_properties))
    return value_changed
示例#39
0
def raise_supply_point_events(xform, cases):
    supply_points = [
        SupplyPointCase.wrap(c._doc) for c in cases
        if c.type == SUPPLY_POINT_CASE_TYPE
    ]
    case_updates = get_case_updates(xform)
    for sp in supply_points:
        created = any(
            filter(
                lambda update: update.id == sp._id and update.creates_case(),
                case_updates))
        supply_point_modified.send(sender=None,
                                   supply_point=sp,
                                   created=created)
示例#40
0
def _get_actions_from_forms(domain, sorted_forms, case_id):
    from corehq.form_processor.parsers.ledgers import get_stock_actions
    case_actions = []
    for form in sorted_forms:
        assert form.domain == domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case_actions.extend(u.get_case_actions(form))
        stock_actions = get_stock_actions(form)
        case_actions.extend([intent.get_couch_action()
                             for intent in stock_actions.case_action_intents
                             if not intent.is_deprecation])
    return case_actions
示例#41
0
def _get_actions_from_forms(domain, sorted_forms, case_id):
    from corehq.form_processor.parsers.ledgers import get_stock_actions
    case_actions = []
    for form in sorted_forms:
        assert form.domain == domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case_actions.extend(u.get_case_actions(form))
        stock_actions = get_stock_actions(form)
        case_actions.extend([intent.get_couch_action()
                             for intent in stock_actions.case_action_intents
                             if not intent.is_deprecation])
    return case_actions
示例#42
0
 def _get_case_stock_result(self, sql_form, couch_form):
     case_stock_result = None
     if sql_form.initial_processing_complete:
         case_stock_result = _get_case_and_ledger_updates(
             self.domain, sql_form)
         if case_stock_result.case_models:
             has_noop_update = any(
                 len(update.actions) == 1
                 and isinstance(update.actions[0], CaseNoopAction)
                 for update in get_case_updates(couch_form))
             if has_noop_update:
                 # record these for later use when filtering case diffs.
                 # See ``_filter_forms_touch_case``
                 self.statedb.add_no_action_case_form(couch_form.form_id)
     return case_stock_result
示例#43
0
def episode_pending_registration_changed(case):
    last_case_action = case.actions[-1]
    if last_case_action.is_case_create:
        return False

    last_update_actions = [
        update.get_update_action()
        for update in get_case_updates(last_case_action.form)
    ]
    value_changed = any(
        action for action in last_update_actions
        if isinstance(action, CaseUpdateAction)
        and 'episode_pending_registration' in action.dynamic_properties
        and action.dynamic_properties['episode_pending_registration'] == 'no')
    return value_changed
示例#44
0
def prepare_planning_db(domain):
    db_filepath = get_planning_db_filepath(domain)
    planning_db = PlanningDB.init(db_filepath)
    xform_ids = get_form_ids_by_type(domain, 'XFormInstance')
    xform_db = XFormInstance.get_db()

    for i, xform in enumerate(iter_docs(xform_db, xform_ids)):
        xform_id = xform['_id']
        case_actions_by_case_id = collections.defaultdict(list)
        try:
            xml = _get_submission_xml(xform, xform_db)
        except ResourceNotFound:
            continue
        new_form_json = _get_new_form_json(xml, xform_id)

        case_updates = get_case_updates(new_form_json)
        xform_copy = deepcopy(xform)
        xform_copy['form'] = new_form_json
        xformdoc = XFormInstance.wrap(xform_copy)
        xformdoc_json = xformdoc.to_json()

        planning_db.add_form(xform_id, xformdoc_json)
        planning_db.add_diffs('form', xform_id,
                              json_diff(xform, xformdoc_json))

        case_actions = [
            (case_update.id, action.xform_id, action.to_json())
            for case_update in case_updates
            for action in case_update.get_case_actions(xformdoc)
        ]

        stock_report_helpers, stock_case_actions = get_stock_actions(xformdoc)
        case_actions.extend(stock_case_actions)

        for case_id, xform_id, case_action in case_actions:
            case_actions_by_case_id[case_id].append((xform_id, case_action))

        for case_id, case_actions in case_actions_by_case_id.items():
            planning_db.ensure_case(case_id)
            planning_db.add_case_actions(case_id, case_actions)
        planning_db.add_stock_report_helpers([
            stock_report_helper.to_json()
            for stock_report_helper in stock_report_helpers
        ])
    return prepare_case_json(planning_db)
示例#45
0
def _get_actions_from_forms(sorted_forms, case_id):
    from corehq.apps.commtrack.processing import get_stock_actions
    case_actions = []
    domain = None
    for form in sorted_forms:
        if domain is None:
            domain = form.domain
        assert form.domain == domain

        case_updates = get_case_updates(form)
        filtered_updates = [u for u in case_updates if u.id == case_id]
        for u in filtered_updates:
            case_actions.extend(u.get_case_actions(form))
        stock_actions = get_stock_actions(form)
        case_actions.extend([intent.action
                             for intent in stock_actions.case_action_intents
                             if not intent.is_deprecation])
    return case_actions, domain
示例#46
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        # have to apply the deprecations before the updates
        sorted_forms = sorted(xforms, key=lambda f: 0 if f.is_deprecated else 1)
        touched_cases = {}
        for xform in sorted_forms:
            for case_update in get_case_updates(xform):
                case_update_meta = case_db.get_case_from_case_update(case_update, xform)
                if case_update_meta.case:
                    touched_cases[case_update_meta.case.case_id] = case_update_meta
                else:
                    logging.error(
                        "XForm %s had a case block that wasn't able to create a case! "
                        "This usually means it had a missing ID" % xform.get_id
                    )

        return touched_cases
示例#47
0
def _reopen_or_create_supply_point(location):
    from .helpers import update_supply_point_from_location
    from .dbaccessors import get_supply_point_by_location_id
    supply_point = get_supply_point_by_location_id(location.domain, location.location_id)
    if supply_point:
        if supply_point and supply_point.closed:
            form_ids = CaseAccessors(supply_point.domain).get_case_xform_ids(supply_point.case_id)
            form_accessor = FormAccessors(supply_point.domain)
            for form_id in form_ids:
                form = form_accessor.get_form(form_id)
                closes_case = any(map(
                    lambda case_update: case_update.closes_case(),
                    get_case_updates(form),
                ))
                if closes_case:
                    form.archive(user_id=const.COMMTRACK_USERNAME)
        update_supply_point_from_location(supply_point, location)
        return supply_point
    else:
        return SupplyInterface.create_from_location(location.domain, location)
示例#48
0
def safe_hard_delete(case):
    """
    Hard delete a case - by deleting the case itself as well as all forms associated with it
    permanently from the database.

    Will fail hard if the case has any reverse indices or if any of the forms associated with
    the case also touch other cases.

    This is used primarily for cleaning up system cases/actions (e.g. the location delegate case).
    """
    if case.reverse_indices:
        raise CommCareCaseError("You can't hard delete a case that has other dependencies ({})!".format(case._id))
    forms = get_case_forms(case._id)
    for form in forms:
        case_updates = get_case_updates(form)
        if any([c.id != case._id for c in case_updates]):
            raise CommCareCaseError("You can't hard delete a case that has shared forms with other cases!")

    docs = [case._doc] + [f._doc for f in forms]
    case.get_db().bulk_delete(docs)
示例#49
0
    def _migrate_form_and_associated_models(self, couch_form):
        sql_form = _migrate_form(self.domain, couch_form)
        _migrate_form_attachments(sql_form, couch_form)
        _migrate_form_operations(sql_form, couch_form)

        self._save_diffs(couch_form, sql_form)

        case_stock_result = None
        if sql_form.initial_processing_complete:
            case_stock_result = _get_case_and_ledger_updates(self.domain, sql_form)
            if len(case_stock_result.case_models):
                touch_updates = [
                    update for update in get_case_updates(couch_form)
                    if len(update.actions) == 1 and isinstance(update.actions[0], CaseNoopAction)
                ]
                if len(touch_updates):
                    # record these for later use when filtering case diffs. See ``_filter_forms_touch_case``
                    self.forms_that_touch_cases_without_actions.add(couch_form.form_id)

        _save_migrated_models(sql_form, case_stock_result)
示例#50
0
    def get_cases_from_forms(case_db, xforms):
        """Get all cases affected by the forms. Includes new cases, updated cases.
        """
        # have to apply the deprecations before the updates
        sorted_forms = sorted(xforms, key=lambda f: 0 if f.is_deprecated else 1)
        # don't process error forms which are being deprecated since they were never processed in the first place.
        # see http://manage.dimagi.com/default.asp?243382
        filtered_sorted_forms = [form for form in sorted_forms if not (form.is_deprecated and form.problem)]
        touched_cases = {}
        for xform in filtered_sorted_forms:
            for case_update in get_case_updates(xform):
                case_update_meta = case_db.get_case_from_case_update(case_update, xform)
                if case_update_meta.case:
                    touched_cases[case_update_meta.case.case_id] = case_update_meta
                else:
                    logging.error(
                        "XForm %s had a case block that wasn't able to create a case! "
                        "This usually means it had a missing ID" % xform.get_id
                    )

        return touched_cases
示例#51
0
 def _check_update_matches(self, case, expected_update):
     last_form = FormAccessors(TEST_DOMAIN).get_form(case.xform_ids[-1])
     case_update = get_case_updates(last_form)[0]
     self.assertDictEqual(case_update.update_block, expected_update)
示例#52
0
def _noauth_post(request, domain, app_id=None):
    """
    This is explictly called for a submission that has secure submissions enabled, but is manually
    overriding the submit URL to not specify auth context. It appears to be used by demo mode.

    It mainly just checks that we are touching test data only in the right domain and submitting
    as demo_user.
    """
    instance, _ = couchforms.get_instance_and_attachment(request)
    form_json = convert_xform_to_json(instance)
    case_updates = get_case_updates(form_json)

    def form_ok(form_json):
        try:
            # require new-style meta/userID (reject Meta/chw_id)
            if form_json['meta']['userID'] == 'demo_user':
                return True
        except (KeyError, ValueError):
            pass
        if is_device_report(form_json):
            return True
        return False

    def case_block_ok(case_updates):
        """
        Check for all cases that we are submitting as demo_user and that the domain we
        are submitting against for any previously existing cases matches the submission
        domain.
        """
        allowed_ids = ('demo_user', 'demo_user_group_id', None)
        case_ids = set()
        for case_update in case_updates:
            case_ids.add(case_update.id)
            create_action = case_update.get_create_action()
            update_action = case_update.get_update_action()
            index_action = case_update.get_index_action()
            if create_action:
                if create_action.user_id not in allowed_ids:
                    return False
                if create_action.owner_id not in allowed_ids:
                    return False
            if update_action:
                if update_action.owner_id not in allowed_ids:
                    return False
            if index_action:
                for index in index_action.indices:
                    case_ids.add(index.referenced_id)

        # todo: consider whether we want to remove this call, and/or pass the result
        # through to the next function so we don't have to get the cases again later
        cases = CommCareCase.bulk_get_lite(list(case_ids))
        for case in cases:
            if case.domain != domain:
                return False
            if case.owner_id or case.user_id not in allowed_ids:
                return False
        return True

    if not (form_ok(form_json) and case_block_ok(case_updates)):
        return HttpResponseForbidden()

    return _process_form(
        request=request,
        domain=domain,
        app_id=app_id,
        user_id=None,
        authenticated=False,
        auth_cls=WaivedAuthContext,
    )
示例#53
0
def raise_supply_point_events(xform, cases):
    supply_points = [SupplyPointCase.wrap(c._doc) for c in cases if c.type == const.SUPPLY_POINT_CASE_TYPE]
    case_updates = get_case_updates(xform)
    for sp in supply_points:
        created = any(filter(lambda update: update.id == sp._id and update.creates_case(), case_updates))
        supply_point_modified.send(sender=None, supply_point=sp, created=created)
示例#54
0
def _noauth_post(request, domain, app_id=None):
    """
    This is explictly called for a submission that has secure submissions enabled, but is manually
    overriding the submit URL to not specify auth context. It appears to be used by demo mode.

    It mainly just checks that we are touching test data only in the right domain and submitting
    as demo_user.
    """
    instance, _ = couchforms.get_instance_and_attachment(request)
    form_json = convert_xform_to_json(instance)
    case_updates = get_case_updates(form_json)

    def form_ok(form_json):
        return (from_demo_user(form_json) or is_device_report(form_json))

    def case_block_ok(case_updates):
        """
        Check for all cases that we are submitting as demo_user and that the domain we
        are submitting against for any previously existing cases matches the submission
        domain.
        """
        allowed_ids = ('demo_user', 'demo_user_group_id', None)
        case_ids = set()
        for case_update in case_updates:
            case_ids.add(case_update.id)
            create_action = case_update.get_create_action()
            update_action = case_update.get_update_action()
            index_action = case_update.get_index_action()
            if create_action:
                if create_action.user_id not in allowed_ids:
                    return False
                if create_action.owner_id not in allowed_ids:
                    return False
            if update_action:
                if update_action.owner_id not in allowed_ids:
                    return False
            if index_action:
                for index in index_action.indices:
                    case_ids.add(index.referenced_id)

        # todo: consider whether we want to remove this call, and/or pass the result
        # through to the next function so we don't have to get the cases again later
        cases = CaseAccessors(domain).get_cases(list(case_ids))
        for case in cases:
            if case.domain != domain:
                return False
            if case.owner_id or case.user_id not in allowed_ids:
                return False
        return True

    if not (form_ok(form_json) and case_block_ok(case_updates)):
        if request.GET.get('submit_mode') != DEMO_SUBMIT_MODE:
            # invalid submissions under demo mode submission can be processed
            return HttpResponseForbidden()

    return _process_form(
        request=request,
        domain=domain,
        app_id=app_id,
        user_id=None,
        authenticated=False,
        auth_cls=WaivedAuthContext,
    )