def can_edit_form_location(domain, web_user, form): # Domain admins can always edit locations. If the user isn't an admin and # the location restriction is enabled, they can only edit forms that are # explicitly at or below them in the location tree. # This first block checks for old permissions, remove when that's gone if toggles.RESTRICT_FORM_EDIT_BY_LOCATION.enabled(domain): domain_obj = Domain.get_by_name(domain) if user_can_edit_any_location(web_user, domain_obj): return True if not form.user_id: return False form_user = CouchUser.get_by_user_id(form.user_id) if domain_obj.supports_multiple_locations_per_user: form_locations = [loc.sql_location for loc in form_user.locations] else: form_locations = form_user.get_sql_locations(domain) for location in form_locations: if user_can_edit_location(web_user, location, domain_obj): return True return False if web_user.has_permission(domain, 'access_all_locations'): return True if not form.user_id: return False form_user = CouchUser.get_by_user_id(form.user_id) if not form_user: return False # It's a special form, deny to be safe form_location_ids = form_user.get_location_ids(domain) return user_can_access_any_location_id(domain, web_user, form_location_ids)
def recipient(self): if self.recipient_type == self.RECIPIENT_TYPE_CASE: try: case = CaseAccessors(self.domain).get_case(self.recipient_id) except CaseNotFound: return None if case.domain != self.domain: return None return case elif self.recipient_type == self.RECIPIENT_TYPE_MOBILE_WORKER: user = CouchUser.get_by_user_id(self.recipient_id, domain=self.domain) if not isinstance(user, CommCareUser): return None return user elif self.recipient_type == self.RECIPIENT_TYPE_WEB_USER: user = CouchUser.get_by_user_id(self.recipient_id, domain=self.domain) if not isinstance(user, WebUser): return None return user elif self.recipient_type == self.RECIPIENT_TYPE_CASE_GROUP: try: group = CommCareCaseGroup.get(self.recipient_id) except ResourceNotFound: return None if group.domain != self.domain: return None return group elif self.recipient_type == self.RECIPIENT_TYPE_USER_GROUP: try: group = Group.get(self.recipient_id) except ResourceNotFound: return None if group.domain != self.domain: return None return group elif self.recipient_type == self.RECIPIENT_TYPE_LOCATION: location = SQLLocation.by_location_id(self.recipient_id) if location is None: return None if location.domain != self.domain: return None return location else: raise UnknownRecipientType(self.recipient_type)
def recipient(self): if self.recipient_type == self.RECIPIENT_TYPE_SELF: return self.case elif self.recipient_type == self.RECIPIENT_TYPE_CASE_OWNER: return self.case_owner elif self.recipient_type == self.RECIPIENT_TYPE_LAST_SUBMITTING_USER: if self.case and self.case.modified_by: return CouchUser.get_by_user_id(self.case.modified_by, domain=self.domain) return None elif self.recipient_type == self.RECIPIENT_TYPE_PARENT_CASE: if self.case: return self.case.parent return None elif self.recipient_type == self.RECIPIENT_TYPE_ALL_CHILD_CASES: if self.case: return list(self.case.get_subcases(index_identifier=DEFAULT_PARENT_IDENTIFIER)) return None elif self.recipient_type == self.RECIPIENT_TYPE_CUSTOM: custom_function = to_function( settings.AVAILABLE_CUSTOM_SCHEDULING_RECIPIENTS[self.recipient_id][0] ) return custom_function(self) else: return super(CaseScheduleInstanceMixin, self).recipient
def handle(self, *args, **options): if len(args) == 0: raise CommandError("Usage: python manage.py fix_smslog_recipient_doc_type <domain1 domain2 ...>") for domain in args: print "*** Processing Domain %s ***" % domain user_cache = {} for msg in SMSLog.by_domain_asc(domain).all(): if msg.couch_recipient: if msg.couch_recipient_doc_type != "CommCareCase": user = None if msg.couch_recipient in user_cache: user = user_cache[msg.couch_recipient] else: try: user = CouchUser.get_by_user_id(msg.couch_recipient) except Exception: user = None if user is None: print "Could not find user %s" % msg.couch_recipient user_cache[msg.couch_recipient] = user if user and msg.couch_recipient_doc_type != user.doc_type: msg.couch_recipient_doc_type = user.doc_type msg.save() else: if msg.couch_recipient_doc_type is not None or msg.couch_recipient is not None: msg.couch_recipient = None msg.couch_recipient_doc_type = None msg.save()
def _get_username(self, user_id): username = self.report.usernames.get(user_id) if not username: mc = cache.caches['default'] cache_key = "%s.%s" % (CouchUser.__class__.__name__, user_id) try: if mc.has_key(cache_key): user_dict = json.loads(mc.get(cache_key)) else: user_obj = CouchUser.get_by_user_id(user_id) if user_id else None if user_obj: user_dict = user_obj.to_json() else: user_dict = {} cache_payload = json.dumps(user_dict) mc.set(cache_key, cache_payload) if user_dict == {}: return None else: user_obj = CouchUser.wrap(user_dict) username = user_obj.username except Exception: return None return username
def get_loadtest_factor_for_user(domain, user_id): from corehq.apps.users.models import CouchUser, CommCareUser if ENABLE_LOADTEST_USERS.enabled(domain) and user_id: user = CouchUser.get_by_user_id(user_id, domain=domain) if isinstance(user, CommCareUser): return user.loadtest_factor or 1 return 1
def process_change(self, change): synclog = change.get_document() if not synclog: return version = None app_id = None try: sync_date = string_to_utc_datetime(synclog.get('date')) except (ValueError, AttributeError): return build_id = synclog.get('build_id') if build_id: version, app_id = get_version_and_app_from_build_id(synclog.get('domain'), build_id) user_id = synclog.get('user_id') if user_id: user = CouchUser.get_by_user_id(user_id) save = update_last_sync(user, app_id, sync_date, version) if version: save |= update_latest_builds(user, app_id, sync_date, version) app_meta = None device_id = synclog.get('device_id') if device_id: if app_id: app_meta = DeviceAppMeta(app_id=app_id, build_id=build_id, last_sync=sync_date) save |= update_device_meta(user, device_id, device_app_meta=app_meta, save=False) if save: user.save(fire_signals=False)
def handle(self, domains, **options): for domain in domains: print("*** Processing Domain %s ***" % domain) user_cache = {} for msg in SMS.by_domain(domain): if msg.couch_recipient: if msg.couch_recipient_doc_type != "CommCareCase": user = None if msg.couch_recipient in user_cache: user = user_cache[msg.couch_recipient] else: try: user = CouchUser.get_by_user_id(msg.couch_recipient) except Exception: user = None if user is None: print("Could not find user %s" % msg.couch_recipient) user_cache[msg.couch_recipient] = user if user and msg.couch_recipient_doc_type != user.doc_type: msg.couch_recipient_doc_type = user.doc_type msg.save() else: if msg.couch_recipient_doc_type is not None or msg.couch_recipient is not None: msg.couch_recipient = None msg.couch_recipient_doc_type = None msg.save()
def verify_phone_number(request, domain, couch_user_id): """ phone_number cannot be passed in the url due to special characters but it can be passed as %-encoded GET parameters """ if 'phone_number' not in request.GET: raise Http404('Must include phone number in request.') phone_number = six.moves.urllib.parse.unquote(request.GET['phone_number']) user = CouchUser.get_by_user_id(couch_user_id, domain) try: result = initiate_sms_verification_workflow(user, phone_number) except BadSMSConfigException as error: messages.error(request, _('Bad SMS configuration: {error}').format(error=error)) else: if result == VERIFICATION__ALREADY_IN_USE: messages.error(request, _('Cannot start verification workflow. Phone number is already in use.')) elif result == VERIFICATION__ALREADY_VERIFIED: messages.error(request, _('Phone number is already verified.')) elif result == VERIFICATION__RESENT_PENDING: messages.success(request, _('Verification message resent.')) elif result == VERIFICATION__WORKFLOW_STARTED: messages.success(request, _('Verification workflow started.')) from corehq.apps.users.views.mobile import EditCommCareUserView redirect = reverse(EditCommCareUserView.urlname, args=[domain, couch_user_id]) return HttpResponseRedirect(redirect)
def get_owned_cases(domain, user_id, closed=False): """ Get all cases in a domain owned by a particular user. """ try: user = CouchUser.get_by_user_id(user_id, domain) except KeyError: user = None try: owner_ids = user.get_owner_ids() except AttributeError: owner_ids = [user_id] @list @inline def keys(): for owner_id in owner_ids: if closed is None: yield [owner_id, True] yield [owner_id, False] else: yield [owner_id, closed] cases = CommCareCase.view('case/by_owner', keys=keys, include_docs=True, reduce=False) # demo_user cases! return [case.get_json() for case in cases if case.domain == domain]
def _sync_user_phone_numbers(couch_user_id): couch_user = CouchUser.get_by_user_id(couch_user_id) if not isinstance(couch_user, CommCareUser): # It isn't necessary to sync WebUser's phone numbers right now # and we need to think through how to support entries when a user # can belong to multiple domains return with CriticalSection([couch_user.phone_sync_key], timeout=5 * 60): phone_entries = couch_user.get_phone_entries() if ( couch_user.is_deleted() or (not couch_user.is_active and not USE_SMS_WITH_INACTIVE_CONTACTS.enabled(couch_user.domain)) ): for phone_number in phone_entries.values(): phone_number.delete() return numbers_that_should_exist = [apply_leniency(phone_number) for phone_number in couch_user.phone_numbers] # Delete entries that should not exist for phone_number in phone_entries.keys(): if phone_number not in numbers_that_should_exist: phone_entries[phone_number].delete() # Create entries that should exist but do not exist for phone_number in numbers_that_should_exist: if phone_number not in phone_entries: try: couch_user.create_phone_entry(phone_number) except InvalidFormatException: pass
def get_recipient_info(self, recipient_doc_type, recipient_id, contact_cache): if recipient_doc_type in ['SQLLocation']: return self.get_orm_recipient_info(recipient_doc_type, recipient_id, contact_cache) if recipient_id in contact_cache: return contact_cache[recipient_id] doc = None if recipient_id not in [None, ""]: try: if recipient_doc_type.startswith('CommCareCaseGroup'): doc = CommCareCaseGroup.get(recipient_id) elif recipient_doc_type.startswith('CommCareCase'): doc = CommCareCase.get(recipient_id) elif recipient_doc_type in ('CommCareUser', 'WebUser'): doc = CouchUser.get_by_user_id(recipient_id) elif recipient_doc_type.startswith('Group'): doc = Group.get(recipient_id) except Exception: pass if doc: doc_info = get_doc_info(doc.to_json(), self.domain) else: doc_info = None contact_cache[recipient_id] = doc_info return doc_info
def get_recipient_info(self, recipient_doc_type, recipient_id, contact_cache): if recipient_doc_type in ['SQLLocation']: return self.get_orm_recipient_info(recipient_doc_type, recipient_id, contact_cache) if recipient_id in contact_cache: return contact_cache[recipient_id] doc = None if recipient_id not in [None, ""]: try: if recipient_doc_type.startswith('CommCareCaseGroup'): doc = CommCareCaseGroup.get(recipient_id) elif recipient_doc_type.startswith('CommCareCase'): doc = CommCareCase.get(recipient_id) elif recipient_doc_type in ('CommCareUser', 'WebUser'): doc = CouchUser.get_by_user_id(recipient_id) elif recipient_doc_type.startswith('Group'): doc = Group.get(recipient_id) except Exception: pass doc_info = None if doc: try: doc_info = get_doc_info(doc.to_json(), self.domain) except DomainMismatchException: # This can happen, for example, if a WebUser was sent an SMS # and then they unsubscribed from the domain. If that's the # case, we'll just leave doc_info as None and no contact link # will be displayed. pass contact_cache[recipient_id] = doc_info return doc_info
def __setstate__(self, state): """ For unpickling a pickled report. """ logging = get_task_logger(__name__) # logging lis likely to happen within celery. self.domain = state.get('domain') self.context = state.get('context', {}) class FakeHttpRequest(object): GET = {} META = {} couch_user = None datespan = None request_data = state.get('request') request = FakeHttpRequest() request.GET = request_data.get('GET', {}) request.META = request_data.get('META', {}) request.datespan = request_data.get('datespan') try: couch_user = CouchUser.get_by_user_id(request_data.get('couch_user')) request.couch_user = couch_user except Exception as e: logging.error("Could not unpickle couch_user from request for report %s. Error: %s" % (self.name, e)) self.request = request self._caching = True self.request_params = state.get('request_params') self._update_initial_context()
def verify_phone_number(request, domain, couch_user_id): """ phone_number cannot be passed in the url due to special characters but it can be passed as %-encoded GET parameters """ if 'phone_number' not in request.GET: return Http404('Must include phone number in request.') phone_number = urllib.unquote(request.GET['phone_number']) user = CouchUser.get_by_user_id(couch_user_id, domain) try: # send verification message smsverify.send_verification(domain, user, phone_number) # create pending verified entry if doesn't exist already user.save_verified_number(domain, phone_number, False, None) except BadSMSConfigException: messages.error(request, "Could not verify phone number. It seems there is no usable SMS backend.") if user.is_commcare_user(): from corehq.apps.users.views.mobile import EditCommCareUserView redirect = reverse(EditCommCareUserView.urlname, args=[domain, couch_user_id]) else: redirect = reverse(EditMyAccountDomainView.urlname, args=[domain]) return HttpResponseRedirect(redirect)
def handle(self, *args, **options): if len(args) != 3: raise CommandError('Usage is duplicate_cases %s' % self.args) start = datetime.now() case_id_file, user_id, domain = args self.submit_url = URL_BASE + get_submit_url(domain) print self.submit_url user = CouchUser.get_by_user_id(user_id, domain) user_id = user._id if not user.is_member_of(domain): raise CommandError("%s can't access %s" % (user, domain)) self.read_progress() with open(case_id_file, 'r') as f: case_ids = f.readlines() try: for id in case_ids: self.duplicate_case(id.strip(), domain, user_id) finally: self.write_progress() print 'finished in %s seconds' % (datetime.now() - start).seconds print '{} cases processed'.format(len(self.cases_processing.keys())) print '{} forms processed'.format(len(self.forms_processing.keys()))
def import_locations_async(domain, file_ref_id, user_id): importer = MultiExcelImporter(import_locations_async, file_ref_id) results = new_locations_import(domain, importer, CouchUser.get_by_user_id(user_id)) importer.mark_complete() if LOCATIONS_IN_UCR.enabled(domain): # We must rebuild datasources once the location import is complete in # case child locations were not updated, but a parent location was. # For example if a state was updated, the county may reference the state # and need to have its row updated datasources = get_datasources_for_domain(domain, "Location", include_static=True) for datasource in datasources: rebuild_indicators_in_place.delay(datasource.get_id) if getattr(settings, 'CELERY_ALWAYS_EAGER', False): # Log results because they are not sent to the view when # CELERY_ALWAYS_EAGER is true logging.getLogger(__name__).info( "import_locations_async %s results: %s -> success=%s", file_ref_id, " ".join( "%s=%r" % (name, getattr(results, name)) for name in ["messages", "warnings", "errors"] if getattr(results, name) ), results.success, ) return { 'messages': results }
def mark_latest_submission(domain, user_id, app_id, build_id, version, metadata, received_on): user = CouchUser.get_by_user_id(user_id, domain) if not user or user.is_deleted(): return try: received_on_datetime = string_to_utc_datetime(received_on) except ValueError: return last_submission = filter_by_app(user.reporting_metadata.last_submissions, app_id) if metadata and metadata.get('appVersion') and not isinstance(metadata['appVersion'], six.string_types): metadata = format_form_meta_for_es(metadata) app_version_info = get_app_version_info( domain, build_id, version, metadata ) if _last_submission_needs_update(last_submission, received_on_datetime, app_version_info.build_version, app_version_info.commcare_version): if last_submission is None: last_submission = LastSubmission() user.reporting_metadata.last_submissions.append(last_submission) last_submission.submission_date = received_on_datetime device_id = metadata.get('deviceID') last_submission.device_id = device_id last_submission.app_id = app_id last_submission.build_id = build_id last_submission.build_version = app_version_info.build_version last_submission.commcare_version = app_version_info.commcare_version if app_version_info.build_version: update_latest_builds(user, app_id, received_on_datetime, app_version_info.build_version) if _last_submission_needs_update(user.reporting_metadata.last_submission_for_user, received_on_datetime, app_version_info.build_version, app_version_info.commcare_version, False): user.reporting_metadata.last_submission_for_user = last_submission app_meta = DeviceAppMeta( app_id=app_id, build_id=build_id, last_submission=received_on_datetime, ) update_device_meta(user, device_id, app_version_info.commcare_version, app_meta, save=False) user.save()
def _add_modified_by_to_template_params(case, result): try: modified_by = CouchUser.get_by_user_id(case.modified_by) except KeyError: return if modified_by: result['case']['last_modified_by'] = _get_obj_template_info(modified_by)
def editable_user(self): try: user = CouchUser.get_by_user_id(self.editable_user_id, self.domain) except (ResourceNotFound, CouchUser.AccountTypeError, KeyError): raise Http404() if not user or not _can_edit_workers_location(self.couch_user, user): raise Http404() return user
def get_users(self, is_active=True, only_commcare=False): users = [CouchUser.get_by_user_id(user_id) for user_id in self.users] users = [user for user in users if not user.is_deleted()] if only_commcare is True: users = [user for user in users if user.__class__ == CommCareUser().__class__] if is_active is True: return [user for user in users if user.is_active] else: return users
def get_contact(contact_id): from corehq.apps.sms.models import CommConnectCase contact = CommConnectCase.get(contact_id) if contact.doc_type != "CommCareCase": try: contact = CouchUser.get_by_user_id(contact_id) except CouchUser.AccountTypeError: raise Exception("Unkown contact type for contact %s" % contact_id) return contact
def handle(self, *args, **options): # This is ok, there's only like 50k of these and we're only querying ids vns = VerifiedNumber.view( 'phone_numbers/verified_number_by_owner_id', include_docs=False ).all() # Convert to a dict of {owner id: count of total numbers} owners = {} for vn in vns: owner_id = vn['key'] if owner_id in owners: owners[owner_id] += 1 else: owners[owner_id] = 1 # Convert to a list of owner ids that have more than one VerifiedNumber # (excluding pending numbers) mult_list = [] for owner_id, count in owners.iteritems(): if count > 1: owner_vns = VerifiedNumber.view( 'phone_numbers/verified_number_by_owner_id', key=owner_id, include_docs=True ).all() owner_vns = [vn for vn in owner_vns if vn.verified] if len(owner_vns) > 1: mult_list.append(owner_id) # If the old methodology's preferred number doesn't match the # new one, report it here. Only fix it if options['fix'] is True for owner_id in mult_list: user = CouchUser.get_by_user_id(owner_id) if not user: print 'ERROR: User not found: %s' % owner_id continue if not self.phones_are_strings(user): print 'ERROR: Phone numbers should be strings: %s' % owner_id continue preferred_old_vn = get_verified_number_for_recipient_old(user) preferred_new_vn = get_verified_number_for_recipient(user) if preferred_old_vn._id != preferred_new_vn._id: print "Need to change %s %s from %s to %s" % ( user.domain, owner_id, preferred_new_vn.phone_number, preferred_old_vn.phone_number, ) if preferred_old_vn.phone_number not in user.phone_numbers: print 'ERROR: Phone numbers are out of sync: %s' % owner_id continue if options.get('fix', False): print " fixing..." user.set_default_phone_number(preferred_old_vn.phone_number)
def unsubscribe(request, user_id): user = CouchUser.get_by_user_id(user_id) domain = user.get_domains()[0] from django.contrib import messages messages.info(request, _('Check "Opt out of emails about new features ' 'and other CommCare updates." below and then ' 'click "Update Information" if you do ' 'not want to receive future emails from us.')) return HttpResponseRedirect(reverse('commcare_user_account', args=[domain, user_id]))
def is_user_contact_active(domain, user_id): try: user = CouchUser.get_by_user_id(user_id, domain=domain) except KeyError: return False if not user: return False return user.is_active
def _get_username(self, user_id): if not user_id: return None try: user = CouchUser.get_by_user_id(user_id) if user: return user.username except CouchUser.AccountTypeError: return None
def delete_phone_number(request, domain, couch_user_id): user = CouchUser.get_by_user_id(couch_user_id, domain) if not user.is_current_web_user(request) and not user.is_commcare_user(): raise Http404 phone_number = request.POST['phone_number'] if not phone_number: return Http404('Must include phone number in request.') user.delete_phone_number(phone_number) return HttpResponseRedirect(reverse("user_account", args=(domain, couch_user_id)))
def redirect_users_to(request, domain): redirect = None # good ol' public domain... if not isinstance(request.couch_user, PublicUser): user = CouchUser.get_by_user_id(request.couch_user._id, domain) if user: if user.has_permission(domain, 'edit_commcare_users'): redirect = reverse("commcare_users", args=[domain]) else: redirect = reverse("user_account", args=[domain, request.couch_user._id]) return redirect
def user_can_access_case(domain, user, case): from corehq.apps.reports.standard.cases.data_sources import CaseInfo info = CaseInfo(None, case.to_json()) if info.owner_type == 'location': return user_can_access_location_id(domain, user, info.owner_id) elif info.owner_type == 'user': owning_user = CouchUser.get_by_user_id(info.owner_id) return user_can_access_other_user(domain, user, owning_user) else: return False
def redirect(self): redirect = None # good ol' public domain... if not isinstance(self.couch_user, PublicUser): user = CouchUser.get_by_user_id(self.couch_user._id, self.domain) if user: if user.has_permission(self.domain, 'edit_commcare_users'): redirect = reverse("commcare_users", args=[self.domain]) elif user.has_permission(self.domain, 'edit_web_users'): redirect = reverse(ListWebUsersView.urlname, args=[self.domain]) return redirect
def user_can_access_case(domain, user, case): from corehq.apps.reports.standard.cases.data_sources import CaseDisplay if user.has_permission(domain, 'access_all_locations'): return True info = CaseDisplay(case.to_json()) if info.owner_type == 'location': return user_can_access_location_id(domain, user, info.owner_id) elif info.owner_type == 'user': owning_user = CouchUser.get_by_user_id(info.owner_id) return user_can_access_other_user(domain, user, owning_user) else: return False
def username(self): name = self.phone_number if self.couch_recipient: try: if self.couch_recipient_doc_type == "CommCareCase": name = CommCareCase.get(self.couch_recipient).name else: # Must be a user name = CouchUser.get_by_user_id( self.couch_recipient).username except Exception as e: pass return name
def _get_org_unit(config, case_trigger_info=None, payload=None): org_unit_id_spec = config.org_unit_id org_unit_id = org_unit_id_spec.get_value( case_trigger_info) if org_unit_id_spec else None if not org_unit_id: user_id = payload.get('@user_id') user = CouchUser.get_by_user_id(user_id) location = user.get_sql_location(payload.get('domain')) org_unit_id = location.metadata.get(LOCATION_DHIS_ID, None) if not org_unit_id: return {} return {'orgUnit': org_unit_id}
def delete_phone_number(request, domain, couch_user_id): user = CouchUser.get_by_user_id(couch_user_id, domain) if not user.is_current_web_user(request) and not user.is_commcare_user(): raise Http404() phone_number = request.POST['phone_number'] if not phone_number: raise Http404('Must include phone number in request.') user.delete_phone_number(phone_number) from corehq.apps.users.views.mobile import EditCommCareUserView redirect = reverse(EditCommCareUserView.urlname, args=[domain, couch_user_id]) return HttpResponseRedirect(redirect)
def process_reporting_metadata_staging(): from corehq.apps.users.models import (CouchUser, UserReportingMetadataStaging) with transaction.atomic(): records = (UserReportingMetadataStaging.objects.select_for_update( skip_locked=True).order_by('pk'))[:100] for record in records: user = CouchUser.get_by_user_id(record.user_id, record.domain) record.process_record(user) record.delete() if UserReportingMetadataStaging.objects.exists(): process_reporting_metadata_staging.delay()
def populate_export_download_task(export_instances, filters, download_id, filename=None, expiry=10 * 60): """ :param expiry: Time period for the export to be available for download in minutes """ domain = export_instances[0].domain with TransientTempfile() as temp_path, datadog_track_errors('populate_export_download_task'): export_file = get_export_file( export_instances, filters, temp_path, # We don't have a great way to calculate progress if it's a bulk download, # so only track the progress for single instance exports. progress_tracker=populate_export_download_task if len(export_instances) == 1 else None ) file_format = Format.from_format(export_file.format) filename = filename or export_instances[0].name with export_file as file_: db = get_blob_db() db.put( file_, domain=domain, parent_id=domain, type_code=CODES.data_export, key=download_id, timeout=expiry, ) expose_blob_download( download_id, expiry=expiry * 60, mimetype=file_format.mimetype, content_disposition=safe_filename_header(filename, file_format.extension), download_id=download_id, ) email_requests = EmailExportWhenDoneRequest.objects.filter( domain=domain, download_id=download_id ) for email_request in email_requests: try: couch_user = CouchUser.get_by_user_id(email_request.user_id, domain=domain) except CouchUser.AccountTypeError: pass else: if couch_user is not None: process_email_request(domain, download_id, couch_user.get_email()) email_requests.delete()
def mark_latest_submission(domain, user_id, app_id, build_id, version, metadata, received_on): user = CouchUser.get_by_user_id(user_id, domain) if not user or user.is_deleted(): return try: received_on_datetime = string_to_utc_datetime(received_on) except ValueError: return last_submission = filter_by_app(user.reporting_metadata.last_submissions, app_id) if metadata and metadata.get('appVersion') and not isinstance( metadata['appVersion'], basestring): metadata = format_form_meta_for_es(metadata) app_version_info = get_app_version_info(domain, build_id, version, metadata) if _last_submission_needs_update(last_submission, received_on_datetime, app_version_info.build_version, app_version_info.commcare_version): if last_submission is None: last_submission = LastSubmission() user.reporting_metadata.last_submissions.append(last_submission) last_submission.submission_date = received_on_datetime last_submission.device_id = metadata.get('deviceID') last_submission.app_id = app_id last_submission.build_id = build_id last_submission.build_version = app_version_info.build_version last_submission.commcare_version = app_version_info.commcare_version if app_version_info.build_version: update_latest_builds(user, app_id, received_on_datetime, app_version_info.build_version) if _last_submission_needs_update( user.reporting_metadata.last_submission_for_user, received_on_datetime, app_version_info.build_version, app_version_info.commcare_version, False): user.reporting_metadata.last_submission_for_user = last_submission user.save()
def get_xform_location(xform): """ Returns the sql location associated with the user who submitted an xform """ from corehq.apps.users.models import CouchUser user_id = xform.user_id if not user_id: return None user = CouchUser.get_by_user_id(user_id) if hasattr(user, 'get_sql_location'): return user.get_sql_location(xform.domain) elif hasattr(user, 'sql_location'): return user.sql_location return None
def _rebuild_cases(self): user = CouchUser.get_by_user_id(self.user_id) reason = "User %s forms archived for domain %s by system" % ( user.raw_username, self.domain) form_processor_interface = FormProcessorInterface(self.domain) with open("cases_rebuilt.txt", "w") as case_log: for case_id in with_progress_bar(self.case_ids_to_rebuild): case_log.write("%s\n" % case_id) rebuild_case_from_forms(self.domain, case_id, RebuildWithReason(reason=reason)) ledgers = form_processor_interface.ledger_db.get_ledgers_for_case( case_id) for ledger in ledgers: form_processor_interface.ledger_processor.rebuild_ledger_state( case_id, ledger.section_id, ledger.entry_id)
def can_edit_form_location(domain, web_user, form): # Domain admins can always edit locations. If the user isn't an admin and # the location restriction is enabled, they can only edit forms that are # explicitly at or below them in the location tree. # This first block checks for old permissions, remove when that's gone if toggles.RESTRICT_FORM_EDIT_BY_LOCATION.enabled(domain): domain_obj = Domain.get_by_name(domain) if user_can_edit_any_location(web_user, domain_obj): return True if not form.user_id: return False form_user = CouchUser.get_by_user_id(form.user_id) if not form_user: # form most likely submitted by a system user return False if domain_obj.supports_multiple_locations_per_user: form_locations = [loc.sql_location for loc in form_user.locations] else: form_locations = form_user.get_sql_locations(domain) for location in form_locations: if user_can_edit_location(web_user, location, domain_obj): return True return False if web_user.has_permission(domain, 'access_all_locations'): return True if not form.user_id: return False form_user = CouchUser.get_by_user_id(form.user_id) if not form_user: return False # It's a special form, deny to be safe form_location_ids = form_user.get_location_ids(domain) return user_can_access_any_location_id(domain, web_user, form_location_ids)
def process_reporting_metadata_staging(): from corehq.apps.users.models import (CouchUser, UserReportingMetadataStaging) start = datetime.utcnow() with transaction.atomic(): records = (UserReportingMetadataStaging.objects.select_for_update( skip_locked=True).order_by('pk'))[:100] for record in records: user = CouchUser.get_by_user_id(record.user_id, record.domain) try: record.process_record(user) except ResourceConflict: # https://sentry.io/organizations/dimagi/issues/1479516073/ user = CouchUser.get_by_user_id(record.user_id, record.domain) record.process_record(user) record.delete() duration = datetime.utcnow() - start run_again = run_periodic_task_again( process_reporting_metadata_staging_schedule, start, duration) if run_again and UserReportingMetadataStaging.objects.exists(): process_reporting_metadata_staging.delay()
def redirect(self): redirect = None has_project_access = has_privilege(self.request, privileges.PROJECT_ACCESS) user = CouchUser.get_by_user_id(self.couch_user._id) if user: if ((user.has_permission(self.domain, 'edit_commcare_users') or user.has_permission(self.domain, 'view_commcare_users')) and has_project_access): from corehq.apps.users.views.mobile import MobileWorkerListView redirect = reverse( MobileWorkerListView.urlname, args=[self.domain] ) elif ((user.has_permission(self.domain, 'edit_groups') or user.has_permission(self.domain, 'view_groups')) and has_project_access): from corehq.apps.users.views.mobile import GroupsListView redirect = reverse( GroupsListView.urlname, args=[self.domain] ) elif (user.has_permission(self.domain, 'edit_web_users') or user.has_permission(self.domain, 'view_web_users')): redirect = reverse( ListWebUsersView.urlname, args=[self.domain] ) elif (user.has_permission(self.domain, 'view_roles') and has_project_access): from corehq.apps.users.views import ListRolesView redirect = reverse( ListRolesView.urlname, args=[self.domain] ) elif ((user.has_permission(self.domain, 'edit_locations') or user.has_permission(self.domain, 'view_locations')) and has_project_access): from corehq.apps.locations.views import LocationsListView redirect = reverse( LocationsListView.urlname, args=[self.domain] ) return redirect
def get_recipient_info(self, domain, recipient_doc_type, recipient_id, contact_cache): """ We need to accept domain as an arg here for admin reports that extend this base. """ if recipient_id in contact_cache: return contact_cache[recipient_id] couch_object = None sql_object = None if recipient_id: try: if recipient_doc_type.startswith('CommCareCaseGroup'): couch_object = CommCareCaseGroup.get(recipient_id) elif recipient_doc_type.startswith('CommCareCase'): obj = CaseAccessors(domain).get_case(recipient_id) if isinstance(obj, CommCareCase): couch_object = obj elif isinstance(obj, CommCareCaseSQL): sql_object = obj elif recipient_doc_type in ('CommCareUser', 'WebUser'): couch_object = CouchUser.get_by_user_id(recipient_id) elif recipient_doc_type.startswith('Group'): couch_object = Group.get(recipient_id) elif recipient_doc_type == 'SQLLocation': sql_object = SQLLocation.objects.get(location_id=recipient_id) except (ResourceNotFound, CaseNotFound, ObjectDoesNotExist): pass doc_info = None if couch_object: try: doc_info = get_doc_info(couch_object.to_json(), domain) except DomainMismatchException: # This can happen, for example, if a WebUser was sent an SMS # and then they unsubscribed from the domain. If that's the # case, we'll just leave doc_info as None and no contact link # will be displayed. pass if sql_object: doc_info = get_object_info(sql_object) contact_cache[recipient_id] = doc_info return doc_info
def rows(self): startdate = json_format_datetime(self.datespan.startdate_utc) enddate = json_format_datetime(self.datespan.enddate_utc) data = ExpectedCallbackEventLog.by_domain(self.domain, startdate, enddate) result = [] status_descriptions = { CALLBACK_PENDING: _("Pending"), CALLBACK_RECEIVED: _("Received"), CALLBACK_MISSED: _("Missed"), } # Store the results of lookups for faster loading username_map = {} for event in data: recipient_id = event.couch_recipient if recipient_id in [None, ""]: username = "******" elif recipient_id in username_map: username = username_map.get(recipient_id) else: username = "******" try: if event.couch_recipient_doc_type == "CommCareCase": username = CommCareCase.get(recipient_id).name else: username = CouchUser.get_by_user_id( recipient_id).username except Exception: pass username_map[recipient_id] = username timestamp = tz_utils.adjust_datetime_to_timezone( event.date, pytz.utc.zone, self.timezone.zone) row = [ self._fmt_timestamp(timestamp), self._fmt(username), self._fmt(status_descriptions.get(event.status, "-")), ] result.append(row) return result
def process_change(self, change): if change.deleted or change.metadata is None: return doc = change.get_document() if not doc: return build_id = doc.get('build_id') domain = change.metadata.domain if build_id and domain: # Marks if a build has a submission. The function is cached based on domain # and build_id so that there is no need to fetch the app again after this # is called. Any subsequent calls with the same arguments will result in # the same effect, an app having has_submissions set to True. mark_has_submission(domain, build_id) user_id = doc.get('form', {}).get('meta', {}).get('userID') if user_id in WEIRD_USER_IDS: return try: received_on = string_to_utc_datetime(doc.get('received_on')) except ValueError: return app_id = doc.get('app_id') version = doc.get('version') try: metadata = doc['form']['meta'] except KeyError: metadata = None if user_id and domain and received_on: if settings.USER_REPORTING_METADATA_BATCH_ENABLED: UserReportingMetadataStaging.add_submission( domain, user_id, app_id, build_id, version, metadata, received_on) else: user = CouchUser.get_by_user_id(user_id, domain) if not user or user.is_deleted(): return mark_latest_submission(domain, user, app_id, build_id, version, metadata, received_on)
def verify_phone_number(request, domain, couch_user_id): """ phone_number cannot be passed in the url due to special characters but it can be passed as %-encoded GET parameters """ if 'phone_number' not in request.GET: return Http404('Must include phone number in request.') phone_number = urllib.unquote(request.GET['phone_number']) user = CouchUser.get_by_user_id(couch_user_id, domain) # send verification message smsverify.send_verification(domain, user, phone_number) # create pending verified entry if doesn't exist already user.save_verified_number(domain, phone_number, False, None) return HttpResponseRedirect(reverse("user_account", args=(domain, couch_user_id )))
def _get_location(form): loc_id = form.form.get('location_id') if loc_id: try: return get_location(loc_id) except SQLLocation.DoesNotExist: logging.info('Location %s Not Found.' % loc_id) else: user_id = form.user_id if not user_id: return None try: user = CouchUser.get_by_user_id(user_id) if isinstance(user, CommCareUser): return user.location except ResourceNotFound: logging.info('Location for user %s Not Found.' % user_id)
def _get_location(form): loc_id = form.form.get('location_id') if loc_id: try: return Location.get(loc_id) except ResourceNotFound: logging.info('Location %s Not Found.' % loc_id) else: user_id = form['auth_context']['user_id'] if not user_id: return None try: user = CouchUser.get_by_user_id(user_id) if isinstance(user, CommCareUser): return user.location except ResourceNotFound: logging.info('Location for user %s Not Found.' % user_id)
def get_owned(self, user_id): try: user = CouchUser.get_by_user_id(user_id, self.domain) except KeyError: user = None try: owner_ids = user.get_owner_ids() except AttributeError: owner_ids = [user_id] closed = { CASE_STATUS_OPEN: False, CASE_STATUS_CLOSED: True, CASE_STATUS_ALL: None, }[self.status] ids = self.case_accessors.get_case_ids_by_owners(owner_ids, closed=closed) return self._case_results(ids)
def get_payload(self, repeat_record, payload_doc): configs = self._get_configs(payload_doc) submitting_user = CouchUser.get_by_user_id(payload_doc.user_id) case_blocks = self._get_case_blocks(repeat_record, configs, submitting_user) return render_to_string('hqcase/xml/case_block.xml', { 'xmlns': self.XMLNS, 'case_block': " ".join(case_blocks), 'time': json_format_datetime(datetime.utcnow()), 'uid': str(uuid4()), 'username': self.submission_username(), 'user_id': self.submission_user_id(), 'device_id': f"{self.DEVICE_ID}:{payload_doc.domain}", 'form_data': { "source_domain": payload_doc.domain, "source_form_id": payload_doc.get_form_transactions()[-1].form_id, "source_username": submitting_user.username } })
def _inner(request, domain, couch_user_id, *args, **kwargs): go_ahead = False if hasattr(request, "couch_user"): user = request.couch_user if user.is_superuser or user.user_id == couch_user_id or (hasattr(user, "is_domain_admin") and user.is_domain_admin()): go_ahead = True else: couch_user = CouchUser.get_by_user_id(couch_user_id) if not couch_user: raise Http404() if couch_user.is_commcare_user() and request.couch_user.can_edit_commcare_users(): go_ahead = True elif couch_user.is_web_user() and request.couch_user.can_edit_web_users(): go_ahead = True if go_ahead: return login_and_domain_required(view_func)(request, domain, couch_user_id, *args, **kwargs) else: raise Http404()
def add_export_email_request(request, domain): download_id = request.POST.get('download_id') user_id = request.couch_user.user_id if download_id is None or user_id is None: return HttpResponseBadRequest(gettext_lazy('Download ID or User ID blank/not provided')) try: download_context = get_download_context(download_id) except TaskFailedError: return HttpResponseServerError(gettext_lazy('Export failed')) if download_context.get('is_ready', False): try: couch_user = CouchUser.get_by_user_id(user_id, domain=domain) except CouchUser.AccountTypeError: return HttpResponseBadRequest(gettext_lazy('Invalid user')) if couch_user is not None: process_email_request(domain, download_id, couch_user.get_email()) else: EmailExportWhenDoneRequest.objects.create(domain=domain, download_id=download_id, user_id=user_id) return HttpResponse(gettext_lazy('Export e-mail request sent.'))
def import_locations_async(domain, file_ref_id, user_id): try: importer = MultiExcelImporter(import_locations_async, file_ref_id) user = CouchUser.get_by_user_id(user_id) results = new_locations_import(domain, importer, user) importer.mark_complete() if LOCATIONS_IN_UCR.enabled(domain): # We must rebuild datasources once the location import is complete in # case child locations were not updated, but a parent location was. # For example if a state was updated, the county may reference the state # and need to have its row updated datasources = get_datasources_for_domain(domain, "Location", include_static=True) for datasource in datasources: rebuild_indicators_in_place.delay(datasource.get_id, initiated_by=user.username, source='import_locations') if getattr(settings, 'CELERY_TASK_ALWAYS_EAGER', False): # Log results because they are not sent to the view when # CELERY_TASK_ALWAYS_EAGER is true logging.getLogger(__name__).info( "import_locations_async %s results: %s -> success=%s", file_ref_id, " ".join("%s=%r" % (name, getattr(results, name)) for name in ["messages", "warnings", "errors"] if getattr(results, name)), results.success, ) except Exception as e: notify_exception(None, message=str(e)) results = LocationUploadResult() results.errors = [str(e)] return { 'messages': { 'messages': results.messages, 'errors': results.errors, 'warnings': results.warnings, 'success': results.success, } }
def get_owner(self): if not self.owner_id: raise ConfigurationError('Owner ID missing') try: if self.owner_type == OWNER_TYPE_GROUP: return Group.get(self.owner_id) elif self.owner_type == OWNER_TYPE_LOCATION: return SQLLocation.objects.get(location_id=self.owner_id) elif self.owner_type == OWNER_TYPE_USER: user = CouchUser.get_by_user_id(self.owner_id) if user: return user else: raise ResourceNotFound() else: raise ConfigurationError(f'Unknown owner type {self.owner_type!r}') except (ResourceNotFound, SQLLocation.DoesNotExist): raise ConfigurationError(f'{self.owner_type.capitalize()} ' f'{self.owner_id!r} does not exist')
def redirect(self): redirect = None user = CouchUser.get_by_user_id(self.couch_user._id, self.domain) if user: if (user.has_permission(self.domain, 'edit_commcare_users') or user.has_permission(self.domain, 'view_commcare_users')): from corehq.apps.users.views.mobile import MobileWorkerListView redirect = reverse( MobileWorkerListView.urlname, args=[self.domain] ) elif (user.has_permission(self.domain, 'edit_groups') or user.has_permission(self.domain, 'view_groups')): from corehq.apps.users.views.mobile import GroupsListView redirect = reverse( GroupsListView.urlname, args=[self.domain] ) elif (user.has_permission(self.domain, 'edit_web_users') or user.has_permission(self.domain, 'view_web_users')): redirect = reverse( ListWebUsersView.urlname, args=[self.domain] ) elif user.has_permission(self.domain, 'view_roles'): from corehq.apps.users.views import ListRolesView redirect = reverse( ListRolesView.urlname, args=[self.domain] ) elif (user.has_permission(self.domain, 'edit_locations') or user.has_permission(self.domain, 'view_locations')): from corehq.apps.locations.views import LocationsListView redirect = reverse( LocationsListView.urlname, args=[self.domain] ) return redirect
def populate_export_download_task(export_instances, filters, download_id, filename=None, expiry=10 * 60 * 60): export_file = get_export_file( export_instances, filters, # We don't have a great way to calculate progress if it's a bulk download, # so only track the progress for single instance exports. progress_tracker=populate_export_download_task if len(export_instances) == 1 else None) file_format = Format.from_format(export_file.format) filename = filename or export_instances[0].name with export_file as file_: db = get_blob_db() db.put(file_, download_id, timeout=expiry) expose_blob_download( download_id, mimetype=file_format.mimetype, content_disposition=safe_filename_header(filename, file_format.extension), download_id=download_id, ) domain = export_instances[0].domain email_requests = EmailExportWhenDoneRequest.objects.filter( domain=domain, download_id=download_id) for email_request in email_requests: try: couch_user = CouchUser.get_by_user_id(email_request.user_id, domain=domain) except CouchUser.AccountTypeError: pass else: if couch_user is not None: process_email_request(domain, download_id, couch_user.get_email()) email_requests.delete()
def process_view(self, request, view_func, view_args, view_kwargs): request.analytics_enabled = True if 'domain' in view_kwargs: request.domain = view_kwargs['domain'] if 'org' in view_kwargs: request.org = view_kwargs['org'] if request.user and request.user.is_authenticated: user_id = username_to_user_id(request.user.username) couch_user = CouchUser.get_by_user_id(user_id) if not couch_user: couch_user = InvalidUser() request.couch_user = couch_user if not request.couch_user.analytics_enabled: request.analytics_enabled = False if 'domain' in view_kwargs: domain = request.domain request.couch_user.current_domain = domain elif is_public_reports(view_kwargs, request): request.couch_user = AnonymousCouchUser() return None
def get_contact(domain, contact_id): contact = None try: contact = CommCareCase.objects.get_case(contact_id, domain) except (ResourceNotFound, CaseNotFound): pass if contact and contact.doc_type == 'CommCareCase' and contact.domain == domain: return contact contact = None try: contact = CouchUser.get_by_user_id(contact_id, domain=domain) except CouchUser.AccountTypeError: pass if not contact: raise ContactNotFoundException("Contact not found") return contact
def process_dots_submission(sender, xform, **kwargs): from pact.tasks import recalculate_dots_data, eval_dots_block try: if xform.xmlns != "http://dev.commcarehq.org/pact/dots_form": return #grrr, if we were on celery 3.0, we could do this! # chain = eval_dots_block.s(xform.to_json()) | recalculate_dots_data.s(case_id) # chain() eval_dots_block(xform.to_json()) case_id = get_case_id(xform) # get user from xform user_id = xform.metadata.userID cc_user = CouchUser.get_by_user_id(user_id) last_sync_token = getattr(xform, 'last_sync_token', None) recalculate_dots_data(case_id, cc_user, sync_token=last_sync_token) except Exception as ex: tb = traceback.format_exc() notify_exception(None, message="Error processing PACT DOT submission due to an unknown error: %s\n\tTraceback: %s" % (ex, tb))
def get_owned(self, user_id): try: user = CouchUser.get_by_user_id(user_id, self.domain) except KeyError: user = None try: owner_ids = user.get_owner_ids() except AttributeError: owner_ids = [user_id] @list @inline def keys(): for owner_id in owner_ids: for bool in status_to_closed_flags(self.status): yield [self.domain, owner_id, bool] view_results = CommCareCase.view('hqcase/by_owner', keys=keys, include_docs=False, reduce=False) ids = [res["id"] for res in view_results] return self._case_results(ids)