Exemplo n.º 1
0
def run_case_update_rules_for_domain(domain, now=None):
    now = now or datetime.utcnow()
    start_run = datetime.utcnow()
    all_rules = AutomaticUpdateRule.by_domain(domain)
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(all_rules)

    for case_type, rules in rules_by_case_type.iteritems():
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_id_chunks = AutomaticUpdateRule.get_case_ids(domain, case_type, boundary_date)

        for case_ids in case_id_chunks:
            for case in CaseAccessors(domain).iter_cases(case_ids):
                time_elapsed = datetime.utcnow() - start_run
                if time_elapsed.seconds > HALT_AFTER:
                    notify_error(
                        "Halting rule run for domain %s as it's been running for more than a day." % domain
                    )
                    return

                for rule in rules:
                    stop_processing = rule.apply_rule(case, now)
                    if stop_processing:
                        break

        for rule in rules:
            rule.last_run = now
            rule.save()
Exemplo n.º 2
0
def run_case_update_rules_for_domain(domain, now=None):
    now = now or datetime.utcnow()

    domain_rules = AutomaticUpdateRule.by_domain(
        domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
    all_rule_case_types = set(domain_rules.values_list('case_type', flat=True))

    for case_type in all_rule_case_types:
        run_record = DomainCaseRuleRun.objects.create(
            domain=domain,
            started_on=datetime.utcnow(),
            status=DomainCaseRuleRun.STATUS_RUNNING,
            case_type=case_type)

        if should_use_sql_backend(domain):
            for db in get_db_aliases_for_partitioned_query():
                run_case_update_rules_for_domain_and_db.delay(domain,
                                                              now,
                                                              run_record.pk,
                                                              case_type,
                                                              db=db)
        else:
            # explicitly pass db=None so that the serial task decorator has access to db in the key generation
            run_case_update_rules_for_domain_and_db.delay(domain,
                                                          now,
                                                          run_record.pk,
                                                          case_type,
                                                          db=None)
Exemplo n.º 3
0
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     try:
         AutomaticUpdateRule.by_domain(
             domain.name,
             AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
         ).update(active=False)
         AutomaticUpdateRule.clear_caches(
             domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
         return True
     except Exception:
         log_accounting_error("Failed to deactivate automatic update rules "
                              "for domain %s." % domain.name)
         return False
Exemplo n.º 4
0
    def test_get_rules_from_domain(self):
        rules = AutomaticUpdateRule.by_domain(self.domain)
        rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(
            rules)

        expected_case_types = [
            'test-case-type', 'test-case-type-2', 'test-case-type-3'
        ]
        actual_case_types = rules_by_case_type.keys()
        self.assertEqual(set(expected_case_types), set(actual_case_types))

        expected_rule_ids = [self.rule.pk, self.rule4.pk]
        actual_rule_ids = [
            rule.pk for rule in rules_by_case_type['test-case-type']
        ]
        self.assertEqual(set(expected_rule_ids), set(actual_rule_ids))

        expected_rule_ids = [self.rule2.pk, self.rule3.pk]
        actual_rule_ids = [
            rule.pk for rule in rules_by_case_type['test-case-type-2']
        ]
        self.assertEqual(set(expected_rule_ids), set(actual_rule_ids))

        expected_rule_ids = [self.rule5.pk]
        actual_rule_ids = [
            rule.pk for rule in rules_by_case_type['test-case-type-3']
        ]
        self.assertEqual(set(expected_rule_ids), set(actual_rule_ids))
Exemplo n.º 5
0
    def get_pagination_data(self, in_data):
        try:
            limit = int(in_data['limit'])
            page = int(in_data['page'])
        except (TypeError, KeyError, ValueError):
            return {
                'success': False,
                'error': _("Please provide pagination info."),
            }

        start = (page - 1) * limit
        stop = limit * page

        rules = AutomaticUpdateRule.by_domain(
            self.domain,
            AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
            active_only=False,
        )

        rule_page = rules.order_by('name')[start:stop]
        total = rules.count()

        return {
            'response': {
                'itemList': map(self._format_rule, rule_page),
                'total': total,
                'page': page,
            },
            'success': True,
        }
Exemplo n.º 6
0
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     try:
         AutomaticUpdateRule.by_domain(
             domain.name,
             AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
         ).update(active=False)
         AutomaticUpdateRule.clear_caches(domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
         return True
     except Exception:
         log_accounting_error(
             "Failed to deactivate automatic update rules "
             "for domain %s." % domain.name
         )
         return False
Exemplo n.º 7
0
def _get_active_scheduling_rules(domain, survey_only=False):
    rules = AutomaticUpdateRule.by_domain(domain.name, AutomaticUpdateRule.WORKFLOW_SCHEDULING, active_only=False)

    result = []
    for rule in rules:
        schedule = rule.get_messaging_rule_schedule()
        if schedule.active and (not survey_only or schedule.memoized_uses_sms_survey):
            result.append(rule)

    return result
Exemplo n.º 8
0
def get_auto_update_rules(domain):
    rules = AutomaticUpdateRule.by_domain(
        domain,
        # For now only grab those rules that update cases, not conditional alerts for messaging
        AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
        active_only=False)

    data = []
    for rule in rules:
        criterias = rule.caserulecriteria_set.all()
        actions = rule.caseruleaction_set.all()

        rule_data = {
            "rule":
            rule.to_json(),
            "criteria": [{
                "match_property_definition": {
                    "property_name":
                    case_rule_criter.match_property_definition.property_name,
                    "property_value":
                    case_rule_criter.match_property_definition.property_value,
                    "match_type":
                    case_rule_criter.match_property_definition.match_type
                } if case_rule_criter.match_property_definition is not None
                else None,
                "custom_match_definition": {
                    "name": case_rule_criter.custom_match_definition.name,
                } if case_rule_criter.custom_match_definition is not None else
                None,
                "closed_parent_definition":
                case_rule_criter.closed_parent_definition is not None
            } for case_rule_criter in criterias],
            "actions": [{
                "update_case_definition": {
                    "properties_to_update":
                    case_rule_action.update_case_definition.
                    properties_to_update,
                    "close_case":
                    case_rule_action.update_case_definition.close_case
                } if case_rule_action.update_case_definition is not None else
                None,
                "custom_action_definition": {
                    "name": case_rule_action.custom_action_definition.name
                } if case_rule_action.custom_action_definition is not None else
                None,
            } for case_rule_action in actions]
        }

        # Delete unnecessary data for running rules
        del rule_data['rule']['last_run']
        del rule_data['rule']['locked_for_editing']

        data.append(rule_data)

    return data
    def test_boundary_date(self):
        rules = AutomaticUpdateRule.by_domain(self.domain)
        rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(rules)

        boundary_date = AutomaticUpdateRule.get_boundary_date(
            rules_by_case_type['test-case-type'], datetime(2016, 1, 1))
        self.assertEqual(boundary_date, datetime(2015, 12, 2))

        boundary_date = AutomaticUpdateRule.get_boundary_date(
            rules_by_case_type['test-case-type-2'], datetime(2016, 1, 1))
        self.assertEqual(boundary_date, datetime(2015, 12, 2))
Exemplo n.º 10
0
    def test_boundary_date(self):
        rules = AutomaticUpdateRule.by_domain(self.domain)
        rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(
            rules)

        boundary_date = AutomaticUpdateRule.get_boundary_date(
            rules_by_case_type['test-case-type'], datetime(2016, 1, 1))
        self.assertEqual(boundary_date, datetime(2015, 12, 2))

        boundary_date = AutomaticUpdateRule.get_boundary_date(
            rules_by_case_type['test-case-type-2'], datetime(2016, 1, 1))
        self.assertEqual(boundary_date, datetime(2015, 12, 2))
Exemplo n.º 11
0
def run_case_update_rules_on_save(case):
    key = 'case-update-on-save-case-{case}'.format(case=case.case_id)
    with CriticalSection([key]):
        update_case = True
        if case.xform_ids:
            last_form = FormAccessors(case.domain).get_form(case.xform_ids[-1])
            update_case = last_form.xmlns != AUTO_UPDATE_XMLNS
        if update_case:
            rules = AutomaticUpdateRule.by_domain(case.domain,
                AutomaticUpdateRule.WORKFLOW_CASE_UPDATE).filter(case_type=case.type)
            now = datetime.utcnow()
            run_rules_for_case(case, rules, now)
Exemplo n.º 12
0
def run_case_update_rules_for_domain_and_db(domain, now, run_id, db=None):
    domain_obj = Domain.get_by_name(domain)
    max_allowed_updates = domain_obj.auto_case_update_limit or settings.MAX_RULE_UPDATES_IN_ONE_RUN
    start_run = datetime.utcnow()

    last_migration_check_time = None
    cases_checked = 0
    case_update_result = CaseRuleActionResult()

    all_rules = list(
        AutomaticUpdateRule.by_domain(
            domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE))
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(
        all_rules)

    for case_type, rules in six.iteritems(rules_by_case_type):
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_ids = list(
            AutomaticUpdateRule.get_case_ids(domain,
                                             case_type,
                                             boundary_date,
                                             db=db))

        for case in CaseAccessors(domain).iter_cases(case_ids):
            migration_in_progress, last_migration_check_time = check_data_migration_in_progress(
                domain, last_migration_check_time)

            time_elapsed = datetime.utcnow() - start_run
            if (time_elapsed.seconds > HALT_AFTER
                    or case_update_result.total_updates >= max_allowed_updates
                    or migration_in_progress):
                DomainCaseRuleRun.done(run_id,
                                       DomainCaseRuleRun.STATUS_HALTED,
                                       cases_checked,
                                       case_update_result,
                                       db=db)
                notify_error("Halting rule run for domain %s." % domain)
                return

            case_update_result.add_result(run_rules_for_case(case, rules, now))
            cases_checked += 1

    run = DomainCaseRuleRun.done(run_id,
                                 DomainCaseRuleRun.STATUS_FINISHED,
                                 cases_checked,
                                 case_update_result,
                                 db=db)

    if run.status == DomainCaseRuleRun.STATUS_FINISHED:
        for rule in all_rules:
            AutomaticUpdateRule.objects.filter(pk=rule.pk).update(last_run=now)
Exemplo n.º 13
0
def run_case_update_rules_on_save(case):
    key = 'case-update-on-save-case-{case}'.format(case=case.case_id)
    with CriticalSection([key]):
        update_case = True
        if case.xform_ids:
            last_form = FormAccessors(case.domain).get_form(case.xform_ids[-1])
            update_case = last_form.xmlns != AUTO_UPDATE_XMLNS
        if update_case:
            rules = AutomaticUpdateRule.by_domain(case.domain).filter(case_type=case.type)
            now = datetime.utcnow()
            for rule in rules:
                stop_processing = rule.apply_rule(case, now)
                if stop_processing:
                    break
Exemplo n.º 14
0
    def test_get_rules_from_domain(self):
        rules = AutomaticUpdateRule.by_domain(self.domain)
        rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(rules)

        expected_case_types = ['test-case-type', 'test-case-type-2']
        actual_case_types = rules_by_case_type.keys()
        self.assertEqual(set(expected_case_types), set(actual_case_types))

        expected_rule_ids = [self.rule.pk]
        actual_rule_ids = [rule.pk for rule in rules_by_case_type['test-case-type']]
        self.assertEqual(set(expected_rule_ids), set(actual_rule_ids))

        expected_rule_ids = [self.rule2.pk, self.rule3.pk]
        actual_rule_ids = [rule.pk for rule in rules_by_case_type['test-case-type-2']]
        self.assertEqual(set(expected_rule_ids), set(actual_rule_ids))
Exemplo n.º 15
0
def run_case_update_rules_for_domain(domain, now=None):
    domain_obj = Domain.get_by_name(domain)
    max_allowed_updates = domain_obj.auto_case_update_limit or settings.MAX_RULE_UPDATES_IN_ONE_RUN

    now = now or datetime.utcnow()
    start_run = datetime.utcnow()
    last_migration_check_time = None
    run_record = DomainCaseRuleRun.objects.create(
        domain=domain,
        started_on=start_run,
        status=DomainCaseRuleRun.STATUS_RUNNING,
    )
    cases_checked = 0
    case_update_result = CaseRuleActionResult()

    all_rules = AutomaticUpdateRule.by_domain(
        domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(
        all_rules)

    for case_type, rules in six.iteritems(rules_by_case_type):
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_ids = list(
            AutomaticUpdateRule.get_case_ids(domain, case_type, boundary_date))

        for case in CaseAccessors(domain).iter_cases(case_ids):
            migration_in_progress, last_migration_check_time = check_data_migration_in_progress(
                domain, last_migration_check_time)

            time_elapsed = datetime.utcnow() - start_run
            if (time_elapsed.seconds > HALT_AFTER
                    or case_update_result.total_updates >= max_allowed_updates
                    or migration_in_progress):
                run_record.done(DomainCaseRuleRun.STATUS_HALTED, cases_checked,
                                case_update_result)
                notify_error("Halting rule run for domain %s." % domain)
                return

            case_update_result.add_result(run_rules_for_case(case, rules, now))
            cases_checked += 1

        for rule in rules:
            rule.last_run = now
            rule.save()

    run_record.done(DomainCaseRuleRun.STATUS_FINISHED, cases_checked,
                    case_update_result)
Exemplo n.º 16
0
def run_case_update_rules_for_domain(domain, now=None):
    now = now or datetime.utcnow()
    all_rules = AutomaticUpdateRule.by_domain(domain)
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(all_rules)

    for case_type, rules in rules_by_case_type.iteritems():
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_ids = AutomaticUpdateRule.get_case_ids(domain, boundary_date, case_type)

        for doc in iter_docs(CommCareCase.get_db(), case_ids):
            case = CommCareCase.wrap(doc)
            for rule in rules:
                rule.apply_rule(case, now)

        for rule in rules:
            rule.last_run = now
            rule.save()
Exemplo n.º 17
0
def run_case_update_rules_for_domain(domain, now=None):
    now = now or datetime.utcnow()
    all_rules = AutomaticUpdateRule.by_domain(domain)
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(all_rules)

    for case_type, rules in rules_by_case_type.iteritems():
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_ids = AutomaticUpdateRule.get_case_ids(domain, case_type, boundary_date)

        for case in CaseAccessors(domain).iter_cases(case_ids):
            for rule in rules:
                stop_processing = rule.apply_rule(case, now)
                if stop_processing:
                    break

        for rule in rules:
            rule.last_run = now
            rule.save()
Exemplo n.º 18
0
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     rule_count = AutomaticUpdateRule.by_domain(
         domain.name,
         AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
     ).count()
     if rule_count > 0:
         return _fmt_alert(
             ungettext(
                 "You have %(rule_count)d automatic case update rule "
                 "configured in your project. If you select this plan, "
                 "this rule will be deactivated.",
                 "You have %(rule_count)d automatic case update rules "
                 "configured in your project. If you select this plan, "
                 "these rules will be deactivated.", rule_count) % {
                     'rule_count': rule_count,
                 })
Exemplo n.º 19
0
    def handle(self, domain, **options):
        result = []
        for rule in AutomaticUpdateRule.by_domain(
                domain,
                AutomaticUpdateRule.WORKFLOW_SCHEDULING,
                active_only=False,
        ):
            json_rule = self.get_json_rule(rule)

            action = rule.memoized_actions[0].definition
            if action.schedule.location_type_filter:
                raise CommandError(
                    "Expected location_type_filter to be empty for rule %s. Location type filtering "
                    "references primary keys of LocationType objects which aren't guaranteed to be "
                    "the same in the imported project. This rule must be excluded from export."
                    % rule.pk)

            if isinstance(action.schedule, TimedSchedule):
                json_schedule = self.get_json_timed_schedule(action.schedule)
            elif isinstance(action.schedule, AlertSchedule):
                json_schedule = self.get_json_alert_schedule(action.schedule)
            else:
                raise CommandError(
                    "Unexpected Schedule type for rule %s. Support must be added to this script for "
                    "anything other than TimedSchedules or AlertSchedules." %
                    rule.pk)

            result.append(
                json.dumps({
                    'rule': json_rule.to_json(),
                    'schedule': json_schedule.to_json(),
                }))

        with open('conditional_alerts_for_%s.txt' % domain,
                  'w',
                  encoding='utf-8') as f:
            for line in result:
                f.write(line)
                f.write('\n')

        print("Done")
Exemplo n.º 20
0
def run_case_update_rules_for_domain_and_db(domain, now, run_id, db=None):
    domain_obj = Domain.get_by_name(domain)
    max_allowed_updates = domain_obj.auto_case_update_limit or settings.MAX_RULE_UPDATES_IN_ONE_RUN
    start_run = datetime.utcnow()

    last_migration_check_time = None
    cases_checked = 0
    case_update_result = CaseRuleActionResult()

    all_rules = list(AutomaticUpdateRule.by_domain(domain, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE))
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(all_rules)

    for case_type, rules in six.iteritems(rules_by_case_type):
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_ids = list(AutomaticUpdateRule.get_case_ids(domain, case_type, boundary_date, db=db))

        for case in CaseAccessors(domain).iter_cases(case_ids):
            migration_in_progress, last_migration_check_time = check_data_migration_in_progress(domain,
                last_migration_check_time)

            time_elapsed = datetime.utcnow() - start_run
            if (
                time_elapsed.seconds > HALT_AFTER or
                case_update_result.total_updates >= max_allowed_updates or
                migration_in_progress
            ):
                DomainCaseRuleRun.done(run_id, DomainCaseRuleRun.STATUS_HALTED, cases_checked, case_update_result,
                    db=db)
                notify_error("Halting rule run for domain %s." % domain)
                return

            case_update_result.add_result(run_rules_for_case(case, rules, now))
            cases_checked += 1

    run = DomainCaseRuleRun.done(run_id, DomainCaseRuleRun.STATUS_FINISHED, cases_checked, case_update_result,
        db=db)

    if run.status == DomainCaseRuleRun.STATUS_FINISHED:
        for rule in all_rules:
            AutomaticUpdateRule.objects.filter(pk=rule.pk).update(last_run=now)
Exemplo n.º 21
0
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     rule_count = AutomaticUpdateRule.by_domain(
         domain.name,
         AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
     ).count()
     if rule_count > 0:
         return _fmt_alert(
             ungettext(
                 "You have %(rule_count)d automatic case update rule "
                 "configured in your project. If you select this plan, "
                 "this rule will be deactivated.",
                 "You have %(rule_count)d automatic case update rules "
                 "configured in your project. If you select this plan, "
                 "these rules will be deactivated.",
                 rule_count
             ) % {
                 'rule_count': rule_count,
             }
         )
Exemplo n.º 22
0
def run_case_update_rules_for_domain(domain, now=None):
    now = now or datetime.utcnow()
    start_run = datetime.utcnow()
    run_record = DomainCaseRuleRun.objects.create(
        domain=domain,
        started_on=start_run,
        status=DomainCaseRuleRun.STATUS_RUNNING,
    )
    cases_checked = 0
    case_update_result = CaseRuleActionResult()

    all_rules = AutomaticUpdateRule.by_domain(domain)
    rules_by_case_type = AutomaticUpdateRule.organize_rules_by_case_type(all_rules)

    for case_type, rules in rules_by_case_type.iteritems():
        boundary_date = AutomaticUpdateRule.get_boundary_date(rules, now)
        case_id_chunks = AutomaticUpdateRule.get_case_ids(domain, case_type, boundary_date)

        for case_ids in case_id_chunks:
            for case in CaseAccessors(domain).iter_cases(case_ids):
                time_elapsed = datetime.utcnow() - start_run
                if (
                    time_elapsed.seconds > HALT_AFTER or
                    case_update_result.total_updates >= settings.MAX_RULE_UPDATES_IN_ONE_RUN
                ):
                    run_record.done(DomainCaseRuleRun.STATUS_HALTED, cases_checked, case_update_result)
                    notify_error("Halting rule run for domain %s." % domain)
                    return

                case_update_result.add_result(run_rules_for_case(case, rules, now))
                cases_checked += 1

        for rule in rules:
            rule.last_run = now
            rule.save()

    run_record.done(DomainCaseRuleRun.STATUS_FINISHED, cases_checked, case_update_result)
Exemplo n.º 23
0
 def _rules(self):
     return AutomaticUpdateRule.by_domain(
         self.domain,
         self.rule_workflow,
         active_only=False,
     ).order_by('name', 'id')
Exemplo n.º 24
0
def update_auto_update_rules(domain_link):
    if domain_link.is_remote:
        upstream_rules = remote_get_auto_update_rules(domain_link)
    else:
        upstream_rules = local_get_auto_update_rules(domain_link.master_domain)

    downstream_rules = AutomaticUpdateRule.by_domain(
        domain_link.linked_domain,
        AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
        active_only=False
    )

    for upstream_rule_def in upstream_rules:
        # Grab local rule by upstream ID (preferred) or by name
        try:
            downstream_rule = downstream_rules.get(upstream_id=upstream_rule_def['rule']['id'])
        except AutomaticUpdateRule.DoesNotExist:
            try:
                downstream_rule = downstream_rules.get(name=upstream_rule_def['rule']['name'])
            except AutomaticUpdateRule.MultipleObjectsReturned:
                # If there are multiple rules with the same name, overwrite the first.
                downstream_rule = downstream_rules.filter(name=upstream_rule_def['rule']['name']).first()
            except AutomaticUpdateRule.DoesNotExist:
                downstream_rule = None

        # If no corresponding local rule, make a new rule
        if not downstream_rule:
            downstream_rule = AutomaticUpdateRule(
                domain=domain_link.linked_domain,
                active=upstream_rule_def['rule']['active'],
                workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
                upstream_id=upstream_rule_def['rule']['id']
            )

        # Copy all the contents from old rule to new rule
        with transaction.atomic():

            downstream_rule.name = upstream_rule_def['rule']['name']
            downstream_rule.case_type = upstream_rule_def['rule']['case_type']
            downstream_rule.filter_on_server_modified = upstream_rule_def['rule']['filter_on_server_modified']
            downstream_rule.server_modified_boundary = upstream_rule_def['rule']['server_modified_boundary']
            downstream_rule.active = upstream_rule_def['rule']['active']
            downstream_rule.save()

            downstream_rule.delete_criteria()
            downstream_rule.delete_actions()

            # Largely from data_interfaces/forms.py - save_criteria()
            for criteria in upstream_rule_def['criteria']:
                definition = None

                if criteria['match_property_definition']:
                    definition = MatchPropertyDefinition.objects.create(
                        property_name=criteria['match_property_definition']['property_name'],
                        property_value=criteria['match_property_definition']['property_value'],
                        match_type=criteria['match_property_definition']['match_type'],
                    )
                elif criteria['custom_match_definition']:
                    definition = CustomMatchDefinition.objects.create(
                        name=criteria['custom_match_definition']['name'],
                    )
                elif criteria['closed_parent_definition']:
                    definition = ClosedParentDefinition.objects.create()

                new_criteria = CaseRuleCriteria(rule=downstream_rule)
                new_criteria.definition = definition
                new_criteria.save()

            # Largely from data_interfacees/forms.py - save_actions()
            for action in upstream_rule_def['actions']:
                definition = None

                if action['update_case_definition']:
                    definition = UpdateCaseDefinition(close_case=action['update_case_definition']['close_case'])
                    properties = []
                    for propertyItem in action['update_case_definition']['properties_to_update']:
                        properties.append(
                            UpdateCaseDefinition.PropertyDefinition(
                                name=propertyItem['name'],
                                value_type=propertyItem['value_type'],
                                value=propertyItem['value'],
                            )
                        )
                    definition.set_properties_to_update(properties)
                    definition.save()
                elif action['custom_action_definition']:
                    definition = CustomActionDefinition.objects.create(
                        name=action['custom_action_definition']['name'],
                    )

                action = CaseRuleAction(rule=downstream_rule)
                action.definition = definition
                action.save()
Exemplo n.º 25
0
    def test_update_auto_update_rules(self):
        self.assertFalse(
            AutomaticUpdateRule.by_domain(domain=self.linked_domain,
                                          workflow="CASE_UPDATE").exists())

        update_auto_update_rules(self.domain_link)

        linked_domain_rules = AutomaticUpdateRule.by_domain(
            self.linked_domain,
            active_only=False,
            workflow=AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
        self.assertEqual(3, linked_domain_rules.count())

        for rule in linked_domain_rules:
            self.assertTrue(
                rule.name in
                ["Norway rule", "Is it hot enough?", "Closed parent case"])
            if (rule.name == "Closed parent case"):
                self.assertEqual(rule.case_type, "family_member")
            else:
                self.assertEqual(rule.case_type, "person")
            if (rule.name == "Is it hot enough?"):
                self.assertFalse(rule.filter_on_server_modified)
                self.assertEqual(2, rule.server_modified_boundary)
            else:
                self.assertTrue(rule.filter_on_server_modified)
                self.assertFalse(rule.server_modified_boundary)

            caseRuleCriterias = CaseRuleCriteria.objects.filter(rule=rule)
            if (rule.name == "Is it hot enough?"):
                criteria = caseRuleCriterias.first()
                self.assertEqual(
                    criteria.match_property_definition.property_name,
                    "temperature")
                self.assertEqual(
                    criteria.match_property_definition.property_value, "96")
                self.assertEqual(criteria.match_property_definition.match_type,
                                 MatchPropertyDefinition.MATCH_EQUAL)
                self.assertFalse(criteria.closed_parent_definition)
            elif (rule.name == "Norway rule"):
                self.assertEqual(2, caseRuleCriterias.count())
                for criteria in caseRuleCriterias:
                    self.assertTrue(criteria.match_property_definition
                                    or criteria.custom_match_definition)
                    if (criteria.match_property_definition is not None):
                        self.assertEqual(
                            criteria.match_property_definition.property_value,
                            "Norway")
                    elif (criteria.custom_match_definition is not None):
                        self.assertEqual(criteria.custom_match_definition.name,
                                         "COVID_US_ASSOCIATED_USER_CASES")
            elif (rule.name == "Closed parent case"):
                criteria = caseRuleCriterias.first()
                self.assertTrue(criteria.closed_parent_definition)

            caseRuleActions = CaseRuleAction.objects.filter(rule=rule)
            if (rule.name == "Norway rule"):
                action = caseRuleActions.first()
                self.assertEqual(action.update_case_definition.close_case,
                                 True)
            if (rule.name == "Is it hot enough?"):
                self.assertEqual(2, caseRuleActions.count())
                for action in caseRuleActions:
                    if (action.update_case_definition is not None):
                        self.assertEqual(
                            2,
                            len(action.update_case_definition.
                                properties_to_update))
                        for property in action.update_case_definition.properties_to_update:
                            self.assertTrue(
                                property['name'] in
                                ["hot_enough", "territory_hot_enough"])
                            if (property['name'] == "hot_enough"):
                                self.assertEqual(property['value_type'],
                                                 "EXACT")
                            elif (property['name'] == "territory_hot_enough"):
                                self.assertEqual(property['value'],
                                                 "current_territory")
                    elif (action.custom_action_definition is not None):
                        self.assertEqual(
                            action.custom_action_definition.name,
                            "COVID_US_CLOSE_CASES_ASSIGNED_CHECKIN")
Exemplo n.º 26
0
 def _rules(self):
     return AutomaticUpdateRule.by_domain(
         self.domain,
         AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
         active_only=False,
     ).order_by('name', 'id')
Exemplo n.º 27
0
 def _rules(self):
     return AutomaticUpdateRule.by_domain(
         self.domain,
         AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
         active_only=False,
     ).order_by('name', 'id')
Exemplo n.º 28
0
    def save_copy(self, new_domain_name=None, new_hr_name=None, user=None,
                  copy_by_id=None, share_reminders=True,
                  share_user_roles=True):
        from corehq.apps.app_manager.dbaccessors import get_app
        from corehq.apps.data_interfaces.models import AutomaticUpdateRule
        from corehq.apps.reminders.models import CaseReminderHandler
        from corehq.apps.fixtures.models import FixtureDataItem
        from corehq.apps.app_manager.dbaccessors import get_brief_apps_in_domain
        from corehq.apps.domain.dbaccessors import get_doc_ids_in_domain_by_class
        from corehq.apps.fixtures.models import FixtureDataType
        from corehq.apps.users.models import UserRole

        db = Domain.get_db()
        new_id = db.copy_doc(self.get_id)['id']
        if new_domain_name is None:
            new_domain_name = new_id

        uses_new_reminders = project_is_on_new_reminders(self)

        with CriticalSection(['request_domain_name_{}'.format(new_domain_name)]):
            new_domain_name = Domain.generate_name(new_domain_name)
            new_domain = Domain.get(new_id)
            new_domain.name = new_domain_name
            new_domain.hr_name = new_hr_name
            new_domain.copy_history = self.get_updated_history()
            new_domain.is_snapshot = False
            new_domain.snapshot_time = None
            new_domain.organization = None  # TODO: use current user's organization (?)

            # reset stuff
            new_domain.cda.signed = False
            new_domain.cda.date = None
            new_domain.cda.type = None
            new_domain.cda.user_id = None
            new_domain.cda.user_ip = None
            new_domain.is_test = "none"
            new_domain.internal = InternalProperties()
            new_domain.creating_user = user.username if user else None
            new_domain.date_created = datetime.utcnow()
            new_domain.use_sql_backend = True
            new_domain.granted_messaging_access = False

            for field in self._dirty_fields:
                if hasattr(new_domain, field):
                    delattr(new_domain, field)

            # Saving the domain should happen before we import any apps since
            # importing apps can update the domain object (for example, if user
            # as a case needs to be enabled)
            try:
                new_domain.save()
            except PreconditionFailed:
                # This is a hack to resolve http://manage.dimagi.com/default.asp?241492
                # Following solution in
                # https://github.com/dimagi/commcare-hq/commit/d59b1e403060ade599cc4a03db0aabc4da62b668
                time.sleep(0.5)
                new_domain.save()

            new_app_components = {}  # a mapping of component's id to its copy

            def copy_data_items(old_type_id, new_type_id):
                for item in FixtureDataItem.by_data_type(self.name, old_type_id):
                    comp = self.copy_component(
                        item.doc_type, item._id, new_domain_name, user=user)
                    comp.data_type_id = new_type_id
                    comp.save()

            def get_latest_app_id(doc_id):
                app = get_app(self.name, doc_id).get_latest_saved()
                if app:
                    return app._id, app.doc_type

            for app in get_brief_apps_in_domain(self.name):
                doc_id, doc_type = app.get_id, app.doc_type
                original_doc_id = doc_id
                if copy_by_id and doc_id not in copy_by_id:
                    continue
                if not self.is_snapshot:
                    doc_id, doc_type = get_latest_app_id(doc_id) or (doc_id, doc_type)
                component = self.copy_component(doc_type, doc_id, new_domain_name, user=user)
                if component:
                    new_app_components[original_doc_id] = component

            for doc_id in get_doc_ids_in_domain_by_class(self.name, FixtureDataType):
                if copy_by_id and doc_id not in copy_by_id:
                    continue
                component = self.copy_component(
                    'FixtureDataType', doc_id, new_domain_name, user=user)
                copy_data_items(doc_id, component._id)

            def convert_form_unique_id_function(form_unique_id):
                from corehq.apps.app_manager.models import FormBase
                form = FormBase.get_form(form_unique_id)
                form_app = form.get_app()
                m_index, f_index = form_app.get_form_location(form.unique_id)
                form_copy = new_app_components[form_app._id].get_module(m_index).get_form(f_index)
                return form_copy.unique_id

            if share_reminders:
                if uses_new_reminders:
                    for rule in AutomaticUpdateRule.by_domain(
                        self.name,
                        AutomaticUpdateRule.WORKFLOW_SCHEDULING,
                        active_only=False,
                    ):
                        rule.copy_conditional_alert(
                            new_domain_name,
                            convert_form_unique_id_function=convert_form_unique_id_function,
                        )
                else:
                    for doc_id in get_doc_ids_in_domain_by_class(self.name, CaseReminderHandler):
                        self.copy_component(
                            'CaseReminderHandler', doc_id, new_domain_name, user=user)
            if share_user_roles:
                for doc_id in get_doc_ids_in_domain_by_class(self.name, UserRole):
                    self.copy_component('UserRole', doc_id, new_domain_name, user=user)

        if user:
            def add_dom_to_user(user):
                user.add_domain_membership(new_domain_name, is_admin=True)
            apply_update(user, add_dom_to_user)

        if not uses_new_reminders:
            # When uses_new_reminders is True, all of this is already taken care of
            # in the copy process
            def update_events(handler):
                """
                Change the form_unique_id to the proper form for each event in a newly copied CaseReminderHandler
                """
                for event in handler.events:
                    if not event.form_unique_id:
                        continue
                    event.form_unique_id = convert_form_unique_id_function(event.form_unique_id)

            def update_for_copy(handler):
                handler.active = False
                update_events(handler)

            if share_reminders:
                for handler in CaseReminderHandler.get_handlers(new_domain_name):
                    apply_update(handler, update_for_copy)

        return new_domain
Exemplo n.º 29
0
    def save_copy(self, new_domain_name=None, new_hr_name=None, user=None,
                  copy_by_id=None, share_reminders=True,
                  share_user_roles=True):
        from corehq.apps.app_manager.dbaccessors import get_app
        from corehq.apps.data_interfaces.models import AutomaticUpdateRule
        from corehq.apps.fixtures.models import FixtureDataItem
        from corehq.apps.app_manager.dbaccessors import get_brief_apps_in_domain
        from corehq.apps.domain.dbaccessors import get_doc_ids_in_domain_by_class
        from corehq.apps.fixtures.models import FixtureDataType
        from corehq.apps.users.models import UserRole

        db = Domain.get_db()
        new_id = db.copy_doc(self.get_id)['id']
        if new_domain_name is None:
            new_domain_name = new_id

        with CriticalSection(['request_domain_name_{}'.format(new_domain_name)]):
            new_domain_name = Domain.generate_name(new_domain_name)
            new_domain = Domain.get(new_id)
            new_domain.name = new_domain_name
            new_domain.hr_name = new_hr_name
            new_domain.copy_history = self.get_updated_history()
            new_domain.is_snapshot = False
            new_domain.snapshot_time = None
            new_domain.organization = None  # TODO: use current user's organization (?)

            # reset stuff
            new_domain.cda.signed = False
            new_domain.cda.date = None
            new_domain.cda.type = None
            new_domain.cda.user_id = None
            new_domain.cda.user_ip = None
            new_domain.is_test = "none"
            new_domain.internal = InternalProperties()
            new_domain.creating_user = user.username if user else None
            new_domain.date_created = datetime.utcnow()
            new_domain.use_sql_backend = True
            new_domain.granted_messaging_access = False

            for field in self._dirty_fields:
                if hasattr(new_domain, field):
                    delattr(new_domain, field)

            # Saving the domain should happen before we import any apps since
            # importing apps can update the domain object (for example, if user
            # as a case needs to be enabled)
            try:
                new_domain.save()
            except PreconditionFailed:
                # This is a hack to resolve http://manage.dimagi.com/default.asp?241492
                # Following solution in
                # https://github.com/dimagi/commcare-hq/commit/d59b1e403060ade599cc4a03db0aabc4da62b668
                time.sleep(0.5)
                new_domain.save()

            new_app_components = {}  # a mapping of component's id to its copy

            def copy_data_items(old_type_id, new_type_id):
                for item in FixtureDataItem.by_data_type(self.name, old_type_id):
                    comp = self.copy_component(
                        item.doc_type, item._id, new_domain_name, user=user)
                    comp.data_type_id = new_type_id
                    comp.save()

            def get_latest_app_id(doc_id):
                app = get_app(self.name, doc_id).get_latest_saved()
                if app:
                    return app._id, app.doc_type

            for app in get_brief_apps_in_domain(self.name):
                doc_id, doc_type = app.get_id, app.doc_type
                original_doc_id = doc_id
                if copy_by_id and doc_id not in copy_by_id:
                    continue
                if not self.is_snapshot:
                    doc_id, doc_type = get_latest_app_id(doc_id) or (doc_id, doc_type)
                component = self.copy_component(doc_type, doc_id, new_domain_name, user=user)
                if component:
                    new_app_components[original_doc_id] = component

            for doc_id in get_doc_ids_in_domain_by_class(self.name, FixtureDataType):
                if copy_by_id and doc_id not in copy_by_id:
                    continue
                component = self.copy_component(
                    'FixtureDataType', doc_id, new_domain_name, user=user)
                copy_data_items(doc_id, component._id)

            def convert_form_unique_id_function(form_unique_id):
                from corehq.apps.app_manager.models import FormBase
                form = FormBase.get_form(form_unique_id)
                form_app = form.get_app()
                m_index, f_index = form_app.get_form_location(form.unique_id)
                form_copy = new_app_components[form_app._id].get_module(m_index).get_form(f_index)
                return form_copy.unique_id

            if share_reminders:
                for rule in AutomaticUpdateRule.by_domain(
                    self.name,
                    AutomaticUpdateRule.WORKFLOW_SCHEDULING,
                    active_only=False,
                ):
                    rule.copy_conditional_alert(
                        new_domain_name,
                        convert_form_unique_id_function=convert_form_unique_id_function,
                    )
            if share_user_roles:
                for doc_id in get_doc_ids_in_domain_by_class(self.name, UserRole):
                    self.copy_component('UserRole', doc_id, new_domain_name, user=user)

        if user:
            def add_dom_to_user(user):
                user.add_domain_membership(new_domain_name, is_admin=True)
            apply_update(user, add_dom_to_user)

        return new_domain