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]]
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()
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)
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
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)
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()
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()
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()
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()
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
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()
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.")
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()
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')
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()
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
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)
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)
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
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'})
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)
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)
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'] )
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
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()
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())
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)
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
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
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, })
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,
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)
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)
def _get_domain_apps(domain): return Domain.get_by_name(domain).applications()
def domain_obj(self, domain_name): return Domain.get_by_name(domain_name)
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
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)
def project(self): return Domain.get_by_name(self.domain)
def commtrack_enabled(self): return Domain.get_by_name(self.domain).commtrack_enabled
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])
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.")
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
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]
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
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
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
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]
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, })
def domain_uses_case_sharing(self): domain = Domain.get_by_name(Group.get(self.group_id).domain) return domain.case_sharing_included()
def domain_obj(self): return Domain.get_by_name(self.domain)
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
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
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
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
def get_domain(self): return Domain.get_by_name(self.domain)
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