Esempio n. 1
0
    def get_billable_domains(cls):
        marked_domains = SMSBillable.get_db().view('hqbilling/domains_marked_for_billing', reduce=False).all()

        prev_month, _ = HQMonthlyBill.get_default_start_end()

        recent = SMSBillable.get_db().view('hqbilling/domains_with_billables',
                                           startkey=[prev_month.year, prev_month.month],
                                           group=True,
                                           group_level=3).all()
        
        recent_counts = defaultdict(int)
        for r in recent:
            recent_counts[r['key'][-1]] += r['value']
        for m in marked_domains:
            if m['key'] not in recent_counts.keys():
                recent_counts[m['key']] = 0

        all_time = SMSBillable.get_db().view('hqbilling/domains_with_billables',
                                             group=True,
                                             group_level=3).all()
        all_time_counts = defaultdict(int)
        for a in all_time:
            if a['key'][-1] not in recent_counts.keys():
                all_time_counts[a['key'][-1]] += a['value']

        sorted_recent = sorted(recent_counts.iteritems(), key=operator.itemgetter(1), reverse=True)
        sorted_all_time = sorted(all_time_counts.iteritems(), key=operator.itemgetter(1), reverse=True)

        return [Domain.get_by_name(r[0]) for r in sorted_recent if r[0]] + \
               [Domain.get_by_name(a[0]) for a in sorted_all_time if a[0]]
Esempio n. 2
0
def tearDownModule():
    if settings.USE_PARTITIONED_DATABASE:
        return

    _call_center_domain_mock = mock.patch(
        'corehq.apps.callcenter.data_source.call_center_data_source_configuration_provider'
    )
    _call_center_domain_mock.start()
    with override_settings(SERVER_ENVIRONMENT='icds'):
        configs = StaticDataSourceConfiguration.by_domain('icds-cas')
        adapters = [get_indicator_adapter(config) for config in configs]
        for adapter in adapters:
            if adapter.config.table_id == 'static-child_health_cases':
                # hack because this is in a migration
                adapter.clear_table()
                continue
            adapter.drop_table()

        engine = connection_manager.get_engine(ICDS_UCR_ENGINE_ID)
        with engine.begin() as connection:
            metadata = sqlalchemy.MetaData(bind=engine)
            metadata.reflect(bind=engine, extend_existing=True)
            table = metadata.tables['ucr_table_name_mapping']
            delete = table.delete()
            connection.execute(delete)
    LocationType.objects.filter(domain='icds-cas').delete()
    SQLLocation.objects.filter(domain='icds-cas').delete()

    Domain.get_by_name('icds-cas').delete()
    _call_center_domain_mock.stop()
Esempio n. 3
0
    def test_dry_run(self):
        self.assertFalse(should_use_sql_backend(self.domain_name))
        call_command(
            'migrate_domain_from_couch_to_sql',
            self.domain_name,
            MIGRATE=True,
            no_input=True,
            dry_run=True
        )
        clear_local_domain_sql_backend_override(self.domain_name)
        with self.assertRaises(CommandError):
            call_command('migrate_domain_from_couch_to_sql', self.domain_name, COMMIT=True, no_input=True)
        self.assertFalse(Domain.get_by_name(self.domain_name).use_sql_backend)

        xml = """<?xml version="1.0" ?>
        <n0:registration xmlns:n0="http://openrosa.org/user/registration">
            <username>W4</username>
            <password>2</password>
            <uuid>P8DU7OLHVLZXU21JR10H3W8J2</uuid>
            <date>2013-11-19</date>
            <registering_phone_id>8H1N48EFPF6PA4UOO8YGZ2KFZ</registering_phone_id>
            <user_data>
                <data key="user_type">standard</data>
             </user_data>
        </n0:registration>
        """
        submit_form_locally(xml, self.domain_name)
        couch_form_ids = self._get_form_ids()
        self.assertEqual(1, len(couch_form_ids))

        call_command('migrate_domain_from_couch_to_sql', self.domain_name, blow_away=True, no_input=True)
        self.assertFalse(Domain.get_by_name(self.domain_name).use_sql_backend)
Esempio n. 4
0
    def clean_domain_name(self):
        data = self.cleaned_data['domain_name'].strip().lower()
        if not re.match("^%s$" % new_domain_re, data):
            raise forms.ValidationError('Only lowercase letters and numbers allowed. Single hyphens may be used to separate words.')

        conflict = Domain.get_by_name(data) or Domain.get_by_name(data.replace('-', '.'))
        if conflict:
            raise forms.ValidationError('Project name already taken---please try another')
        return data
Esempio n. 5
0
 def get_domain(domain):
     obj = Domain.get_by_name(domain)
     if obj:
         return obj
     else:
         # This could happen in when there is an issue with couch cluster
         #   that makes the obj not available
         time.sleep(5)
         return Domain.get_by_name(domain)
Esempio n. 6
0
    def aggregated_data(self, stock_states):
        product_aggregation = {}
        for state in stock_states:
            if state.product_id in product_aggregation:
                product = product_aggregation[state.product_id]
                product['current_stock'] = self.format_decimal(
                    product['current_stock'] + state.stock_on_hand
                )

                if product['total_consumption'] is None:
                    product['total_consumption'] = state.get_consumption()
                elif state.get_consumption() is not None:
                    product['total_consumption'] += state.get_consumption()

                product['count'] += 1

                if product['total_consumption'] is not None:
                    product['consumption'] = product['total_consumption'] / product['count']
                else:
                    product['consumption'] = None

                product['category'] = stock_category(
                    product['current_stock'],
                    product['consumption'],
                    Domain.get_by_name(self.domain)
                )
                product['months_remaining'] = months_of_stock_remaining(
                    product['current_stock'],
                    product['consumption']
                )
            else:
                product = Product.get(state.product_id)
                consumption = state.get_consumption()

                product_aggregation[state.product_id] = {
                    'product_id': product._id,
                    'location_id': None,
                    'product_name': product.name,
                    'location_lineage': None,
                    'resupply_quantity_needed': None,
                    'current_stock': self.format_decimal(state.stock_on_hand),
                    'total_consumption': consumption,
                    'count': 1,
                    'consumption': consumption,
                    'category': stock_category(
                        state.stock_on_hand,
                        consumption,
                        Domain.get_by_name(self.domain)
                    ),
                    'months_remaining': months_of_stock_remaining(
                        state.stock_on_hand,
                        consumption
                    )
                }

        return product_aggregation.values()
Esempio n. 7
0
    def aggregated_data(self, stock_states):
        def _convert_to_daily(consumption):
            return consumption / 30 if consumption is not None else None

        product_aggregation = {}
        for state in stock_states:
            if state.product_id in product_aggregation:
                product = product_aggregation[state.product_id]
                product['current_stock'] = format_decimal(
                    product['current_stock'] + state.stock_on_hand
                )

                consumption = state.get_monthly_consumption()
                if product['consumption'] is None:
                    product['consumption'] = consumption
                elif consumption is not None:
                    product['consumption'] += consumption

                product['count'] += 1

                product['category'] = stock_category(
                    product['current_stock'],
                    _convert_to_daily(product['consumption']),
                    Domain.get_by_name(self.domain)
                )
                product['months_remaining'] = months_of_stock_remaining(
                    product['current_stock'],
                    _convert_to_daily(product['consumption'])
                )
            else:
                product = Product.get(state.product_id)
                consumption = state.get_monthly_consumption()

                product_aggregation[state.product_id] = {
                    'product_id': product._id,
                    'location_id': None,
                    'product_name': product.name,
                    'location_lineage': None,
                    'resupply_quantity_needed': None,
                    'current_stock': format_decimal(state.stock_on_hand),
                    'count': 1,
                    'consumption': consumption,
                    'category': stock_category(
                        state.stock_on_hand,
                        _convert_to_daily(consumption),
                        Domain.get_by_name(self.domain)
                    ),
                    'months_remaining': months_of_stock_remaining(
                        state.stock_on_hand,
                        _convert_to_daily(consumption)
                    )
                }

        return product_aggregation.values()
Esempio n. 8
0
def tearDownModule():
    if isinstance(Domain.get_db(), Mock):
        # needed to skip setUp for javascript tests thread on Travis
        return

    _call_center_domain_mock = mock.patch(
        'corehq.apps.callcenter.data_source.call_center_data_source_configuration_provider'
    )
    _call_center_domain_mock.start()
    Domain.get_by_name('champ-cameroon').delete()
    _call_center_domain_mock.stop()
Esempio n. 9
0
 def tearDownClass(cls):
     delete_domain_phone_numbers(TEST_DOMAIN)
     CommCareUser.get_by_username('stella').delete()
     CommCareUser.get_by_username('super').delete()
     FacilityInCharge.objects.all().delete()
     LocationType.objects.all().delete()
     for product in Product.by_domain(TEST_DOMAIN):
         product.delete()
     SQLProduct.objects.all().delete()
     EWSGhanaConfig.for_domain(TEST_DOMAIN).delete()
     DocDomainMapping.objects.all().delete()
     Domain.get_by_name(TEST_DOMAIN).delete()
     super(EWSScriptTest, cls).tearDownClass()
Esempio n. 10
0
    def clean_domain_name(self):
        data = self.cleaned_data['domain_name'].strip().lower()
        if not re.match("^%s$" % new_domain_re, data):
            raise forms.ValidationError('Only lowercase letters and numbers allowed. Single hyphens may be used to separate words.')
        if 'org' in self.cleaned_data and self.cleaned_data['org']:
            org_name = self.cleaned_data['org']
            if Domain.get_by_organization_and_slug(org_name, data):
                raise forms.ValidationError('Project alias already exists in org --- please try another name')
            data = '{org_name}:{domain_name}'.format(org_name=org_name, domain_name=data)

        conflict = Domain.get_by_name(data) or Domain.get_by_name(data.replace('-', '.'))
        if conflict:
            raise forms.ValidationError('Project name already taken---please try another')
        return data
Esempio n. 11
0
 def tearDownClass(cls):
     CommCareUser.get_by_username("stella").delete()
     CommCareUser.get_by_username("super").delete()
     FacilityInCharge.objects.all().delete()
     delete_all_locations()
     LocationType.objects.all().delete()
     for product in Product.by_domain(TEST_DOMAIN):
         product.delete()
     SQLProduct.objects.all().delete()
     EWSGhanaConfig.for_domain(TEST_DOMAIN).delete()
     DocDomainMapping.objects.all().delete()
     generator.delete_all_subscriptions()
     cls.sms_backend_mapping.delete()
     cls.backend.delete()
     Domain.get_by_name(TEST_DOMAIN).delete()
Esempio n. 12
0
    def handle(self, domain_name, app_name, **options):
        try:
            Domain.get_by_name(domain_name)
        except ResourceNotFound:
            raise CommandError("Domain with name '{domain_name}' not found".format(
                domain_name=domain_name
            ))

        self.create_two_module_app(domain_name, app_name)

        if not getattr(settings, 'BASE_ADDRESS', None):
            print ("Warning: You must set BASE_ADDRESS setting "
                   "in your localsettings.py file in order for commcare-hq "
                   "to be able to generate absolute urls. "
                   "This is necessary for a number of features.")
Esempio n. 13
0
 def tearDownClass(cls):
     MobileBackend.load_by_name(TEST_DOMAIN, TEST_BACKEND).delete()
     CommCareUser.get_by_username('stella').delete()
     CommCareUser.get_by_username('super').delete()
     delete_all_locations()
     LocationType.objects.all().delete()
     for product in Product.by_domain(TEST_DOMAIN):
         product.delete()
     SQLProduct.objects.all().delete()
     EWSGhanaConfig.for_domain(TEST_DOMAIN).delete()
     DocDomainMapping.objects.all().delete()
     generator.delete_all_subscriptions()
     cls.sms_backend_mapping.delete()
     cls.backend.delete()
     Domain.get_by_name(TEST_DOMAIN).delete()
Esempio n. 14
0
def api_query_supply_point(request, domain):
    id = request.GET.get('id')
    query = request.GET.get('name', '')
    
    def loc_to_payload(loc):
        return {'id': loc._id, 'name': loc.name}

    if id:
        try:
            loc = Location.get(id)
            return HttpResponse(json.dumps(loc_to_payload(loc)), 'text/json')

        except ResourceNotFound:
            return HttpResponseNotFound(json.dumps({'message': 'no location with is %s found' % id}, 'text/json'))

    else:
        LIMIT = 100
        loc_types = [loc_type.name for loc_type in Domain.get_by_name(domain).commtrack_settings.location_types if not loc_type.administrative]

        def get_locs(type):
            # TODO use ES instead?
            q = query.lower()
            startkey = [domain, type, q]
            endkey = [domain, type, q + 'zzzzzz']
            return Location.view('locations/by_name',
                startkey=startkey,
                endkey=endkey,
                limit=LIMIT,
                reduce=False,
                include_docs=True,
            )

        locs = sorted(itertools.chain(*(get_locs(loc_type) for loc_type in loc_types)), key=lambda e: e.name)[:LIMIT]
        return HttpResponse(json.dumps(map(loc_to_payload, locs)), 'text/json')
Esempio n. 15
0
    def get_copy_ajax_response(self, rule, copy_to_project_name):
        if not self.allow_copy:
            return JsonResponse({
                'status': 'error',
                'error_msg': _("You do not have permission to copy alerts."),
            })

        destination_project = Domain.get_by_name(copy_to_project_name)
        if (
            destination_project is None or
            destination_project.is_snapshot or
            not self.request.couch_user.has_permission(copy_to_project_name, 'edit_data')
        ):
            return JsonResponse({
                'status': 'error',
                'error_msg': _("Destination project not found."),
            })

        # Use the same copy method as the exchange uses, which will
        # return None if the rule can't be copied, otherwise will
        # copy the rule as inactive.
        copied_rule = rule.copy_conditional_alert(copy_to_project_name, allow_custom_references=True)
        if copied_rule is None:
            return JsonResponse({
                'status': 'error',
                'error_msg': _("This rule includes references that cannot be copied."),
            })

        initiate_messaging_rule_run(copied_rule.domain, copied_rule.pk)
        return JsonResponse({
            'status': 'success',
            'rule': self._format_rule_for_json(rule),
        })
    def handle(self, *args, **options):
        domains = Domain.get_all()
        seen = set([])
        dups = set([])
        for domain in domains:
            if domain.name in seen:
                dups.add(domain.name)
            else:
                seen.add(domain.name)

        if not dups:
            self.stdout.write('Found no duplicate domains\n')

        for domain in list(dups):
            real_dom = Domain.get_by_name(domain)
            total_doms = Domain.view("domain/domains",
                key=domain,
                reduce=False,
                include_docs=True,
            ).all()
            fake_doms = [d for d in total_doms if d.get_id != real_dom.get_id]

            self.stdout.write('Found Dup: %s\n' % domain)
            self.stdout.write(" -- _id of correct domain: %s\n" % real_dom.get_id)
            self.stdout.write(" -- ids of duplicate domains: %s\n" % [d.get_id for d in fake_doms])

            for dom in fake_doms:
                dom.doc_type = 'Domain-DUPLICATE'
                dom.save()
Esempio n. 17
0
def get_app_build(app_dict):
    domain = Domain.get_by_name(app_dict["domain"])
    if domain.use_cloudcare_releases:
        return ApplicationBase.get(app_dict["_id"]).get_latest_app()["_id"]
    else:
        return ApplicationBase.get_latest_build(app_dict["domain"], app_dict["_id"])["_id"]
    return None
Esempio n. 18
0
def chat_contacts(request, domain):
    domain_obj = Domain.get_by_name(domain, strict=True)
    verified_numbers = VerifiedNumber.by_domain(domain)
    contacts = []
    for vn in verified_numbers:
        owner = vn.owner
        if owner is not None and owner.doc_type in ('CommCareCase','CommCareUser'):
            if owner.doc_type == "CommCareUser":
                url = reverse(EditCommCareUserView.urlname, args=[domain, owner._id])
                name = owner.raw_username
            else:
                url = reverse("case_details", args=[domain, owner._id])
                if domain_obj.custom_case_username:
                    name = owner.get_case_property(domain_obj.custom_case_username) or _("(unknown)")
                else:
                    name = owner.name
            contacts.append({
                "id" : owner._id,
                "doc_type" : owner.doc_type,
                "url" : url,
                "name" : name,
            })
    context = {
        "domain" : domain,
        "contacts" : contacts,
    }
    return render(request, "sms/chat_contacts.html", context)
Esempio n. 19
0
def chat(request, domain, contact_id):
    domain_obj = Domain.get_by_name(domain, strict=True)
    timezone = report_utils.get_timezone(None, domain)

    # floored_utc_timestamp is the datetime in UTC representing
    # midnight today in local time. This is used to calculate
    # all message history choices' timestamps, so that choosing
    # "Yesterday", for example, gives you data from yesterday at
    # midnight local time.
    local_date = datetime.now(timezone).date()
    floored_utc_timestamp = tz_utils.adjust_datetime_to_timezone(
        datetime.combine(local_date, time(0,0)),
        timezone.zone,
        pytz.utc.zone
    ).replace(tzinfo=None)

    def _fmt(d):
        return json_format_datetime(floored_utc_timestamp - timedelta(days=d))
    history_choices = [(_(x), _fmt(y)) for (x, y) in SMS_CHAT_HISTORY_CHOICES]
    history_choices.append(
        (_("All Time"), json_format_datetime(datetime(1970, 1, 1)))
    )

    context = {
        "domain" : domain,
        "contact_id" : contact_id,
        "contact" : get_contact(contact_id),
        "message_count_threshold" : domain_obj.chat_message_count_threshold or DEFAULT_MESSAGE_COUNT_THRESHOLD,
        "custom_case_username" : domain_obj.custom_case_username,
        "history_choices" : history_choices,
    }
    template = settings.CUSTOM_CHAT_TEMPLATES.get(domain_obj.custom_chat_template) or "sms/chat.html"
    return render(request, template, context)
Esempio n. 20
0
def sync_location_supply_point(loc):
    """
    This method syncs the location/supply point connection
    and is triggered whenever a location is edited or created.
    """
    # circular import
    from corehq.apps.domain.models import Domain

    domain = Domain.get_by_name(loc.domain)
    if not domain.commtrack_enabled:
        return

    def _needs_supply_point(loc, domain):
        """Exclude administrative-only locs"""
        return loc.location_type in [loc_type.name for loc_type in domain.location_types if not loc_type.administrative]

    if _needs_supply_point(loc, domain):
        supply_point = SupplyPointCase.get_by_location(loc)
        if supply_point:
            supply_point.update_from_location(loc)
            updated_supply_point = supply_point
        else:
            updated_supply_point = SupplyPointCase.create_from_location(loc.domain, loc)

        # need to sync this sp change to the sql location
        # but saving the doc will trigger a loop
        try:
            sql_loc = SQLLocation.objects.get(location_id=loc._id)
            sql_loc.supply_point_id = updated_supply_point._id
            sql_loc.save()
        except SQLLocation.DoesNotExist:
            pass
Esempio n. 21
0
def internal_settings(request, domain, template='domain/internal_settings.html'):
    domain = Domain.get_by_name(domain)

    if request.method == 'POST':
        internal_form = DomainInternalForm(request.POST)
        if internal_form.is_valid():
            internal_form.save(domain)
            messages.success(request, "The internal information for project %s was successfully updated!" % domain.name)
        else:
            messages.error(request, "There seems to have been an error. Please try again!")
    else:
        internal_form = DomainInternalForm(initial={
            "sf_contract_id": domain.internal.sf_contract_id,
            "sf_account_id": domain.internal.sf_account_id,
            "commcare_edition": domain.internal.commcare_edition,
            "services": domain.internal.services,
            "real_space": 'true' if domain.internal.real_space else 'false',
            "initiative": domain.internal.initiative,
            "project_state": domain.internal.project_state,
            "self_started": 'true' if domain.internal.self_started else 'false',
            "area": domain.internal.area,
            "sub_area": domain.internal.sub_area,
            "using_adm": 'true' if domain.internal.using_adm else 'false',
            "using_call_center": 'true' if domain.internal.using_call_center else 'false',
            "custom_eula": 'true' if domain.internal.custom_eula else 'false',
            "can_use_data": 'true' if domain.internal.can_use_data else 'false',
            "organization_name": domain.internal.organization_name,
            "notes": domain.internal.notes,
        })

    return render(request, template, {"project": domain, "domain": domain.name, "form": internal_form, 'active': 'settings'})
Esempio n. 22
0
def orgs_team_members(request, org, team_id, template="orgs/orgs_team_members.html"):
    class TeamMembersNotification(Notification):
        doc_type = 'OrgTeamMembersNotification'

        def template(self):
            return 'orgs/partials/team_members_notification.html'

    MainNotification.display_if_needed(messages, request, ctxt={"org": request.organization})
    TeamMembersNotification.display_if_needed(messages, request)

    ctxt = base_context(request, request.organization)
    ctxt["tab"] = "teams"

    try:
        team = Team.get(team_id)
    except ResourceNotFound:
        raise Http404("Team %s does not exist" % team_id)

    team_members = team.get_members()
    team_members.sort(key=lambda user: user.username)

    #inspect the domains of the team
    domain_names = team.get_domains()
    team_domains = list()
    for name in domain_names:
        team_domains.append([Domain.get_by_name(name), team.role_label(domain=name), UserRole.by_domain(name)])

    nonmembers = filter(lambda m: m.username not in [tm.username for tm in team_members], ctxt["members"])
    nondomains = filter(lambda d: d.name not in [td[0].name for td in team_domains], ctxt["domains"])

    ctxt.update(dict(team=team, team_members=team_members, nonmembers=nonmembers,
                     team_domains=team_domains, nondomains=nondomains))
    return render(request, template, ctxt)
Esempio n. 23
0
def create_user_and_domain(username='******', 
                           password='******',
                           domain_name='mockdomain'):
    """Creates a domain 'mockdomain' and a web user with name/pw 
       'brian'/'test'.  Returns these two objects in a tuple 
       as (domain, user).  The parameters are configurable."""
    try:
        domain = Domain.get_by_name(domain_name)
        print "WARNING: tried to create domain %s but it already exists!" % domain_name
        print "Are all your tests cleaning up properly?"
    except Domain.DoesNotExist:
        # this is the normal case
        domain = Domain(name=domain_name, is_active=True)
        domain.save()
    
    try:
        user = User.objects.get(username=username)
        print "WARNING: tried to create user %s but it already exists!" % username
        print "Are all your tests cleaning up properly?"
        # update the pw anyway
        user.password = _get_salted_pw(password)
        user.save()
    except User.DoesNotExist:
        user = User()
        user.username = username
        # here, we mimic what the django auth system does
        # only we specify the salt to be 12345
        user.password = _get_salted_pw(password)
        
        user.save()
        
    return (user, domain)
Esempio n. 24
0
def update_domains(request):
    if request.method == "POST":
        try:
            workbook = WorkbookJSONReader(request.file)
            domains = workbook.get_worksheet(title="domains")
            success_count = 0
            fail_count = 0
            for row in domains:
                try:
                    name = row["name"]
                    domain = Domain.get_by_name(name)
                    if domain:
                        for k, v in row.items():
                            setattr(domain, k, v)
                        domain.save()
                        success_count += 1
                    else:
                        messages.warning(request, "No domain with name %s found" % name)
                        fail_count += 1
                except Exception, e:
                    messages.warning(request, "Update for %s failed: %s" % (row.get("name", "<No Name>"), e))
                    fail_count += 1
            if success_count:
                messages.success(request, "%s domains successfully updated" % success_count)
            if fail_count:
                messages.error(request, "%s domains had errors. details above." % fail_count)

        except Exception, e:
            messages.error(request, "Something went wrong! Update failed. Here's your error: %s" % e)
    def handle(self, filename, **options):
        domain = options["domain"]
        user = options["user"]
        display_superuser = options["display_superuser"]

        dimagi_username = ""
        if not display_superuser:
            dimagi_username = "******"

        if not domain and not user:
            raise CommandError("Please provide one of 'domain' or 'user'")

        if domain:
            domain_object = Domain.get_by_name(domain)
            if not domain_object:
                raise CommandError("Domain not found")

        users, super_users = get_users_to_export(user, domain)

        with open(filename, 'wb') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerow(['Date', 'User', 'Domain', 'IP Address', 'Request Path'])
            for user in users:
                write_log_events(
                    writer, user, domain,
                    start_date=options['start'], end_date=options['end']
                )

            for user in super_users:
                write_log_events(
                    writer, user, domain,
                    override_user=dimagi_username,
                    start_date=options['start'], end_date=options['end']
                )
Esempio n. 26
0
 def clean_domain(self):
     domain_name = self.cleaned_data['domain']
     if self.fields['domain'].required:
         domain = Domain.get_by_name(domain_name)
         if domain is None:
             raise forms.ValidationError("A valid project space is required.")
     return domain_name
Esempio n. 27
0
def get_restore_response(domain, couch_user, app_id=None, since=None, version='1.0',
                         state=None, items=False, force_cache=False,
                         cache_timeout=None, overwrite_cache=False,
                         force_restore_mode=None):
    # not a view just a view util
    if not couch_user.is_commcare_user():
        return HttpResponse("No linked chw found for %s" % couch_user.username,
                            status=401)  # Authentication Failure
    elif domain != couch_user.domain:
        return HttpResponse("%s was not in the domain %s" % (couch_user.username, domain),
                            status=401)

    project = Domain.get_by_name(domain)
    app = get_app(domain, app_id) if app_id else None
    restore_config = RestoreConfig(
        project=project,
        user=couch_user.to_casexml_user(),
        params=RestoreParams(
            sync_log_id=since,
            version=version,
            state_hash=state,
            include_item_count=items,
            force_restore_mode=force_restore_mode,
            app=app,
        ),
        cache_settings=RestoreCacheSettings(
            force_cache=force_cache,
            cache_timeout=cache_timeout,
            overwrite_cache=overwrite_cache
        ),
    )
    return restore_config.get_response()
Esempio n. 28
0
def dump_users_and_groups(response, domain):
    def _load_memoizer(domain):
        group_memoizer = GroupMemoizer(domain=domain)
        # load groups manually instead of calling group_memoizer.load_all()
        # so that we can detect blank groups
        blank_groups = set()
        for group in Group.by_domain(domain):
            if group.name:
                group_memoizer.add_group(group)
            else:
                blank_groups.add(group)
        if blank_groups:
            raise GroupNameError(blank_groups=blank_groups)

        return group_memoizer

    export_file = StringIO()
    writer = Excel2007ExportWriter()
    group_memoizer = _load_memoizer(domain)
    location_cache = LocationIdToSiteCodeCache(domain)

    user_data_model = CustomDataFieldsDefinition.get_or_create(
        domain,
        UserFieldsView.field_type
    )

    user_headers, user_rows = parse_users(
        group_memoizer,
        domain,
        user_data_model,
        location_cache
    )

    group_headers, group_rows = parse_groups(group_memoizer.groups)
    headers = [
        ('users', [user_headers]),
        ('groups', [group_headers]),
    ]
    rows = [
        ('users', user_rows),
        ('groups', group_rows),
    ]

    domain_obj = Domain.get_by_name(domain)
    # This is only for domains using the multiple locations feature flag
    if domain_obj.commtrack_enabled and domain_obj.supports_multiple_locations_per_user:
        headers.append(
            ('locations', [['username', 'location-sms-code', 'location name (optional)']])
        )
        rows.append(
            ('locations', get_location_rows(domain))
        )

    writer.open(
        header_table=headers,
        file=export_file,
    )
    writer.write(rows)
    writer.close()
    response.write(export_file.getvalue())
Esempio n. 29
0
def redirect_to_default(req, domain=None):
    if not req.user.is_authenticated():
        if domain != None:
            url = reverse('domain_login', args=[domain])
        else:
            # this actually gets hijacked by the static site, but is necessary
            url = reverse('corehq.apps.hqwebapp.views.landing_page')
    else:
        if domain:
            domain = normalize_domain_name(domain)
            domains = [Domain.get_by_name(domain)]
        else:
            domains = Domain.active_for_user(req.user)
        if 0 == len(domains) and not req.user.is_superuser:
            return redirect('registration_domain')
        elif 1 == len(domains):
            if domains[0]:
                domain = domains[0].name
                if req.couch_user.is_commcare_user():
                    if not is_mobile_worker_with_report_access(
                            req.couch_user, domain):
                        url = reverse("cloudcare_main", args=[domain, ""])
                    else:
                        url = reverse("saved_reports", args=[domain])
                elif req.couch_user.can_view_reports(domain) or req.couch_user.get_viewable_reports(domain):
                    url = reverse('corehq.apps.reports.views.default', args=[domain])
                else:
                    url = reverse('corehq.apps.app_manager.views.default', args=[domain])
            else:
                raise Http404
        else:
            url = settings.DOMAIN_SELECT_URL
    return HttpResponseRedirect(url)
Esempio n. 30
0
def fallback_handler(v, text, msg):
    domain_obj = Domain.get_by_name(v.domain, strict=True)
    default_workflow_meta = MessageMetadata(workflow=WORKFLOW_DEFAULT, location_id=msg.location_id)
    if domain_obj.use_default_sms_response and domain_obj.default_sms_response:
        send_sms_to_verified_number(v, domain_obj.default_sms_response, metadata=default_workflow_meta)
    add_msg_tags(msg, default_workflow_meta)
    return True
Esempio n. 31
0
 def tearDown(self):
     Domain.get_by_name(TEST_DOMAIN).delete()
 def obj_get(self, bundle, **kwargs):
     domain = Domain.get_by_name(kwargs.get('domain'))
     if domain is None:
         raise NotFound
     return domain
Esempio n. 33
0
def new_update_case_properties():
    _domain = Domain.get_by_name(DOMAINS[0])
    if _domain is None:
        return
    time_zone = _domain.get_default_timezone()
    past_21_date = past_x_date(time_zone, 21)
    past_42_date = past_x_date(time_zone, 42)
    setup_indices()
    for domain in DOMAINS:
        case_list = list(get_cases_in_domain(domain, type=BIRTH_TYPE))
        case_list = case_list + list(
            get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE))
        cases_to_modify = []
        for case in case_list:
            if case.closed:
                continue
            if not get_none_or_value(
                    case, "owner_id") or not get_none_or_value(
                        case, "date_admission") or not get_none_or_value(
                            case, "facility_id"):
                continue
            curr_assignment = get_none_or_value(case, "current_assignment")
            next_assignment = get_none_or_value(case, "next_assignment")
            facility_id = get_none_or_value(case, "facility_id")
            fida_group = get_group_id(domain, "fida", facility_id)

            # get cati_owner_username from current owner-group
            assigned_owner_group = get_none_or_value(case, "owner_id")
            if assigned_owner_group not in GROUPS_BY_ID[domain]:
                continue
            cati_owner_username = GROUPS_BY_ID[domain][
                assigned_owner_group].metadata.get('main_user', None)

            # Assignment Directly from Registration ##
            # Assign Cases to Call Center
            if case.date_admission >= past_21_date and (
                    not curr_assignment) and (not next_assignment):
                owner_id = get_group_id(domain, "cati", facility_id)
                if not owner_id:
                    continue
                owner_group = GROUPS_BY_ID[domain].get(owner_id, None)
                cati_name = owner_group.metadata.get(
                    'name', None) if owner_group else None
                update = {"current_assignment": "cati", "cati_name": cati_name}
                cases_to_modify.append({
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": owner_id,
                })
            # Assign Cases Directly To Field
            elif (case.date_admission >=
                  past_42_date) and (case.date_admission < past_21_date) and (
                      not curr_assignment) and (not next_assignment):
                if not fida_group:
                    continue
                update = {
                    "current_assignment": "fida",
                    "cati_status": 'skipped',
                }
                cases_to_modify.append({
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": fida_group,
                })
Esempio n. 34
0
    def _is_safe_to_modify(form):
        if form.domain != domain:
            return False

        case_ids = get_case_ids_from_form(form)
        # all cases touched by the form and not already modified
        for case in CaseAccessors(domain).iter_cases(case_ids -
                                                     modified_cases):
            if case.is_deleted != is_deletion:
                # we can't delete/undelete this form - this would change the state of `case`
                return False

        # all cases touched by this form are deleted
        return True

    if is_deletion or Domain.get_by_name(domain).use_sql_backend:
        all_forms = FormAccessors(domain).iter_forms(form_ids_to_modify)
    else:
        # accessor.iter_forms doesn't include deleted forms on the couch backend
        all_forms = list(
            map(FormAccessors(domain).get_form, form_ids_to_modify))
    return [form.form_id for form in all_forms if _is_safe_to_modify(form)]


@task(serializer='pickle',
      queue='background_queue',
      ignore_result=True,
      acks_late=True)
def tag_system_forms_as_deleted(domain, deleted_forms, deleted_cases,
                                deletion_id, deletion_date):
    to_delete = _get_forms_to_modify(domain,
Esempio n. 35
0
def confirm_domain(request, guid=None):
    # Did we get a guid?
    vals = {}
    if guid is None:
        vals['message_title'] = _('Missing Activation Key')
        vals['message_subtitle'] = _('Account Activation Failed')
        vals['message_body'] = _(
            'An account activation key was not provided.  If you think this '
            'is an error, please contact the system administrator.')
        vals['is_error'] = True
        return render(request, 'registration/confirmation_complete.html', vals)

    # Does guid exist in the system?
    req = RegistrationRequest.get_by_guid(guid)
    if not req:
        vals['message_title'] = _('Invalid Activation Key')
        vals['message_subtitle'] = _('Account Activation Failed')
        vals['message_body'] = _(
            'The account activation key "%s" provided is invalid. If you '
            'think this is an error, please contact the system '
            'administrator.') % guid
        vals['is_error'] = True
        return render(request, 'registration/confirmation_complete.html', vals)

    requested_domain = Domain.get_by_name(req.domain)
    context = get_domain_context(requested_domain.domain_type)
    context['requested_domain'] = req.domain

    # Has guid already been confirmed?
    if requested_domain.is_active:
        assert (req.confirm_time is not None and req.confirm_ip is not None)
        context['message_title'] = _('Already Activated')
        context['message_body'] = _(
            'Your account %s has already been activated. No further '
            'validation is required.') % req.new_user_username
        context['is_error'] = False
        return render(request, 'registration/confirmation_complete.html',
                      context)

    # Set confirm time and IP; activate domain and new user who is in the
    req.confirm_time = datetime.utcnow()
    req.confirm_ip = get_ip(request)
    req.save()
    requested_domain.is_active = True
    requested_domain.save()
    requesting_user = WebUser.get_by_username(req.new_user_username)

    send_new_request_update_email(requesting_user,
                                  get_ip(request),
                                  requested_domain.name,
                                  is_confirming=True)

    context['message_title'] = _('Account Confirmed')
    context['message_subtitle'] = _(
        'Thank you for activating your account, %s!'
    ) % requesting_user.first_name
    context['message_body'] = _(
        'Your account has been successfully activated.  Thank you for taking '
        'the time to confirm your email address: %s.'
    ) % requesting_user.username
    context['is_error'] = False
    return render(request, 'registration/confirmation_complete.html', context)
Esempio n. 36
0
    def handle(self, *args, **options):
        if len(args) not in [2, 3]:
            raise CommandError('Usage is copy_domain %s' % self.args)
        self.exclude_dbs = (
            # these have data we don't want to copy
            'receiverwrapper',
            'couchlog',
            'auditcare',
            'fluff-bihar',
            'fluff-opm',
            'fluff-mc',
            'fluff-cvsu',
            'mvp-indicators',
            'm4change',
            # todo: missing domain/docs, but probably want to add back
            'meta',
        )
        self.source_couch = source_couch = CouchConfig(args[0])
        domain = args[1].strip()
        simulate = options['simulate']
        exclude_attachments = options['exclude_attachments']
        self.run_multi_process = options['run_multi_process']

        since = json_format_date(iso_string_to_date(
            options['since'])) if options['since'] else None

        if options['list_types']:
            for sourcedb_name, sourcedb in self.iter_source_dbs():
                self.list_types(sourcedb, domain, since)
            sys.exit(0)

        if simulate:
            print "\nSimulated run, no data will be copied.\n"

        if options['postgres_db'] and options['postgres_password']:
            settings.DATABASES[options['postgres_db']]['PASSWORD'] = options[
                'postgres_password']

        self.targetdb = CouchConfig(
            args[2]) if len(args) == 3 else CouchConfig()

        try:
            domain_doc = Domain.get_by_name(domain)
        except ResourceNotFound:
            domain_doc = None

        if domain_doc is None:
            self.copy_domain(source_couch, domain)

        if options['doc_types']:
            doc_types = options['doc_types'].split(',')
            for doc_type in doc_types:
                sourcedb = source_couch.get_db_for_doc_type(doc_type)
                startkey = [
                    x for x in [domain, doc_type, since] if x is not None
                ]
                endkey = [x for x in [domain, doc_type, {}] if x is not None]
                self.copy_docs(sourcedb,
                               domain,
                               simulate,
                               startkey,
                               endkey,
                               doc_type=doc_type,
                               since=since,
                               postgres_db=options['postgres_db'],
                               exclude_attachments=exclude_attachments)
        elif options['id_file']:
            path = options['id_file']
            if not os.path.isfile(path):
                print "Path '%s' does not exist or is not a file" % path
                sys.exit(1)

            with open(path) as input:
                doc_ids = [line.rstrip('\n') for line in input]

            if not doc_ids:
                print "Path '%s' does not contain any document ID's" % path
                sys.exit(1)

            for sourcedb_name, sourcedb in self.iter_source_dbs():
                self.copy_docs(sourcedb,
                               domain,
                               simulate,
                               doc_ids=doc_ids,
                               postgres_db=options['postgres_db'],
                               exclude_attachments=exclude_attachments)
        else:
            startkey = [domain]
            endkey = [domain, {}]
            exclude_types = DEFAULT_EXCLUDE_TYPES + options[
                'doc_types_exclude'].split(',')
            for sourcedb_name, sourcedb in self.iter_source_dbs():
                self.copy_docs(sourcedb,
                               domain,
                               simulate,
                               startkey,
                               endkey,
                               exclude_types=exclude_types,
                               postgres_db=options['postgres_db'],
                               exclude_attachments=exclude_attachments)
Esempio n. 37
0
def _get_domain_apps(domain):
    return Domain.get_by_name(domain).applications()
Esempio n. 38
0
 def domain_obj(self, domain_name):
     return Domain.get_by_name(domain_name)
Esempio n. 39
0
def load_domain(req, domain):
    domain_name = normalize_domain_name(domain)
    domain = Domain.get_by_name(domain_name)
    req.project = domain
    return domain_name, domain
Esempio n. 40
0
def process_sms(queued_sms_pk):
    """
    queued_sms_pk - pk of a QueuedSMS entry
    """
    utcnow = get_utcnow()
    # Prevent more than one task from processing this SMS, just in case
    # the message got enqueued twice.
    message_lock = get_lock("sms-queue-processing-%s" % queued_sms_pk)

    if message_lock.acquire(blocking=False):
        try:
            msg = QueuedSMS.objects.get(pk=queued_sms_pk)
        except QueuedSMS.DoesNotExist:
            # The message was already processed and removed from the queue
            release_lock(message_lock, True)
            return

        if message_is_stale(msg, utcnow):
            msg.set_system_error(SMS.ERROR_MESSAGE_IS_STALE)
            remove_from_queue(msg)
            release_lock(message_lock, True)
            return

        outbound_counter = None
        if msg.direction == OUTGOING:
            domain_object = Domain.get_by_name(
                msg.domain) if msg.domain else None

            if domain_object and handle_domain_specific_delays(
                    msg, domain_object, utcnow):
                release_lock(message_lock, True)
                return

            outbound_counter = OutboundDailyCounter(domain_object)
            if not outbound_counter.can_send_outbound_sms(msg):
                release_lock(message_lock, True)
                return

        requeue = False
        # Process inbound SMS from a single contact one at a time
        recipient_block = msg.direction == INCOMING

        # We check datetime_to_process against utcnow plus a small amount
        # of time because timestamps can differ between machines which
        # can cause us to miss sending the message the first time and
        # result in an unnecessary delay.
        if (isinstance(msg.processed, bool) and not msg.processed
                and not msg.error and msg.datetime_to_process <
            (utcnow + timedelta(seconds=10))):
            if recipient_block:
                recipient_lock = get_lock("sms-queue-recipient-phone-%s" %
                                          msg.phone_number)
                recipient_lock.acquire(blocking=True)

            if msg.direction == OUTGOING:
                if (msg.domain and msg.couch_recipient_doc_type
                        and msg.couch_recipient and not is_contact_active(
                            msg.domain, msg.couch_recipient_doc_type,
                            msg.couch_recipient)):
                    msg.set_system_error(SMS.ERROR_CONTACT_IS_INACTIVE)
                    remove_from_queue(msg)
                else:
                    requeue = handle_outgoing(msg)
            elif msg.direction == INCOMING:
                try:
                    handle_incoming(msg)
                except DelayProcessing:
                    process_sms.apply_async([queued_sms_pk], countdown=60)
                    if recipient_block:
                        release_lock(recipient_lock, True)
                    release_lock(message_lock, True)
            else:
                msg.set_system_error(SMS.ERROR_INVALID_DIRECTION)
                remove_from_queue(msg)

            if recipient_block:
                release_lock(recipient_lock, True)

        release_lock(message_lock, True)
        if requeue:
            if outbound_counter:
                outbound_counter.decrement()
            send_to_sms_queue(msg)
Esempio n. 41
0
 def project(self):
     return Domain.get_by_name(self.domain)
Esempio n. 42
0
 def commtrack_enabled(self):
     return Domain.get_by_name(self.domain).commtrack_enabled
Esempio n. 43
0
def logo(request, domain):
    logo = Domain.get_by_name(domain).get_custom_logo()
    if logo is None:
        raise Http404()

    return HttpResponse(logo[0], content_type=logo[1])
Esempio n. 44
0
 def odata_feed_limit(self):
     domain_object = Domain.get_by_name(self.domain)
     return domain_object.odata_feed_limit or settings.DEFAULT_ODATA_FEED_LIMIT
    def handle(self, domain, filename, **options):
        domain_obj = Domain.get_by_name(domain)
        if domain_obj is None:
            raise CommandError("Project space '%s' not found" % domain)

        json_rules = []
        with open(filename, 'r', encoding='utf-8') as f:
            for line in f:
                json_rules.append(json.loads(line))

        print("Importing %s rules..." % len(json_rules))

        rules = []
        with transaction.atomic():
            for entry in json_rules:
                json_rule = SimpleSchedulingRule(entry['rule'])

                schedule_type = entry['schedule']['schedule_type']
                if schedule_type == SIMPLE_SMS_DAILY_SCHEDULE_WITH_TIME:
                    json_schedule = SimpleSMSDailyScheduleWithTime(
                        entry['schedule'])
                    schedule = TimedSchedule.create_simple_daily_schedule(
                        domain,
                        TimedEvent(time=json_schedule.time),
                        SMSContent(message=json_schedule.message),
                        total_iterations=json_schedule.total_iterations,
                        start_offset=json_schedule.start_offset,
                        start_day_of_week=json_schedule.start_day_of_week,
                        extra_options=json_schedule.extra_options.to_json(),
                        repeat_every=json_schedule.repeat_every,
                    )
                elif schedule_type == SIMPLE_SMS_ALERT_SCHEDULE:
                    json_schedule = SimpleSMSAlertSchedule(entry['schedule'])
                    schedule = AlertSchedule.create_simple_alert(
                        domain,
                        SMSContent(message=json_schedule.message),
                        extra_options=json_schedule.extra_options.to_json(),
                    )
                else:
                    raise CommandError("Unexpected schedule_type: %s" %
                                       schedule_type)

                rule = AutomaticUpdateRule.objects.create(
                    domain=domain,
                    name=json_rule.name,
                    case_type=json_rule.case_type,
                    active=True,
                    filter_on_server_modified=False,
                    workflow=AutomaticUpdateRule.WORKFLOW_SCHEDULING,
                )

                for criterion in json_rule.criteria:
                    rule.add_criteria(
                        MatchPropertyDefinition,
                        property_name=criterion.property_name,
                        property_value=criterion.property_value,
                        match_type=criterion.match_type,
                    )

                rule.add_action(
                    CreateScheduleInstanceActionDefinition,
                    alert_schedule_id=schedule.schedule_id if isinstance(
                        schedule, AlertSchedule) else None,
                    timed_schedule_id=schedule.schedule_id if isinstance(
                        schedule, TimedSchedule) else None,
                    recipients=json_rule.recipients,
                    reset_case_property_name=json_rule.
                    reset_case_property_name,
                    start_date_case_property=json_rule.
                    start_date_case_property,
                    specific_start_date=json_rule.specific_start_date,
                    scheduler_module_info=json_rule.scheduler_module_info.
                    to_json(),
                )

                rules.append(rule)

        print("Import complete. Starting instance refresh tasks...")

        for rule in rules:
            initiate_messaging_rule_run(rule)

        print("Done.")
Esempio n. 46
0
def first_domain_for_user(domain):
    domain_obj = Domain.get_by_name(domain)
    if domain_obj:
        return domain_obj.first_domain_for_user
    return None
Esempio n. 47
0
def location_hierarchy_config(domain):
    return [(loc_type.name,
             [loc_type.parent_type.name if loc_type.parent_type else None])
            for loc_type in Domain.get_by_name(domain).location_types]
Esempio n. 48
0
def _get_report_module_context(app, module):
    def _report_to_config(report):
        return {
            'report_id':
            report._id,
            'title':
            report.title,
            'description':
            report.description,
            'charts':
            [chart for chart in report.charts if chart.type == 'multibar'],
            'filter_structure':
            report.filters_without_prefilters,
        }

    all_reports = ReportConfiguration.by_domain(app.domain) + \
                  StaticReportConfiguration.by_domain(app.domain)
    validity = module.check_report_validity()

    # We're now proactively deleting these references, so after that's been
    # out for a while, this can be removed (say June 2016 or later)
    if not validity.is_valid:
        module.report_configs = validity.valid_report_configs

    filter_choices = [{
        'slug': f.doc_type,
        'description': f.short_description
    } for f in get_all_mobile_filter_configs()]
    auto_filter_choices = [{
        'slug': f.slug,
        'description': f.short_description
    } for f in get_auto_filter_configurations()]
    from corehq.apps.app_manager.suite_xml.features.mobile_ucr import get_column_xpath_client_template, get_data_path
    data_path_placeholders = {}
    for r in module.report_configs:
        data_path_placeholders[r.report_id] = {}
        for chart_id in r.complete_graph_configs.keys():
            data_path_placeholders[r.report_id][chart_id] = get_data_path(
                r, app.domain)

    context = {
        'report_module_options': {
            'moduleName':
            module.name,
            'moduleFilter':
            module.module_filter,
            'availableReports':
            [_report_to_config(r)
             for r in all_reports],  # structure for all reports
            'currentReports': [r.to_json() for r in module.report_configs
                               ],  # config data for app reports
            'columnXpathTemplate':
            get_column_xpath_client_template(app.mobile_ucr_restore_version),
            'dataPathPlaceholders':
            data_path_placeholders,
            'languages':
            app.langs,
            'supportSyncDelay':
            app.mobile_ucr_restore_version != MOBILE_UCR_VERSION_1,
            'globalSyncDelay':
            Domain.get_by_name(app.domain).default_mobile_ucr_sync_interval,
        },
        'static_data_options': {
            'filterChoices':
            filter_choices,
            'autoFilterChoices':
            auto_filter_choices,
            'dateRangeOptions':
            [choice._asdict() for choice in get_simple_dateranges()],
        },
    }
    return context
Esempio n. 49
0
    def handle(self):
        domain = Domain.get_by_name(self.domain)
        split_text = self.msg.text.split(' ', 1)
        if split_text[0].lower() == 'soh':
            text = split_text[1]
        elif split_text[0].startswith('soh'):
            text = split_text[0][3:]
        else:
            text = self.msg.text

        if not domain.commtrack_enabled:
            return False

        if not self.sql_location:
            self.respond(NO_SUPPLY_POINT_MESSAGE)
            return True

        try:
            parser = self.parser
            formatted_text = EWSFormatter().format(text)
            data = parser.parse(formatted_text)
            if not data:
                return False
            if EWS_INVALID_REPORT_RESPONSE.enabled(self.domain):
                filtered_transactions = self.get_valid_reports(data)

                if not filtered_transactions:
                    return True

                data['transactions'] = filtered_transactions

        except NotAUserClassError:
            return False
        except (SMSError, NoDefaultLocationException):
            self.respond(six.text_type(INVALID_MESSAGE))
            return True
        except ProductCodeException as e:
            self.respond(six.text_type(e))
            return True
        except Exception as e:
            if settings.UNIT_TESTING or settings.DEBUG:
                raise
            self.respond('problem with stock report: %s' % str(e))
            return True

        stockouts = set()
        if self.sql_location.location_type.name in [
                'Regional Medical Store', 'Central Medical Store'
        ]:
            stockouts = set(
                StockState.objects.filter(
                    case_id=self.sql_location.supply_point_id,
                    stock_on_hand=0).values_list('sql_product__name',
                                                 flat=True))

        process(domain.name, data)
        transactions = data['transactions']

        if not self.async_response:
            self.send_messages(parser, stockouts, transactions)
        else:
            send_soh_messages_task.delay(self, parser, stockouts, transactions)
        return True
Esempio n. 50
0
def load_locs_json(domain,
                   selected_loc_id=None,
                   include_archived=False,
                   user=None,
                   only_administrative=False):
    """initialize a json location tree for drill-down controls on
    the client. tree is only partially initialized and branches
    will be filled in on the client via ajax.

    what is initialized:
    * all top level locs
    * if a 'selected' loc is provided, that loc and its complete
      ancestry

    only_administrative - if False get all locations
                          if True get only administrative locations
    """
    from .permissions import (user_can_edit_location, user_can_view_location,
                              user_can_access_location_id)

    def loc_to_json(loc, project):
        ret = {
            'name': loc.name,
            'location_type':
            loc.location_type.name,  # todo: remove when types aren't optional
            'uuid': loc.location_id,
            'is_archived': loc.is_archived,
            'can_edit': True
        }
        if user:
            if user.has_permission(domain, 'access_all_locations'):
                ret['can_edit'] = user_can_edit_location(user, loc, project)
            else:
                ret['can_edit'] = user_can_access_location_id(
                    domain, user, loc.location_id)
        return ret

    project = Domain.get_by_name(domain)

    locations = SQLLocation.root_locations(
        domain, include_archive_ancestors=include_archived)

    if only_administrative:
        locations = locations.filter(location_type__administrative=True)

    loc_json = [
        loc_to_json(loc, project) for loc in locations
        if user is None or user_can_view_location(user, loc, project)
    ]

    # if a location is selected, we need to pre-populate its location hierarchy
    # so that the data is available client-side to pre-populate the drop-downs
    if selected_loc_id:
        selected = SQLLocation.objects.get(domain=domain,
                                           location_id=selected_loc_id)

        lineage = selected.get_ancestors()

        parent = {'children': loc_json}
        for loc in lineage:
            children = loc.child_locations(
                include_archive_ancestors=include_archived)
            if only_administrative:
                children = children.filter(location_type__administrative=True)

            # find existing entry in the json tree that corresponds to this loc
            try:
                this_loc = [
                    k for k in parent['children']
                    if k['uuid'] == loc.location_id
                ][0]
            except IndexError:
                # if we couldn't find this location the view just break out of the loop.
                # there are some instances in viewing archived locations where we don't actually
                # support drilling all the way down.
                break
            this_loc['children'] = [
                loc_to_json(loc, project) for loc in children
                if user is None or user_can_view_location(user, loc, project)
            ]
            parent = this_loc

    return loc_json
Esempio n. 51
0
 def format_domains(dom_list, extra=None):
     extra = extra or []
     dom_list = list(set(filter(lambda d: d not in ctxt["domains"] + extra, dom_list)))
     return [Domain.get_by_name(d) for d in dom_list]
Esempio n. 52
0
def import_app(request, domain):
    template = "app_manager/import_app.html"
    if request.method == "POST":
        clear_app_cache(request, domain)
        name = request.POST.get('name')
        file = request.FILES.get('source_file')

        valid_request = True
        if not name:
            messages.error(
                request,
                _("You must submit a name for the application you are importing."
                  ))
            valid_request = False
        if not file:
            messages.error(request, _("You must upload the app source file."))
            valid_request = False

        try:
            if valid_request:
                source = json.load(file)
        except json.decoder.JSONDecodeError:
            messages.error(request,
                           _("The file uploaded is an invalid JSON file"))
            valid_request = False

        if not valid_request:
            return render(request, template, {'domain': domain})

        assert (source is not None)
        app = import_app_util(source, domain, {'name': name}, request=request)

        return back_to_main(request, domain, app_id=app._id)
    else:
        app_id = request.GET.get('app')
        redirect_domain = request.GET.get('domain') or None
        if redirect_domain is not None:
            redirect_domain = redirect_domain.lower()
            if Domain.get_by_name(redirect_domain):
                return HttpResponseRedirect(
                    reverse('import_app', args=[redirect_domain]) +
                    "?app={app_id}".format(app_id=app_id))
            else:
                if redirect_domain:
                    messages.error(
                        request, "We can't find a project called \"%s\"." %
                        redirect_domain)
                else:
                    messages.error(request, "You left the project name blank.")
                return HttpResponseRedirect(
                    request.META.get('HTTP_REFERER', request.path))

        if app_id:
            app = get_app(None, app_id)
            assert (app.get_doc_type() in ('Application', 'RemoteApp'))
            assert (request.couch_user.is_member_of(app.domain))
        else:
            app = None

        return render(request, template, {
            'domain': domain,
            'app': app,
        })
Esempio n. 53
0
 def domain_uses_case_sharing(self):
     domain = Domain.get_by_name(Group.get(self.group_id).domain)
     return domain.case_sharing_included()
Esempio n. 54
0
 def domain_obj(self):
     return Domain.get_by_name(self.domain)
Esempio n. 55
0
def is_usercase_in_use(domain_name):
    domain_obj = Domain.get_by_name(domain_name) if domain_name else None
    return domain_obj and domain_obj.usercase_enabled
Esempio n. 56
0
def process_sms_registration(msg):
    """
    This method handles registration via sms.
    Returns True if a contact was registered, False if not.

    To have a case register itself, do the following:

        1) Select "Enable Case Registration Via SMS" in project settings, and fill in the
        associated Case Registration settings.

        2) Text in "join <domain>", where <domain> is the domain to join. If the sending
        number does not exist in the system, a case will be registered tied to that number.
        The "join" keyword can be any keyword in REGISTRATION_KEYWORDS. This is meant to
        support multiple translations.

    To have a mobile worker register itself, do the following:

        1) Select "Enable Mobile Worker Registration via SMS" in project settings.

        2) Text in "join <domain> worker <username>", where <domain> is the domain to join and <username> is the
        requested username.  If the username doesn't exist it will be created, otherwise the registration will error.
        If the username argument is not specified, the username will be the mobile number

        The "join" and "worker" keywords can be any keyword in REGISTRATION_KEYWORDS and
        REGISTRATION_MOBILE_WORKER_KEYWORDS, respectively. This is meant to support multiple
        translations.
    """
    registration_processed = False
    text_words = msg.text.upper().split()
    keyword1 = text_words[0] if len(text_words) > 0 else ""
    keyword2 = text_words[1].lower() if len(text_words) > 1 else ""
    keyword3 = text_words[2] if len(text_words) > 2 else ""
    keyword4 = text_words[3] if len(text_words) > 3 else ""
    cleaned_phone_number = strip_plus(msg.phone_number)
    if is_registration_text(msg.text) and keyword2 != "":
        domain_name = keyword2

        if any_migrations_in_progress(domain_name):
            raise DelayProcessing()

        domain_obj = Domain.get_by_name(domain_name, strict=True)

        if domain_obj is not None:
            if domain_has_privilege(domain_obj, privileges.INBOUND_SMS):
                if (keyword3 in REGISTRATION_MOBILE_WORKER_KEYWORDS
                        and domain_obj.sms_mobile_worker_registration_enabled):
                    if keyword4 != '':
                        username = keyword4
                    else:
                        username = cleaned_phone_number
                    try:
                        user_data = {}

                        invitation = SelfRegistrationInvitation.by_phone(
                            msg.phone_number)
                        if invitation:
                            invitation.completed()
                            user_data = invitation.custom_user_data

                        username = process_username(username, domain_obj)
                        password = random_password()
                        new_user = CommCareUser.create(domain_obj.name,
                                                       username,
                                                       password,
                                                       user_data=user_data)
                        new_user.add_phone_number(cleaned_phone_number)
                        new_user.save()

                        entry = new_user.get_or_create_phone_entry(
                            cleaned_phone_number)
                        entry.set_two_way()
                        entry.set_verified()
                        entry.save()
                        registration_processed = True

                        if domain_obj.enable_registration_welcome_sms_for_mobile_worker:
                            send_sms(
                                domain_obj.name, None, cleaned_phone_number,
                                get_message(
                                    MSG_REGISTRATION_WELCOME_MOBILE_WORKER,
                                    domain=domain_obj.name))
                    except ValidationError as e:
                        send_sms(domain_obj.name, None, cleaned_phone_number,
                                 e.messages[0])

                elif domain_obj.sms_case_registration_enabled:
                    register_sms_contact(
                        domain=domain_obj.name,
                        case_type=domain_obj.sms_case_registration_type,
                        case_name="unknown",
                        user_id=domain_obj.sms_case_registration_user_id,
                        contact_phone_number=cleaned_phone_number,
                        contact_phone_number_is_verified="1",
                        owner_id=domain_obj.sms_case_registration_owner_id,
                    )
                    registration_processed = True
                    if domain_obj.enable_registration_welcome_sms_for_case:
                        send_sms(
                            domain_obj.name, None, cleaned_phone_number,
                            get_message(MSG_REGISTRATION_WELCOME_CASE,
                                        domain=domain_obj.name))
            msg.domain = domain_obj.name
            msg.save()

    return registration_processed
Esempio n. 57
0
def create_or_update_users_and_groups(domain,
                                      user_specs,
                                      group_specs,
                                      task=None):
    from corehq.apps.users.views.mobile.custom_data_fields import UserFieldsView
    custom_data_validator = UserFieldsView.get_validator(domain)
    ret = {"errors": [], "rows": []}
    total = len(user_specs) + len(group_specs)

    def _set_progress(progress):
        if task is not None:
            DownloadBase.set_progress(task, progress, total)

    group_memoizer = create_or_update_groups(domain, group_specs, log=ret)
    current = len(group_specs)

    usernames = set()
    user_ids = set()
    allowed_groups = set(group_memoizer.groups)
    allowed_group_names = [group.name for group in allowed_groups]
    allowed_roles = UserRole.by_domain(domain)
    roles_by_name = {role.name: role for role in allowed_roles}
    can_assign_locations = domain_has_privilege(domain, privileges.LOCATIONS)
    # ToDo: We need more speccing on what/how locations can be assigned if location-restrictions is enabled
    #       For now, don't support bulk assigning if location-restrictions are enabled
    can_assign_locations = can_assign_locations and not toggles.RESTRICT_WEB_USERS_BY_LOCATION.enabled(
        domain)
    if can_assign_locations:
        location_cache = SiteCodeToLocationCache(domain)
    project = Domain.get_by_name(domain)
    usernames_with_dupe_passwords = users_with_duplicate_passwords(user_specs)

    try:
        for row in user_specs:
            _set_progress(current)
            current += 1

            data = row.get('data')
            email = row.get('email')
            group_names = map(unicode, row.get('group') or [])
            language = row.get('language')
            name = row.get('name')
            password = row.get('password')
            phone_number = row.get('phone-number')
            uncategorized_data = row.get('uncategorized_data')
            user_id = row.get('user_id')
            username = row.get('username')
            location_codes = row.get('location_code') or []
            if location_codes and not isinstance(location_codes, list):
                location_codes = [location_codes]
            # ignore empty
            location_codes = [code for code in location_codes if code]
            role = row.get('role', '')

            if password:
                password = unicode(password)
            try:
                username = normalize_username(str(username), domain)
            except TypeError:
                username = None
            except ValidationError:
                ret['rows'].append({
                    'username':
                    username,
                    'row':
                    row,
                    'flag':
                    _('username cannot contain spaces or symbols'),
                })
                continue
            status_row = {
                'username': raw_username(username) if username else None,
                'row': row,
            }

            is_active = row.get('is_active')
            if isinstance(is_active, basestring):
                try:
                    is_active = string_to_boolean(
                        is_active) if is_active else None
                except ValueError:
                    ret['rows'].append({
                        'username':
                        username,
                        'row':
                        row,
                        'flag':
                        _("'is_active' column can only contain 'true' or 'false'"
                          ),
                    })
                    continue

            if username in usernames or user_id in user_ids:
                status_row['flag'] = 'repeat'
            elif not username and not user_id:
                status_row['flag'] = 'missing-data'
            else:
                try:
                    if username:
                        usernames.add(username)
                    if user_id:
                        user_ids.add(user_id)
                    if user_id:
                        user = CommCareUser.get_by_user_id(user_id, domain)
                    else:
                        user = CommCareUser.get_by_username(username)

                    if project.strong_mobile_passwords and is_password(
                            password):
                        if raw_username(
                                username) in usernames_with_dupe_passwords:
                            raise UserUploadError(
                                _("Provide a unique password for each mobile worker"
                                  ))

                        try:
                            clean_password(password)
                        except forms.ValidationError:
                            if settings.ENABLE_DRACONIAN_SECURITY_FEATURES:
                                msg = _(
                                    "Mobile Worker passwords must be 8 "
                                    "characters long with at least 1 capital "
                                    "letter, 1 special character and 1 number")
                            else:
                                msg = _("Please provide a stronger password")
                            raise UserUploadError(msg)

                    if user:
                        if user.domain != domain:
                            raise UserUploadError(
                                _('User with username %(username)r is '
                                  'somehow in domain %(domain)r') % {
                                      'username': user.username,
                                      'domain': user.domain
                                  })
                        if username and user.username != username:
                            raise UserUploadError(
                                _('Changing usernames is not supported: %(username)r to %(new_username)r'
                                  ) % {
                                      'username': user.username,
                                      'new_username': username
                                  })
                        if is_password(password):
                            user.set_password(password)
                        status_row['flag'] = 'updated'
                    else:
                        max_username_length = get_mobile_worker_max_username_length(
                            domain)
                        if len(raw_username(username)) > max_username_length:
                            ret['rows'].append({
                                'username':
                                username,
                                'row':
                                row,
                                'flag':
                                _("username cannot contain greater than %d characters"
                                  % max_username_length)
                            })
                            continue
                        if not is_password(password):
                            raise UserUploadError(
                                _("Cannot create a new user with a blank password"
                                  ))
                        user = CommCareUser.create(domain,
                                                   username,
                                                   password,
                                                   commit=False)
                        status_row['flag'] = 'created'
                    if phone_number:
                        user.add_phone_number(_fmt_phone(phone_number),
                                              default=True)
                    if name:
                        user.set_full_name(unicode(name))
                    if data:
                        error = custom_data_validator(data)
                        if error:
                            raise UserUploadError(error)
                        user.user_data.update(data)
                    if uncategorized_data:
                        user.user_data.update(uncategorized_data)
                    if language:
                        user.language = language
                    if email:
                        try:
                            validate_email(email)
                        except ValidationError:
                            raise UserUploadError(
                                _("User has an invalid email address"))

                        user.email = email.lower()
                    if is_active is not None:
                        user.is_active = is_active

                    if can_assign_locations:
                        # Do this here so that we validate the location code before we
                        # save any other information to the user, this way either all of
                        # the user's information is updated, or none of it
                        location_ids = []
                        for code in location_codes:
                            loc = get_location_from_site_code(
                                code, location_cache)
                            location_ids.append(loc.location_id)

                    if role:
                        if role in roles_by_name:
                            user.set_role(
                                domain, roles_by_name[role].get_qualified_id())
                        else:
                            raise UserUploadError(
                                _("Role '%s' does not exist") % role)

                    # following blocks require user doc id, so it needs to be saved if new user
                    user.save()
                    if can_assign_locations:
                        locations_updated = set(
                            user.assigned_location_ids) != set(location_ids)
                        primary_location_removed = (
                            user.location_id and not location_ids
                            or user.location_id not in location_ids)

                        if primary_location_removed:
                            user.unset_location()
                        if locations_updated:
                            user.reset_locations(location_ids)

                    if is_password(password):
                        # Without this line, digest auth doesn't work.
                        # With this line, digest auth works.
                        # Other than that, I'm not sure what's going on
                        user.get_django_user().check_password(password)

                    for group_id in Group.by_user(user, wrap=False):
                        group = group_memoizer.get(group_id)
                        if group.name not in group_names:
                            group.remove_user(user)

                    for group_name in group_names:
                        if group_name not in allowed_group_names:
                            raise UserUploadError(
                                _("Can't add to group '%s' "
                                  "(try adding it to your spreadsheet)") %
                                group_name)
                        group_memoizer.by_name(group_name).add_user(user,
                                                                    save=False)

                except (UserUploadError, CouchUser.Inconsistent) as e:
                    status_row['flag'] = unicode(e)

            ret["rows"].append(status_row)
    finally:
        try:
            group_memoizer.save_all()
        except BulkSaveError as e:
            _error_message = (
                "Oops! We were not able to save some of your group changes. "
                "Please make sure no one else is editing your groups "
                "and try again.")
            logging.exception(('BulkSaveError saving groups. '
                               'User saw error message "%s". Errors: %s') %
                              (_error_message, e.errors))
            ret['errors'].append(_error_message)

    _set_progress(total)
    return ret
Esempio n. 58
0
def iter_cases_to_modify():
    _domain = Domain.get_by_name(DOMAINS[0])
    if _domain is None:
        return
    time_zone = _domain.get_default_timezone()
    past_21_date = past_x_date(time_zone, 21)
    past_42_date = past_x_date(time_zone, 42)
    setup_indices()
    for domain in DOMAINS:
        for case in chain(get_cases_in_domain(domain, type=BIRTH_TYPE),
                          get_cases_in_domain(domain, type=CATI_FIDA_CHECK_TYPE)):
            if case.closed:
                continue
            if (
                not get_none_or_value(case, "owner_id") or
                not get_none_or_value(case, "date_admission") or
                not get_none_or_value(case, "facility_id")
            ):
                continue
            curr_assignment = get_none_or_value(case, "current_assignment")
            next_assignment = get_none_or_value(case, "next_assignment")
            facility_id = get_none_or_value(case, "facility_id")
            fida_group = get_group_id(domain, "fida", facility_id)

            # get cati_owner_username from current owner-group
            assigned_owner_group = get_none_or_value(case, "owner_id")
            if assigned_owner_group not in GROUPS_BY_ID[domain]:
                continue
            cati_owner_username = GROUPS_BY_ID[domain][assigned_owner_group].metadata.get('main_user', None)

            # Assignment Directly from Registration ##
            # Assign Cases to Call Center
            if (
                not curr_assignment and
                not next_assignment and
                past_21_date <= case.date_admission
            ):
                owner_id = get_group_id(domain, "cati", facility_id)
                if not owner_id:
                    continue
                owner_group = GROUPS_BY_ID[domain].get(owner_id, None)
                cati_name = owner_group.metadata.get('name', None) if owner_group else None
                update = {
                    "current_assignment": "cati",
                    "cati_name": cati_name
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": owner_id,
                }, domain
            # Assign Cases Directly To Field
            elif (
                not curr_assignment and
                not next_assignment and
                past_42_date <= case.date_admission < past_21_date
            ):
                if not fida_group:
                    continue
                update = {
                    "current_assignment": "fida",
                    "cati_status": 'skipped',
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": fida_group,
                }, domain
            # Assign Cases Directly to Lost to Follow Up
            elif (
                not curr_assignment and
                not next_assignment and
                case.date_admission < past_42_date
            ):
                update = {
                    "cati_status": 'skipped',
                    "last_assignment": '',
                    "closed_status": "timed_out_lost_to_follow_up",
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": True,
                }, domain

            ## Assignment from Call Center ##
            # Assign Cases to Field (manually by call center)
            elif (
                next_assignment == "fida" and
                past_42_date <= case.date_admission
            ):
                if not cati_owner_username or not fida_group:
                    continue
                update = {
                    "last_cati_user": cati_owner_username,
                    "current_assignment": "fida",
                    "next_assignment": '',
                    "cati_status": 'manually_assigned_to_field'
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": fida_group,
                }, domain
            # Assign cases to field (automatically)
            elif (
                curr_assignment in ("cati", "cati_tl", "cati-tl") and
                past_42_date <= case.date_admission < past_21_date
            ):
                if not cati_owner_username or not fida_group:
                    continue
                update = {
                    "last_cati_assignment": curr_assignment,
                    "last_cati_user": cati_owner_username,
                    "cati_status": 'timed_out',
                    "current_assignment": "fida",
                    "next_assignment": '',
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": False,
                    "owner_id": fida_group,
                }, domain
            # Assign Cases to Lost to Follow Up
            elif (
                curr_assignment in ("cati", "cati_tl", "cati-tl") and
                case.date_admission < past_42_date
            ):
                if not get_owner_username(domain, curr_assignment, facility_id) or not cati_owner_username:
                    continue
                update = {
                    "last_cati_assignment": curr_assignment,
                    "last_cati_user": cati_owner_username,
                    "last_user": get_owner_username(domain, curr_assignment, facility_id),
                    "cati_status": 'timed_out',
                    "last_assignment": curr_assignment,
                    "current_assignment": '',
                    "closed_status": "timed_out_lost_to_follow_up",
                    "next_assignment": ''
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": True,
                }, domain

            ## Assignment from Field ##
            # Assign Cases to Lost to Follow Up
            elif (
                curr_assignment in ("fida", "fida_tl") and
                case.date_admission < past_42_date
            ):
                if not get_owner_username(domain, curr_assignment, facility_id):
                    continue
                update = {
                    "last_user": get_owner_username(domain, curr_assignment, facility_id),
                    "last_assignment": curr_assignment,
                    "current_assignment": '',
                    "closed_status": "timed_out_lost_to_follow_up",
                    "next_assignment": '',
                }
                yield {
                    "case_id": case._id,
                    "update": update,
                    "close": True,
                }, domain
Esempio n. 59
0
 def get_domain(self):
     return Domain.get_by_name(self.domain)
Esempio n. 60
0
def get_restore_response(domain,
                         couch_user,
                         app_id=None,
                         since=None,
                         version='1.0',
                         state=None,
                         items=False,
                         force_cache=False,
                         cache_timeout=None,
                         overwrite_cache=False,
                         as_user=None,
                         device_id=None,
                         user_id=None,
                         openrosa_version=None,
                         case_sync=None):
    """
    :param domain: Domain being restored from
    :param couch_user: User performing restore
    :param app_id: App ID of the app making the request
    :param since: ID of current sync log used to generate incremental sync
    :param version: Version of the sync response required
    :param state: Hash value of the current database of cases on the device for consistency checking
    :param items: Include item count if True
    :param force_cache: Force response to be cached
    :param cache_timeout: Override the default cache timeout of 1 hour.
    :param overwrite_cache: Ignore cached response if True
    :param as_user: Username of user to generate restore for (if different from current user)
    :param device_id: ID of device performing restore
    :param user_id: ID of user performing restore (used in case of deleted user with same username)
    :param openrosa_version:
    :param case_sync: Override default case sync algorithm
    :return: Tuple of (http response, timing context or None)
    """

    if user_id and user_id != couch_user.user_id:
        # sync with a user that has been deleted but a new
        # user was created with the same username and password
        from couchforms.openrosa_response import get_simple_response_xml
        from couchforms.openrosa_response import ResponseNature
        response = get_simple_response_xml(
            'Attempt to sync with invalid user.',
            ResponseNature.OTA_RESTORE_ERROR)
        return HttpResponse(response,
                            content_type="text/xml; charset=utf-8",
                            status=412), None

    is_demo_restore = couch_user.is_commcare_user() and couch_user.is_demo_user
    if is_demo_restore:
        # if user is in demo-mode, return demo restore
        return demo_user_restore_response(couch_user), None

    uses_login_as = bool(as_user)
    as_user_obj = CouchUser.get_by_username(as_user) if uses_login_as else None
    if uses_login_as and not as_user_obj:
        msg = _('Invalid restore as user {}').format(as_user)
        return HttpResponse(msg, status=401), None
    is_permitted, message = is_permitted_to_restore(
        domain,
        couch_user,
        as_user_obj,
    )
    if not is_permitted:
        return HttpResponse(message, status=401), None

    restore_user = get_restore_user(domain, couch_user, as_user_obj)
    if not restore_user:
        return HttpResponse('Could not find user', status=404), None

    project = Domain.get_by_name(domain)
    async_restore_enabled = (toggles.ASYNC_RESTORE.enabled(domain)
                             and openrosa_version and
                             LooseVersion(openrosa_version) >= LooseVersion(
                                 OPENROSA_VERSION_MAP['ASYNC_RESTORE']))

    app = get_app_cached(domain, app_id) if app_id else None
    restore_config = RestoreConfig(
        project=project,
        restore_user=restore_user,
        params=RestoreParams(
            sync_log_id=since,
            version=version,
            state_hash=state,
            include_item_count=items,
            app=app,
            device_id=device_id,
            openrosa_version=openrosa_version,
        ),
        cache_settings=RestoreCacheSettings(force_cache=force_cache
                                            or async_restore_enabled,
                                            cache_timeout=cache_timeout,
                                            overwrite_cache=overwrite_cache),
        is_async=async_restore_enabled,
        case_sync=case_sync,
    )
    return restore_config.get_response(), restore_config.timing_context