def set_parameters(self, request): self.user = request.user self.registry_code = request.GET.get("registry_code") self.registry_model = get_object_or_404(Registry, code=self.registry_code) self.clinicians_have_patients = self.registry_model.has_feature( "clinicians_have_patients") self.form_progress = FormProgress(self.registry_model) self.supports_contexts = self.registry_model.has_feature("contexts") self.rdrf_context_manager = RDRFContextManager(self.registry_model) def getint(param): try: return int(request.POST.get(param) or 0) except ValueError: return 0 self.search_term = request.POST.get("search[value]") or "" self.draw = getint("draw") # unknown self.start = getint("start") # offset self.length = getint("length") # page size self.page_number = ( (self.start / self.length) if self.length else 0) + 1 self.sort_field, self.sort_direction = self.get_ordering(request) self.columns = self.get_configure_columns()
def save_form_progress(self, registry_code, context_model=None): from rdrf.forms.progress.form_progress import FormProgress registry_model = Registry.objects.get(code=registry_code) form_progress = FormProgress(registry_model) dynamic_data = self.load_dynamic_data(registry_code, "cdes", flattened=False) return form_progress.save_progress(self.obj, dynamic_data, context_model)
def __init__(self, registry_model, patient_model, form_model, context_form_group, context_model=None): self.registry_model = registry_model self.context_form_group = context_form_group self.patient_model = patient_model self.form_model = form_model self.context_model = context_model self.progress = FormProgress(self.registry_model) # if no progress cdes defined on form, don't show any percentage self.has_progress = form_model.has_progress_indicator
class FormWrapper(object): def __init__(self, registry_model, patient_model, form_model, context_form_group, context_model=None): self.registry_model = registry_model self.context_form_group = context_form_group self.patient_model = patient_model self.form_model = form_model self.context_model = context_model self.progress = FormProgress(self.registry_model) # if no progress cdes defined on form, don't show any percentage self.has_progress = form_model.has_progress_indicator @property def link(self): return reverse('registry_form', args=(self.registry_model.code, self.form_model.id, self.patient_model.pk, self.context_model.id)) @property def title(self): if not self.context_form_group or self.context_form_group.context_type == "F": return self.form_model.nice_name else: # multiple group if self.context_form_group.supports_direct_linking: value = self.context_form_group.get_name_from_cde( self.patient_model, self.context_model) if not value: return "Not set" else: return value else: return self.context_form_group.name + " " + self.form_model.nice_name @property def progress_percentage(self): return self.progress.get_form_progress(self.form_model, self.patient_model, self.context_model) @property def is_current(self): return self.progress.get_form_currency(self.form_model, self.patient_model, self.context_model)
def _update_progress(self): form_progress = FormProgress(self.registry_model) for patient_model in Patient.objects.filter( rdrf_registry__in=[self.registry_model]): if not self.registry_model.has_feature("contexts"): default_context = patient_model.default_context( self.registry_model) form_progress.save_for_patient(patient_model, default_context) self.stdout.write("Recalculated progress for Patient %s" % patient_model.pk) else: self.stderr.write( "Script does not support registries with multiple contexts allowed, yet" ) sys.exit(1)
def __init__(self, registry_model, column, form_model=None, section_model=None, cde_model=None, field=None): self.registry_model = registry_model self.column = column self.form_model = form_model self.section_model = section_model self.form_progress = FormProgress(self.registry_model) self.progress_percentage = None if self.section_model: self.is_multiple = section_model.allow_multiple else: self.is_multiple = False self.cde_model = cde_model self.field = field
class PatientsListingView(View): def __init__(self, *args, **kwargs): super(PatientsListingView, self).__init__(*args, **kwargs) self.registry_model = None self.user = None self.registries = [] self.patient_id = None # grid params self.custom_ordering = None self.start = None self.length = None self.page_number = None self.sort_field = None self.sort_direction = None self.columns = None self.queryset = None self.records_total = None self.filtered_total = None self.context = {} def get(self, request): # get just displays the empty table and writes the page # which initiates an ajax/post request on registry select # the protocol is the jquery DataTable # see http://datatables.net/manual/server-side self.user = request.user if self.user and self.user.is_anonymous: login_url = "%s?next=%s" % (reverse("two_factor:login"), reverse("login_router")) return redirect(login_url) self.do_security_checks() self.set_csrf(request) self.set_registry(request) self.set_registries() # for drop down self.patient_id = request.GET.get("patient_id", None) template_context = self.build_context() template = self.get_template() return render(request, template, template_context) def get_template(self): template = 'rdrf_cdes/patients_listing_no_registries.html' if len( self.registries) == 0 else 'rdrf_cdes/patients_listing.html' return template def build_context(self): return { "registries": self.registries, "location": _("Patient Listing"), "patient_id": self.patient_id, "registry_code": self.registry_model.code if self.registry_model else None, "columns": [ col.to_dict(i) for (i, col) in enumerate(self.get_configure_columns()) ], } def get_columns(self): return [ ColumnFullName(_("Patient"), "patients.can_see_full_name"), ColumnDateOfBirth(_("Date of Birth"), "patients.can_see_dob"), ColumnCodeField(_("Code"), "patients.can_see_code_field"), ColumnWorkingGroups(_("Working Groups"), "patients.can_see_working_groups"), ColumnDiagnosisProgress(_("Diagnosis Entry Progress"), "patients.can_see_diagnosis_progress"), ColumnDiagnosisCurrency(_("Updated < 365 days"), "patients.can_see_diagnosis_currency"), ColumnGeneticDataMap(_("Genetic Data"), "patients.can_see_genetic_data_map"), ColumnContextMenu(_("Modules"), "patients.can_see_data_modules"), ] def get_configure_columns(self): columns = self.get_columns() for i, col in enumerate(columns): col.configure(self.registry_model, self.user, i) return [col for col in columns if col.user_can_see] def do_security_checks(self): if self.user.is_patient: raise PermissionDenied() def set_csrf(self, request): self.context.update(csrf(request)) def set_registry(self, request): registry_code = request.GET.get("registry_code", None) if registry_code is not None: try: self.registry_model = Registry.objects.get(code=registry_code) except Registry.DoesNotExist: return HttpResponseRedirect("/") def set_registries(self): if self.registry_model is None: if self.user.is_superuser: self.registries = [ registry_model for registry_model in Registry.objects.all() ] else: self.registries = [ registry_model for registry_model in self.user.registry.all() ] else: self.registries = [self.registry_model] def json(self, data): json_data = json.dumps(data) return HttpResponse(json_data, content_type="application/json") def post(self, request): # see http://datatables.net/manual/server-side self.user = request.user if self.user and self.user.is_anonymous: login_url = "%s?next=%s" % (reverse("two_factor:login"), reverse("login_router")) return redirect(login_url) self.set_parameters(request) self.set_csrf(request) rows = self.get_results(request) results_dict = self.get_results_dict(self.draw, self.page_number, self.record_total, self.filtered_total, rows) return self.json(results_dict) def set_parameters(self, request): self.user = request.user self.registry_code = request.GET.get("registry_code") self.registry_model = get_object_or_404(Registry, code=self.registry_code) self.clinicians_have_patients = self.registry_model.has_feature( "clinicians_have_patients") self.form_progress = FormProgress(self.registry_model) self.supports_contexts = self.registry_model.has_feature("contexts") self.rdrf_context_manager = RDRFContextManager(self.registry_model) def getint(param): try: return int(request.POST.get(param) or 0) except ValueError: return 0 self.search_term = request.POST.get("search[value]") or "" self.draw = getint("draw") # unknown self.start = getint("start") # offset self.length = getint("length") # page size self.page_number = ( (self.start / self.length) if self.length else 0) + 1 self.sort_field, self.sort_direction = self.get_ordering(request) self.columns = self.get_configure_columns() def get_results(self, request): if self.registry_model is None: return [] if not self.check_security(): return [] patients = self.run_query() return patients def check_security(self): self.do_security_checks() if not self.user.is_superuser: if self.registry_model.code not in [ r.code for r in self.user.registry.all() ]: logger.warning( "User id %s tried to browse patients in registry %s of which they are not a member" % (self.user.id, self.registry_model.code)) return False return True def get_ordering(self, request): # columns[0][data]:full_name # order[0][column]:1 # order[0][dir]:asc sort_column_index = None sort_direction = None for key in request.POST: if key.startswith("order"): if "[column]" in key: sort_column_index = request.POST[key] elif "[dir]" in key: sort_direction = request.POST[key] column_name = "columns[%s][data]" % sort_column_index sort_field = request.POST.get(column_name, None) return sort_field, sort_direction def run_query(self): self.get_initial_queryset() self.filter_by_user_group() self.apply_ordering() self.record_total = self.patients.count() self.apply_search_filter() self.filtered_total = self.patients.count() return self.get_rows_in_page() def _get_main_or_default_context(self, patient_model): # for registries which do not have multiple contexts this will be the single context model # assigned to the patient # for registries which allow multiple form groups, it will be the # (only) context with cfg marked as default context_model = patient_model.default_context(self.registry_model) assert context_model is not None, "Expected context model to exist always" if context_model.context_form_group: assert context_model.context_form_group.is_default, "Expected to always get a context of the default form group" return context_model def apply_custom_ordering(self, qs): key_func = [ col.sort_key(self.supports_contexts, self.form_progress, self.rdrf_context_manager) for col in self.columns if col.field == self.sort_field and col.sort_key and not col.sort_fields ] if key_func: # we have to retrieve all rows - otherwise , queryset has already been # ordered on base model k = key_func[0] def key_func_wrapper(thing): value = k(thing) if value is None: return self.bottom else: return value return sorted(qs, key=key_func_wrapper, reverse=(self.sort_direction == "desc")) else: return qs def get_rows_in_page(self): results = self.apply_custom_ordering(self.patients) rows = [] paginator = Paginator(results, self.length) try: page = paginator.page(self.page_number) except InvalidPage: logger.error("invalid page number: %s" % self.page_number) return [] self.append_rows(page, rows) return rows def append_rows(self, page_object, row_list_to_update): if self.registry_model.has_feature("consent_checks"): row_list_to_update.extend([ self._get_row_dict(obj) for obj in page_object.object_list if consent_check( self.registry_model, self.user, obj, "see_patient") ]) else: row_list_to_update.extend( [self._get_row_dict(obj) for obj in page_object.object_list]) def _get_row_dict(self, instance): # we need to do this so that the progress data for this instance # loaded! self.form_progress.reset() self.form_progress._set_current(instance) return { col.field: col.fmt( col.cell(instance, self.supports_contexts, self.form_progress, self.rdrf_context_manager)) for col in self.columns } def get_initial_queryset(self): self.registry_queryset = Registry.objects.filter( code=self.registry_model.code) self.patients = Patient.objects.all().prefetch_related( "working_groups").prefetch_related("rdrf_registry").filter( rdrf_registry__code=self.registry_model.code) def apply_search_filter(self): if self.search_term: self.patients = self.patients.filter( Q(given_names__icontains=self.search_term) | Q(family_name__icontains=self.search_term)) def filter_by_user_group(self): if not self.user.is_superuser: if self.user.is_curator: query_patients = Q( rdrf_registry__in=self.registry_queryset) & Q( working_groups__in=self.user.working_groups.all()) self.patients = self.patients.filter(query_patients) elif self.user.is_genetic_staff: self.patients = self.patients.filter( working_groups__in=self.user.working_groups.all()) elif self.user.is_genetic_curator: self.patients = self.patients.filter( working_groups__in=self.user.working_groups.all()) elif self.user.is_working_group_staff: self.patients = self.patients.filter( working_groups__in=self.user.working_groups.all()) elif self.user.is_clinician and self.clinicians_have_patients: self.patients = self.patients.filter(clinician=self.user) elif self.user.is_clinician and not self.clinicians_have_patients: query_patients = Q( rdrf_registry__in=self.registry_queryset) & Q( working_groups__in=self.user.working_groups.all()) self.patients = self.patients.filter(query_patients) elif self.user.is_patient: self.patients = self.patients.filter(user=self.user) else: self.patients = self.patients.none() else: self.patients = self.patients.filter( rdrf_registry__in=self.registry_queryset) def apply_ordering(self): if self.sort_field and self.sort_direction: def sdir(field): return "-" + field if self.sort_direction == "desc" else field sort_fields = chain(*[ map(sdir, col.sort_fields) for col in self.columns if col.field == self.sort_field ]) self.patients = self.patients.order_by(*sort_fields) def get_results_dict(self, draw, page, total_records, total_filtered_records, rows): return { "draw": draw, "recordsTotal": total_records, "recordsFiltered": total_filtered_records, "rows": rows }
class DataSource: def __init__(self, registry_model, column, form_model=None, section_model=None, cde_model=None, field=None): self.registry_model = registry_model self.column = column self.form_model = form_model self.section_model = section_model self.form_progress = FormProgress(self.registry_model) self.progress_percentage = None if self.section_model: self.is_multiple = section_model.allow_multiple else: self.is_multiple = False self.cde_model = cde_model self.field = field @property def datatype(self): return lower_strip(self.cde_model.datatype) @property def column_name(self): return self.column.name def get_value(self, patient_model, context_model): if self.field: return self._get_field_value(patient_model, context_model) else: return self._get_cde_value(patient_model, context_model) def _get_field_value(self, patient_model, context_model): if self.field == "patient_id": return patient_model.pk elif self.field == "form": return self.form_model.name elif self.field == "context_id": return context_model.pk elif self.field == "section": return self.section_model.display_name elif self.field == "form_group": return get_form_group(context_model) elif self.field == "username": return self._get_last_user(patient_model, context_model) elif self.field == "timestamp": return patient_model.get_form_timestamp(self.form_model, context_model) elif self.field == "progress": return self._get_form_progress(patient_model, context_model) else: raise Exception("Unknown field: %s" % self.field) def _get_form_progress(self, patient_model, context_model): if self.progress_percentage is None: self.progress_percentage = self.form_progress.get_form_progress( self.form_model, patient_model, context_model) return self.progress_percentage def _get_last_user(self, patient_model, context_model): # last user to edit the _form_ in this context history = ClinicalData.objects.collection(self.registry_model.code, "history") snapshots = history.find(patient_model, record_type="snapshot") snapshots = sorted([s for s in snapshots], key=attrgetter("pk"), reverse=True) for snapshot in snapshots: if snapshot.data and "record" in snapshot.data: record = snapshot.data["record"] if "context_id" in record: if context_model.pk == record["context_id"]: if "form_name" in snapshot.data: form_name = snapshot.data["form_name"] if form_name == self.form_model.name: if "form_user" in snapshot.data: return snapshot.data["form_user"] def _get_cde_value(self, patient_model, context_model): try: data = get_clinical_data(self.registry_model.code, patient_model.pk, context_model.pk) raw_value = patient_model.get_form_value( self.registry_model.code, self.form_model.name, self.section_model.code, self.cde_model.code, False, context_id=context_model.pk, clinical_data=data) except KeyError: # the dynamic data record is empty return None value = self.cde_model.get_display_value(raw_value) return fix_display_value(self.cde_model.datatype, value)