def _get_or_update_cases(xforms, case_db): """ Given an xform document, update any case blocks found within it, returning a dictionary mapping the case ids affected to the couch case document objects """ domain = getattr(case_db, 'domain', None) touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms) _validate_indices(case_db, touched_cases.values()) return CaseProcessingResult( domain, [update.case for update in touched_cases.values()], )
def _get_case_and_ledger_updates(domain, sql_form): """ Get a CaseStockProcessingResult with the appropriate cases and ledgers to be saved. See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent section of the form-processing code. """ from corehq.apps.commtrack.processing import process_stock interface = FormProcessorInterface(domain) assert sql_form.domain xforms = [sql_form] with interface.casedb_cache( domain=domain, lock=False, deleted_ok=True, xforms=xforms, load_src="couchsqlmigration", ) as case_db: touched_cases = FormProcessorInterface(domain).get_cases_from_forms( case_db, xforms) extensions_to_close = get_all_extensions_to_close( domain, list(touched_cases.values())) case_result = CaseProcessingResult( domain, [update.case for update in touched_cases.values()], [], # ignore dirtiness_flags, extensions_to_close) for case in case_result.cases: case_db.post_process_case(case, sql_form) case_db.mark_changed(case) cases = case_result.cases try: stock_result = process_stock(xforms, case_db) cases = case_db.get_cases_for_saving(sql_form.received_on) stock_result.populate_models() except MissingFormXml: stock_result = None return CaseStockProcessingResult( case_result=case_result, case_models=cases, stock_result=stock_result, )
def _get_or_update_cases(xforms, case_db): """ Given an xform document, update any case blocks found within it, returning a dictionary mapping the case ids affected to the couch case document objects """ domain = getattr(case_db, 'domain', None) touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms) _validate_indices(case_db, [case_update_meta.case for case_update_meta in touched_cases.values()]) dirtiness_flags = _get_all_dirtiness_flags_from_cases(case_db, touched_cases) extensions_to_close = get_all_extensions_to_close(domain, touched_cases.values()) return CaseProcessingResult( domain, [update.case for update in touched_cases.values()], dirtiness_flags, extensions_to_close )
def _get_or_update_cases(xforms, case_db): """ Given an xform document, update any case blocks found within it, returning a dictionary mapping the case ids affected to the couch case document objects """ domain = getattr(case_db, 'domain', None) touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms) _validate_indices(case_db, [case_update_meta.case for case_update_meta in touched_cases.values()]) dirtiness_flags = _get_all_dirtiness_flags_from_cases(case_db, touched_cases) extensions_to_close = get_all_extensions_to_close(domain, list(touched_cases.values())) return CaseProcessingResult( domain, [update.case for update in touched_cases.values()], dirtiness_flags, extensions_to_close )
def _get_case_and_ledger_updates(domain, sql_form): """ Get a CaseStockProcessingResult with the appropriate cases and ledgers to be saved. See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent section of the form-processing code. """ from casexml.apps.case.xform import get_and_check_xform_domain from corehq.apps.commtrack.processing import process_stock interface = FormProcessorInterface(domain) get_and_check_xform_domain(sql_form) xforms = [sql_form] # todo: I think this can be changed to lock=False with interface.casedb_cache(domain=domain, lock=True, deleted_ok=True, xforms=xforms) as case_db: touched_cases = FormProcessorInterface(domain).get_cases_from_forms( case_db, xforms) extensions_to_close = get_all_extensions_to_close( domain, touched_cases.values()) case_result = CaseProcessingResult( domain, [update.case for update in touched_cases.values()], [], # ignore dirtiness_flags, extensions_to_close) # todo: is this necessary? for case in case_result.cases: case_db.mark_changed(case) stock_result = process_stock(xforms, case_db) cases = case_db.get_cases_for_saving(sql_form.received_on) stock_result.populate_models() return CaseStockProcessingResult( case_result=case_result, case_models=cases, stock_result=stock_result, )
def _get_case_and_ledger_updates(domain, sql_form): """ Get a CaseStockProcessingResult with the appropriate cases and ledgers to be saved. See SubmissionPost.process_xforms_for_cases and methods it calls for the equivalent section of the form-processing code. """ from corehq.apps.commtrack.processing import process_stock interface = FormProcessorInterface(domain) assert sql_form.domain xforms = [sql_form] with interface.casedb_cache( domain=domain, lock=False, deleted_ok=True, xforms=xforms, load_src="couchsqlmigration", ) as case_db: touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms) extensions_to_close = get_all_extensions_to_close(domain, list(touched_cases.values())) case_result = CaseProcessingResult( domain, [update.case for update in touched_cases.values()], [], # ignore dirtiness_flags, extensions_to_close ) for case in case_result.cases: case_db.post_process_case(case, sql_form) case_db.mark_changed(case) stock_result = process_stock(xforms, case_db) cases = case_db.get_cases_for_saving(sql_form.received_on) stock_result.populate_models() return CaseStockProcessingResult( case_result=case_result, case_models=cases, stock_result=stock_result, )
def _get_or_update_cases(xforms, case_db): """ Given an xform document, update any case blocks found within it, returning a dictionary mapping the case ids affected to the couch case document objects """ domain = getattr(case_db, 'domain', None) touched_cases = FormProcessorInterface(domain).get_cases_from_forms(case_db, xforms) # once we've gotten through everything, validate all indices # and check for new dirtiness flags def _validate_indices(case): if case.indices: for index in case.indices: # call get and not doc_exists to force domain checking # see CaseDbCache._validate_case referenced_case = case_db.get(index.referenced_id) if not referenced_case: # just log, don't raise an error or modify the index logging.error( "Case '%s' references non-existent case '%s'", case.case_id, index.referenced_id, ) def _get_dirtiness_flags_for_outgoing_indices(case, tree_owners=None): """ if the outgoing indices touch cases owned by another user this cases owner is dirty """ if tree_owners is None: tree_owners = set() extension_indices = [index for index in case.indices if index.relationship == CASE_INDEX_EXTENSION] unowned_host_cases = [] for index in extension_indices: host_case = case_db.get(index.referenced_id) if ( host_case and host_case.owner_id == UNOWNED_EXTENSION_OWNER_ID and host_case not in unowned_host_cases ): unowned_host_cases.append(host_case) owner_ids = {case_db.get(index.referenced_id).owner_id for index in case.indices if case_db.get(index.referenced_id)} | tree_owners potential_clean_owner_ids = owner_ids | set([UNOWNED_EXTENSION_OWNER_ID]) more_than_one_owner_touched = len(owner_ids) > 1 touches_different_owner = len(owner_ids) == 1 and case.owner_id not in potential_clean_owner_ids if (more_than_one_owner_touched or touches_different_owner): yield DirtinessFlag(case.case_id, case.owner_id) if extension_indices: # If this case is an extension, each of the touched cases is also dirty for index in case.indices: referenced_case = case_db.get(index.referenced_id) yield DirtinessFlag(referenced_case.case_id, referenced_case.owner_id) if case.owner_id != UNOWNED_EXTENSION_OWNER_ID: tree_owners.add(case.owner_id) for unowned_host_case in unowned_host_cases: # A host case of this extension is unowned, which means it could potentially touch an owned case # Check these unowned cases' outgoing indices and mark dirty if appropriate for dirtiness_flag in _get_dirtiness_flags_for_outgoing_indices(unowned_host_case, tree_owners=tree_owners): yield dirtiness_flag def _get_dirtiness_flags_for_child_cases(cases): child_cases = case_db.get_reverse_indexed_cases([c.case_id for c in cases]) case_owner_map = dict((case.case_id, case.owner_id) for case in cases) for child_case in child_cases: for index in child_case.indices: if (index.referenced_id in case_owner_map and child_case.owner_id != case_owner_map[index.referenced_id]): yield DirtinessFlag(child_case.case_id, child_case.owner_id) def _get_dirtiness_flags_for_reassigned_case(case_metas): # for reassigned cases, we mark them temporarily dirty to allow phones to sync # the latest changes. these will get cleaned up when the weekly rebuild triggers for case_update_meta in case_metas: if _is_change_of_ownership(case_update_meta.previous_owner_id, case_update_meta.case.owner_id): yield DirtinessFlag(case_update_meta.case.case_id, case_update_meta.previous_owner_id) dirtiness_flags = [] extensions_to_close = set() # process the temporary dirtiness flags first so that any hints for real dirtiness get overridden dirtiness_flags += list(_get_dirtiness_flags_for_reassigned_case(touched_cases.values())) for case_update_meta in touched_cases.values(): _validate_indices(case_update_meta.case) extensions_to_close = extensions_to_close | get_extensions_to_close(case_update_meta.case, domain) dirtiness_flags += list(_get_dirtiness_flags_for_outgoing_indices(case_update_meta.case)) dirtiness_flags += list(_get_dirtiness_flags_for_child_cases([meta.case for meta in touched_cases.values()])) return CaseProcessingResult( domain, [update.case for update in touched_cases.values()], dirtiness_flags, extensions_to_close )