예제 #1
0
    def handle(self, domain, **options):
        NotAllowed.check(domain)
        if not options['noinput']:
            confirm = input(
                """
                Are you sure you want to hard delete all forms and cases in domain "{}"?
                This operation is PERMANENT.

                Type the domain's name again to continue, or anything else to cancel:
                """.format(domain)
            )
            if confirm != domain:
                print("\n\t\tDomain deletion cancelled.")
                return

        logger.info('Hard deleting forms...')
        deleted_sql_form_ids = FormAccessorSQL.get_deleted_form_ids_in_domain(domain)
        for form_id_chunk in chunked(with_progress_bar(deleted_sql_form_ids, stream=silence_during_tests()), 500):
            FormAccessorSQL.hard_delete_forms(domain, list(form_id_chunk), delete_attachments=True)

        logger.info('Hard deleting cases...')
        deleted_sql_case_ids = CaseAccessorSQL.get_deleted_case_ids_in_domain(domain)
        for case_id_chunk in chunked(with_progress_bar(deleted_sql_case_ids, stream=silence_during_tests()), 500):
            CaseAccessorSQL.hard_delete_cases(domain, list(case_id_chunk))

        logger.info('Done.')
예제 #2
0
def tag_cases_as_deleted_and_remove_indices(domain, case_ids, deletion_id, deletion_date):
    from corehq.apps.sms.tasks import delete_phone_numbers_for_owners
    from corehq.messaging.scheduling.tasks import delete_schedule_instances_for_cases
    NotAllowed.check(domain)
    CaseAccessors(domain).soft_delete_cases(list(case_ids), deletion_date, deletion_id)
    _remove_indices_from_deleted_cases_task.delay(domain, case_ids)
    delete_phone_numbers_for_owners.delay(case_ids)
    delete_schedule_instances_for_cases.delay(domain, case_ids)
예제 #3
0
 def handle(self, domain, case_id, **options):
     NotAllowed.check(domain)
     case_accessor = CaseAccessors(domain=domain)
     case = case_accessor.get_case(case_id)
     if not case.is_deleted and input('\n'.join([
             'Case {} is not already deleted. Are you sure you want to delete it? (y/N)'
             .format(case_id)
     ])).lower() != 'y':
         sys.exit(0)
예제 #4
0
    def soft_delete_forms(domain,
                          form_ids,
                          deletion_date=None,
                          deletion_id=None):
        def _form_delete(doc):
            doc['server_modified_on'] = json_format_datetime(datetime.utcnow())

        NotAllowed.check(domain)
        return _soft_delete(XFormInstance.get_db(), form_ids, deletion_date,
                            deletion_id, _form_delete)
예제 #5
0
 def ensure_prerequisites(self, domain, app_id, version_number, test_run):
     NotAllowed.check(domain)
     self.domain = domain
     self.app_id = app_id
     self.version_number = version_number
     self.test_run = test_run == 'yes'
     _notify_parsed_args(domain, app_id, version_number, test_run)
     app = Application.get(self.app_id)
     if app.domain != self.domain:
         raise CommandError('Domain not same as from app id')
     self.setup()
예제 #6
0
def delete_exploded_cases(domain, explosion_id, task=None):
    NotAllowed.check(domain)
    if task:
        DownloadBase.set_progress(delete_exploded_case_task, 0, 0)
    query = (CaseSearchES()
             .domain(domain)
             .case_property_query("cc_explosion_id", explosion_id))
    case_ids = query.values_list('_id', flat=True)
    if task:
        DownloadBase.set_progress(delete_exploded_case_task, 0, len(case_ids))

    case_accessor = CaseAccessors(domain)
    form_accessor = FormAccessors(domain)
    ledger_accessor = LedgerAccessorSQL
    deleted_form_ids = set()
    num_deleted_ledger_entries = 0

    for id in case_ids:
        ledger_form_ids = {tx.form_id for tx in ledger_accessor.get_ledger_transactions_for_case(id)}
        for form_id in ledger_form_ids:
            ledger_accessor.delete_ledger_transactions_for_form([id], form_id)
        num_deleted_ledger_entries += ledger_accessor.delete_ledger_values(id)

        new_form_ids = set(case_accessor.get_case_xform_ids(id)) - deleted_form_ids
        form_accessor.soft_delete_forms(list(new_form_ids))
        deleted_form_ids |= new_form_ids

    completed = 0
    for ids in chunked(case_ids, 100):
        case_accessor.soft_delete_cases(list(ids))
        if task:
            completed += len(ids)
            DownloadBase.set_progress(delete_exploded_case_task, completed, len(case_ids))
    return {
        'messages': [
            "Successfully deleted {} cases".format(len(case_ids)),
            "Successfully deleted {} forms".format(len(deleted_form_ids)),
            "Successfully deleted {} ledgers".format(num_deleted_ledger_entries),
        ]
    }
예제 #7
0
def _handle_duplicate(new_doc):
    """
    Handle duplicate xforms and xform editing ('deprecation')

    existing doc *must* be validated as an XFormInstance in the right domain
    and *must* include inline attachments

    :returns: A two-tuple: `(<new form>, <duplicate form or None>)`
    The new form may have a different `form_id` than `new_doc.form_id`.
    """
    interface = FormProcessorInterface(new_doc.domain)
    conflict_id = new_doc.form_id
    try:
        existing_doc = FormAccessors(new_doc.domain).get_with_attachments(conflict_id)
    except ResourceNotFound:
        # Original form processing failed but left behind a form doc with no
        # attachments. It's safe to delete this now since we're going to re-process
        # the form anyway.
        from couchforms.models import XFormInstance
        XFormInstance.get_db().delete_doc(conflict_id)
        return new_doc, None

    try:
        existing_md5 = existing_doc.xml_md5()
    except MissingFormXml:
        existing_md5 = None
        if not existing_doc.is_error:
            existing_doc.problem = 'Missing form.xml'

    new_md5 = new_doc.xml_md5()

    if existing_md5 != new_md5:
        _soft_assert = soft_assert(to='{}@{}.com'.format('skelly', 'dimagi'), exponential_backoff=False)
        if new_doc.xmlns != existing_doc.xmlns:
            # if the XMLNS has changed this probably isn't a form edit
            # it could be a UUID clash (yes we've had that before)
            # Assign a new ID to the form and process as normal + notify_admins
            xform = interface.assign_new_id(new_doc)
            _soft_assert(
                False, "Potential UUID clash", {
                    'incoming_form_id': conflict_id,
                    'existing_form_id': existing_doc.form_id,
                    'new_form_id': xform.form_id,
                    'incoming_xmlns': new_doc.xmlns,
                    'existing_xmlns': existing_doc.xmlns,
                    'domain': new_doc.domain,
                }
            )
            return xform, None
        else:
            if existing_doc.is_error and not existing_doc.initial_processing_complete:
                # edge case from ICDS where a form errors and then future re-submissions of the same
                # form do not have the same MD5 hash due to a bug on mobile:
                # see https://dimagi-dev.atlassian.net/browse/ICDS-376

                # since we have a new form and the old one was not successfully processed
                # we can effectively ignore this form and process the new one as normal
                if not interface.use_sql_domain:
                    new_doc._rev, existing_doc._rev = existing_doc._rev, new_doc._rev
                interface.assign_new_id(existing_doc)
                existing_doc.save()
                return new_doc, None
            else:
                # if the form contents are not the same:
                #  - "Deprecate" the old form by making a new document with the same contents
                #    but a different ID and a doc_type of XFormDeprecated
                #  - Save the new instance to the previous document to preserve the ID
                NotAllowed.check(new_doc.domain)
                existing_doc, new_doc = apply_deprecation(existing_doc, new_doc, interface)
                return new_doc, existing_doc
    else:
        # follow standard dupe handling, which simply saves a copy of the form
        # but a new doc_id, and a doc_type of XFormDuplicate
        duplicate = interface.deduplicate_xform(new_doc)
        return duplicate, existing_doc
예제 #8
0
 def soft_undelete_cases(domain, case_ids):
     NotAllowed.check(domain)
     return _soft_undelete(CommCareCase.get_db(), case_ids)
예제 #9
0
 def soft_delete(self):
     NotAllowed.check(self.domain)
     self.doc_type += DELETED_SUFFIX
     self.save()
예제 #10
0
 def _deprecate_old_form():
     NotAllowed.check(new_doc.domain)
     existing, new = apply_deprecation(existing_doc, new_doc, interface)
     return new, existing