def hard_rebuild_case(domain, case_id, detail): try: case = CommCareCase.get(case_id) assert case.domain == domain found = True except CaseNotFound: case = CommCareCase() case.case_id = case_id case.domain = domain found = False forms = FormProcessorCouch.get_case_forms(case_id) filtered_forms = [f for f in forms if f.is_normal] sorted_forms = sorted(filtered_forms, key=lambda f: f.received_on) actions = _get_actions_from_forms(domain, sorted_forms, case_id) if not found and case.domain is None: case.domain = domain rebuild_case_from_actions(case, actions) # 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
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
def hard_rebuild_case(domain, case_id, detail, save=True, lock=True): if lock: # only record metric if locking since otherwise it has been # (most likley) recorded elsewhere case_load_counter("rebuild_case", domain)() case, lock_obj = FormProcessorCouch.get_case_with_lock(case_id, lock=lock, wrap=True) found = bool(case) if not found: case = CommCareCase() case.case_id = case_id case.domain = domain if lock: lock_obj = CommCareCase.get_obj_lock_by_id(case_id) acquire_lock(lock_obj, degrade_gracefully=False) try: assert case.domain == domain, (case.domain, domain) forms = FormProcessorCouch.get_case_forms(case_id) form_load_counter("rebuild_case", domain)(len(forms)) filtered_forms = [f for f in forms if f.is_normal] sorted_forms = sorted(filtered_forms, key=lambda f: f.received_on) actions = _get_actions_from_forms(domain, sorted_forms, case_id) if not found and case.domain is None: case.domain = domain rebuild_case_from_actions(case, actions) # 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()) if save: case.save() return case finally: release_lock(lock_obj, degrade_gracefully=True)
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
def rebuild_case_from_forms(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 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) actions, domain = _get_actions_from_forms(sorted_forms, case_id) if not found and case.domain is None: case.domain = domain rebuild_case_from_actions(case, actions) # 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