def deduplicate_xform(cls, xform): # follow standard dupe handling, which simply saves a copy of the form # but a new doc_id, and a doc_type of XFormDuplicate xform.doc_type = XFormDuplicate.__name__ dupe = XFormDuplicate.wrap(xform.to_json()) dupe.problem = "Form is a duplicate of another! (%s)" % xform._id return cls.assign_new_id(dupe)
def swap_doc_types(self, log_file, bad_xform_id, duplicate_xform_id, domain, dry_run): bad_xform = XFormInstance.get(bad_xform_id) # confirm that the doc hasn't already been fixed: bad_xform_problem = None try: bad_xform_problem = bad_xform.problem or "" except AttributeError: pass if bad_xform_problem: if re.match(PROBLEM_TEMPLATE_START, bad_xform_problem): self.log_already_fixed(log_file, bad_xform_id, domain) return duplicate_xform = XFormInstance.get(duplicate_xform_id) now = datetime.now().isoformat() # Convert the XFormInstance to an XFormDuplicate bad_xform.doc_type = XFormDuplicate.__name__ bad_xform.problem = BAD_FORM_PROBLEM_TEMPLATE.format(duplicate_xform_id, now) bad_xform = XFormDuplicate.wrap(bad_xform.to_json()) # Convert the XFormDuplicate to an XFormInstance duplicate_xform.problem = FIXED_FORM_PROBLEM_TEMPLATE.format( id_=bad_xform_id, datetime_=now ) duplicate_xform.doc_type = XFormInstance.__name__ duplicate_xform = XFormInstance.wrap(duplicate_xform.to_json()) self.log_swap(log_file, bad_xform_id, domain, duplicate_xform_id, dry_run) if not dry_run: duplicate_xform.save() bad_xform.save()
def deduplicate_xform(cls, xform): # follow standard dupe handling, which simply saves a copy of the form # but a new doc_id, and a doc_type of XFormDuplicate xform.doc_type = XFormDuplicate.__name__ dupe = XFormDuplicate.wrap(xform.to_json()) assert not xform.persistent_blobs, "some blobs would be lost" if xform._deferred_blobs: dupe._deferred_blobs = xform._deferred_blobs.copy() dupe.problem = "Form is a duplicate of another! (%s)" % xform._id return cls.assign_new_id(dupe)
def _handle_id_conflict(instance, attachments): """ For id conflicts, we check if the files contain exactly the same content, If they do, we just log this as a dupe. If they don't, we deprecate the previous form and overwrite it with the new form's contents. """ def _extract_id_from_raw_xml(xml): # this is the standard openrosa way of doing things parsed = etree.XML(xml) meta_ns = "http://openrosa.org/jr/xforms" val = parsed.find("{%(ns)s}meta/{%(ns)s}instanceID" % \ {"ns": meta_ns}) if val is not None and val.text: return val.text # if we get here search more creatively for some of the older # formats _PATTERNS = (r"<instanceID>([\w-]+)</instanceID>", r"<uid>([\w-]+)</uid>", r"<uuid>([\w-]+)</uuid>") for pattern in _PATTERNS: if re.search(pattern, xml): return re.search(pattern, xml).groups()[0] logging.error("Unable to find conflicting matched uid in form: %s" % xml) return "" conflict_id = _extract_id_from_raw_xml(instance) # get old document existing_doc = XFormInstance.get(conflict_id) # compare md5s existing_md5 = existing_doc.xml_md5() new_md5 = hashlib.md5(instance).hexdigest() # if not same: # Deprecate old form (including changing ID) # to deprecate, copy new instance into a XFormDeprecated if existing_md5 != new_md5: doc_copy = XFormInstance.get_db().copy_doc(conflict_id) # get the doc back to avoid any potential bigcouch race conditions. # r=3 implied by class xfd = XFormDeprecated.get(doc_copy['id']) xfd.orig_id = conflict_id xfd.doc_type=XFormDeprecated.__name__ xfd.save() # after that delete the original document and resubmit. XFormInstance.get_db().delete_doc(conflict_id) return post_xform_to_couch(instance, attachments=attachments) else: # follow standard dupe handling new_doc_id = uid.new() response, errors = post_from_settings(instance, {"uid": new_doc_id}) if not _has_errors(response, errors): # create duplicate doc # get and save the duplicate to ensure the doc types are set correctly # so that it doesn't show up in our reports dupe = XFormDuplicate.get(response) dupe.problem = "Form is a duplicate of another! (%s)" % conflict_id dupe.save() return dupe else: # how badly do we care about this? raise CouchFormException("Problem POSTing form to couch! errors/response: %s/%s" % (errors, response))
xfd.doc_type = XFormDeprecated.__name__ xfd.save() # after that delete the original document and resubmit. XFormInstance.get_db().delete_doc(conflict_id) return post_xform_to_couch(instance, attachments=attachments) else: # follow standard dupe handling new_doc_id = uid.new() response, errors = post_from_settings(instance, {"uid": new_doc_id}) if not _has_errors(response, errors): # create duplicate doc # get and save the duplicate to ensure the doc types are set correctly # so that it doesn't show up in our reports dupe = XFormDuplicate.get(response) dupe.problem = "Form is a duplicate of another! (%s)" % conflict_id dupe.save() return dupe else: # how badly do we care about this? raise CouchFormException( "Problem POSTing form to couch! errors/response: %s/%s" % (errors, response)) else: raise def value_for_display(value, replacement_chars="_-"): """
xfd.orig_id = conflict_id xfd.doc_type=XFormDeprecated.__name__ xfd.save() # after that delete the original document and resubmit. XFormInstance.get_db().delete_doc(conflict_id) return post_xform_to_couch(instance, attachments=attachments) else: # follow standard dupe handling new_doc_id = uid.new() response, errors = post_from_settings(instance, {"uid": new_doc_id}) if not _has_errors(response, errors): # create duplicate doc # get and save the duplicate to ensure the doc types are set correctly # so that it doesn't show up in our reports dupe = XFormDuplicate.get(response) dupe.problem = "Form is a duplicate of another! (%s)" % conflict_id dupe.save() return dupe else: # how badly do we care about this? raise CouchFormException("Problem POSTing form to couch! errors/response: %s/%s" % (errors, response)) else: raise def value_for_display(value, replacement_chars="_-"): """ Formats an xform value for display, replacing the contents of the system characters with spaces """