diff --git a/smash/web/api_views/subject.py b/smash/web/api_views/subject.py index 808cf020e38baab072d52113df9c2f29c2eb635f..2ee56a843200565748644a27b4c298291cf526df 100644 --- a/smash/web/api_views/subject.py +++ b/smash/web/api_views/subject.py @@ -1,7 +1,6 @@ from django.db.models import F import logging import re -from distutils.util import strtobool from django.core.handlers.wsgi import WSGIRequest from django.db.models import Count, Case, When, Min, Max, QuerySet @@ -9,6 +8,7 @@ from django.db.models import Q from django.http import JsonResponse, HttpRequest, HttpResponseNotAllowed, HttpResponse from django.urls import reverse +from web.utils import strtobool from web.api_views.serialization_utils import ( str_to_yes_no_null, bool_to_yes_no, @@ -42,7 +42,10 @@ from web.models.constants import ( CUSTOM_FIELD_TYPE_SELECT_LIST, CUSTOM_FIELD_TYPE_FILE, ) -from web.models.custom_data.custom_study_subject_field import get_study_subject_field_id, CustomStudySubjectField +from web.models.custom_data.custom_study_subject_field import ( + get_study_subject_field_id, + CustomStudySubjectField, +) from web.models.study_subject_list import ( SUBJECT_LIST_GENERIC, SUBJECT_LIST_NO_VISIT, @@ -63,20 +66,28 @@ logger = logging.getLogger(__name__) # noinspection PyUnusedLocal def cities(request): - result_subjects = Subject.objects.filter(city__isnull=False).values_list("city").distinct() + result_subjects = ( + Subject.objects.filter(city__isnull=False).values_list("city").distinct() + ) return JsonResponse({"cities": [x[0] for x in result_subjects]}) # noinspection PyUnusedLocal def referrals(request): - result_subjects = StudySubject.objects.filter(referral__isnull=False).values_list("referral").distinct() + result_subjects = ( + StudySubject.objects.filter(referral__isnull=False) + .values_list("referral") + .distinct() + ) return JsonResponse({"referrals": [x[0] for x in result_subjects]}) # noinspection PyUnusedLocal def get_subject_columns(request: HttpRequest, subject_list_type: str) -> JsonResponse: study = Study.objects.filter(id=GLOBAL_STUDY_ID)[0] - study_subject_lists = StudySubjectList.objects.filter(study=study, type=subject_list_type) + study_subject_lists = StudySubjectList.objects.filter( + study=study, type=subject_list_type + ) if len(study_subject_lists) > 0: study_subject_list = study_subject_lists[0] subject_columns = study_subject_list.visible_subject_columns @@ -87,19 +98,59 @@ def get_subject_columns(request: HttpRequest, subject_list_type: str) -> JsonRes study_subject_columns = StudyColumns() result = [] - add_column(result, "Subject number", "nd_number", study_subject_columns, "string_filter", study.columns) - add_column(result, "Screening", "screening_number", study_subject_columns, "string_filter", study.columns) + add_column( + result, + "Subject number", + "nd_number", + study_subject_columns, + "string_filter", + study.columns, + ) + add_column( + result, + "Screening", + "screening_number", + study_subject_columns, + "string_filter", + study.columns, + ) add_column(result, "First name", "first_name", subject_columns, "string_filter") add_column(result, "Last name", "last_name", subject_columns, "string_filter") add_column(result, "Address", "address", subject_columns, "string_filter") - add_column(result, "Social Security Number", "social_security_number", subject_columns, "string_filter") + add_column( + result, + "Social Security Number", + "social_security_number", + subject_columns, + "string_filter", + ) add_column(result, "Phone number", "phone_number", subject_columns, "string_filter") - add_column(result, "Phone number 2", "phone_number_2", subject_columns, "string_filter") - add_column(result, "Phone number 3", "phone_number_3", subject_columns, "string_filter") + add_column( + result, "Phone number 2", "phone_number_2", subject_columns, "string_filter" + ) + add_column( + result, "Phone number 3", "phone_number_3", subject_columns, "string_filter" + ) add_column(result, "Date of birth", "date_born", subject_columns, None) - add_column(result, "Contact on", "datetime_contact_reminder", study_subject_columns, None, study.columns) - add_column(result, "Last contact attempt", "last_contact_attempt", study_subject_list, None) - add_column(result, "Referred by", "referral", study_subject_columns, "string_filter", study.columns) + add_column( + result, + "Contact on", + "datetime_contact_reminder", + study_subject_columns, + None, + study.columns, + ) + add_column( + result, "Last contact attempt", "last_contact_attempt", study_subject_list, None + ) + add_column( + result, + "Referred by", + "referral", + study_subject_columns, + "string_filter", + study.columns, + ) add_column( result, "Health partner name", @@ -118,19 +169,80 @@ def get_subject_columns(request: HttpRequest, subject_list_type: str) -> JsonRes add_param=study.columns.health_partner, visible_param=study_subject_columns.health_partner, ) - add_column(result, "Location", "default_location", study_subject_columns, "location_filter", study.columns) add_column( - result, "Flying team location", "flying_team", study_subject_columns, "flying_team_filter", study.columns + result, + "Location", + "default_location", + study_subject_columns, + "location_filter", + study.columns, + ) + add_column( + result, + "Flying team location", + "flying_team", + study_subject_columns, + "flying_team_filter", + study.columns, ) add_column(result, "Deceased", "dead", subject_columns, "yes_no_filter") - add_column(result, "Resigned", "resigned", study_subject_columns, "yes_no_filter", study.columns) - add_column(result, "Endpoint Reached", "endpoint_reached", study_subject_columns, "yes_no_filter", study.columns) - add_column(result, "Postponed", "postponed", study_subject_columns, "yes_no_filter", study.columns) - add_column(result, "Next of kin", "next_of_kin_name", subject_columns, "string_filter") - add_column(result, "Next of kin phone", "next_of_kin_phone", subject_columns, "string_filter") - add_column(result, "Next of kin address", "next_of_kin_address", subject_columns, "string_filter") - add_column(result, "Excluded", "excluded", study_subject_columns, "yes_no_filter", study.columns) - add_column(result, "Info sent", "information_sent", study_subject_columns, "yes_no_filter", study.columns) + add_column( + result, + "Resigned", + "resigned", + study_subject_columns, + "yes_no_filter", + study.columns, + ) + add_column( + result, + "Endpoint Reached", + "endpoint_reached", + study_subject_columns, + "yes_no_filter", + study.columns, + ) + add_column( + result, + "Postponed", + "postponed", + study_subject_columns, + "yes_no_filter", + study.columns, + ) + add_column( + result, "Next of kin", "next_of_kin_name", subject_columns, "string_filter" + ) + add_column( + result, + "Next of kin phone", + "next_of_kin_phone", + subject_columns, + "string_filter", + ) + add_column( + result, + "Next of kin address", + "next_of_kin_address", + subject_columns, + "string_filter", + ) + add_column( + result, + "Excluded", + "excluded", + study_subject_columns, + "yes_no_filter", + study.columns, + ) + add_column( + result, + "Info sent", + "information_sent", + study_subject_columns, + "yes_no_filter", + study.columns, + ) add_column( result, "Default Written Communication Language", @@ -139,16 +251,22 @@ def get_subject_columns(request: HttpRequest, subject_list_type: str) -> JsonRes "language_filter", ) - visit_from_zero = ConfigurationItem.objects.get(type=VISIT_SHOW_VISIT_NUMBER_FROM_ZERO).value + visit_from_zero = ConfigurationItem.objects.get( + type=VISIT_SHOW_VISIT_NUMBER_FROM_ZERO + ).value # True values are y, yes, t, true, on and 1; false values are n, no, f, false, off and 0. if strtobool(visit_from_zero): visit_numbers = list(range(0, study.visits_to_show_in_subject_list + 0)) else: visit_numbers = list(range(1, study.visits_to_show_in_subject_list + 1)) - add_column(result, "Type", "type", study_subject_columns, "type_filter", study.columns) + add_column( + result, "Type", "type", study_subject_columns, "type_filter", study.columns + ) for custom_study_subject_field in study.customstudysubjectfield_set.all(): - visible = study_subject_columns.is_custom_field_visible(custom_study_subject_field) + visible = study_subject_columns.is_custom_field_visible( + custom_study_subject_field + ) if custom_study_subject_field.type == CUSTOM_FIELD_TYPE_TEXT: add_column( result, @@ -222,7 +340,12 @@ def get_subject_columns(request: HttpRequest, subject_list_type: str) -> JsonRes for one_based_idx, visit_number in enumerate(visit_numbers, 1): visit_key = f"visit_{one_based_idx}" # always starts in 1 add_column( - result, f"Visit {visit_number}", visit_key, None, "visit_filter", visible_param=study_subject_list.visits + result, + f"Visit {visit_number}", + visit_key, + None, + "visit_filter", + visible_param=study_subject_list.visits, ) return JsonResponse({"columns": result}) @@ -243,11 +366,15 @@ def get_subjects(request, list_type): def order_by_visit(subjects_to_be_ordered, order_f, visit_number): return subjects_to_be_ordered.annotate( - sort_visit_date=Min(Case(When(visit__visit_number=visit_number, then="visit__datetime_begin"))) + sort_visit_date=Min( + Case(When(visit__visit_number=visit_number, then="visit__datetime_begin")) + ) ).order_by(order_f("sort_visit_date")) -def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_direction, column_filters=None): +def get_subjects_order( + subjects_to_be_ordered: QuerySet, order_column, order_direction, column_filters=None +): if column_filters is None: column_filters = {} result = subjects_to_be_ordered @@ -274,13 +401,17 @@ def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_dir elif order_column == "next_of_kin_phone": result = subjects_to_be_ordered.order_by(order_f("subject__next_of_kin_phone")) elif order_column == "next_of_kin_address": - result = subjects_to_be_ordered.order_by(order_f("subject__next_of_kin_address")) + result = subjects_to_be_ordered.order_by( + order_f("subject__next_of_kin_address") + ) elif order_column == "nd_number": result = subjects_to_be_ordered.order_by(order_f("nd_number")) elif order_column == "referral": result = subjects_to_be_ordered.order_by(order_f("referral")) elif order_column == "default_written_communication_language": - result = subjects_to_be_ordered.order_by(order_f("subject__default_written_communication_language__name")) + result = subjects_to_be_ordered.order_by( + order_f("subject__default_written_communication_language__name") + ) elif order_column == "phone_number": result = subjects_to_be_ordered.order_by(order_f("subject__phone_number")) elif order_column == "phone_number_2": @@ -295,7 +426,9 @@ def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_dir result = subjects_to_be_ordered.all() result = sorted( result, - key=lambda t: t.sort_matched_screening_first(pattern, reverse=order_direction != "asc"), + key=lambda t: t.sort_matched_screening_first( + pattern, reverse=order_direction != "asc" + ), reverse=order_direction != "asc", ) elif order_column == "default_location": @@ -315,7 +448,9 @@ def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_dir elif order_column == "health_partner_last_name": result = subjects_to_be_ordered.order_by(order_f("health_partner__last_name")) elif order_column == "social_security_number": - result = subjects_to_be_ordered.order_by(order_f("subject__social_security_number")) + result = subjects_to_be_ordered.order_by( + order_f("subject__social_security_number") + ) elif order_column == "postponed": result = subjects_to_be_ordered.order_by(order_f("postponed")) elif order_column == "excluded": @@ -330,9 +465,9 @@ def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_dir result = subjects_to_be_ordered.order_by(order_f("datetime_contact_reminder")) elif order_column == "last_contact_attempt": # noinspection SpellCheckingInspection - result = subjects_to_be_ordered.annotate(sort_contact_attempt=Max("contactattempt__datetime_when")).order_by( - order_f("sort_contact_attempt") - ) + result = subjects_to_be_ordered.annotate( + sort_contact_attempt=Max("contactattempt__datetime_when") + ).order_by(order_f("sort_contact_attempt")) elif str(order_column).startswith("visit_"): visit_number = get_visit_number_from_visit_x_string(order_column) result = order_by_visit(subjects_to_be_ordered, order_f, visit_number) @@ -342,7 +477,8 @@ def get_subjects_order(subjects_to_be_ordered: QuerySet, order_column, order_dir custom_field_value=Min( Case( When( - customstudysubjectvalue__study_subject_field__id=field_id, then="customstudysubjectvalue__value" + customstudysubjectvalue__study_subject_field__id=field_id, + then="customstudysubjectvalue__value", ) ) ) @@ -362,8 +498,12 @@ def filter_by_visit(result, visit_number, visit_type): datetime_begin_filter = "visit_" + str(visit_number) + "_datetime_begin" datetime_end_filter = "visit_" + str(visit_number) + "_datetime_end" is_finished_filter = "visit_" + str(visit_number) + "_is_finished" - finished_appointments_filter = "visit_" + str(visit_number) + "_finished_appointments" - scheduled_appointments_filter = "visit_" + str(visit_number) + "_scheduled_appointments" + finished_appointments_filter = ( + "visit_" + str(visit_number) + "_finished_appointments" + ) + scheduled_appointments_filter = ( + "visit_" + str(visit_number) + "_scheduled_appointments" + ) # this is hack... instead of providing True/False value this field contain 1/0 value, the problem is that we need # to provide aggregate function for the interacting parameter @@ -372,7 +512,13 @@ def filter_by_visit(result, visit_number, visit_type): result = result.annotate( **{ is_finished_filter: Count( - Case(When(Q(visit__is_finished=True) & Q(visit__visit_number=visit_number), then=1)) + Case( + When( + Q(visit__is_finished=True) + & Q(visit__visit_number=visit_number), + then=1, + ) + ) ) } ) @@ -383,7 +529,9 @@ def filter_by_visit(result, visit_number, visit_type): finished_appointments_filter: Count( Case( When( - Q(visit__appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED) + Q( + visit__appointment__status=Appointment.APPOINTMENT_STATUS_FINISHED + ) & Q(visit__visit_number=visit_number), then=1, ) @@ -397,7 +545,9 @@ def filter_by_visit(result, visit_number, visit_type): scheduled_appointments_filter: Count( Case( When( - Q(visit__appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED) + Q( + visit__appointment__status=Appointment.APPOINTMENT_STATUS_SCHEDULED + ) & Q(visit__visit_number=visit_number), then=1, ) @@ -408,11 +558,21 @@ def filter_by_visit(result, visit_number, visit_type): # when visit starts result = result.annotate( - **{datetime_begin_filter: Min(Case(When(visit__visit_number=visit_number, then="visit__datetime_begin")))} + **{ + datetime_begin_filter: Min( + Case( + When(visit__visit_number=visit_number, then="visit__datetime_begin") + ) + ) + } ) # when visit finish result = result.annotate( - **{datetime_end_filter: Min(Case(When(visit__visit_number=visit_number, then="visit__datetime_end")))} + **{ + datetime_end_filter: Min( + Case(When(visit__visit_number=visit_number, then="visit__datetime_end")) + ) + } ) if visit_type == "DONE": @@ -448,7 +608,9 @@ def filter_by_visit(result, visit_number, visit_type): .filter(**{scheduled_appointments_filter: 0}) ) elif visit_type == "UPCOMING": - result = result.filter(**{datetime_begin_filter + "__gt": get_today_midnight_date()}) + result = result.filter( + **{datetime_begin_filter + "__gt": get_today_midnight_date()} + ) return result @@ -482,7 +644,9 @@ def get_subjects_filtered(subjects_to_be_filtered: QuerySet, filters) -> QuerySe elif column == "referral": result = result.filter(referral__icontains=value) elif column == "default_written_communication_language": - result = result.filter(subject__default_written_communication_language__id=value) + result = result.filter( + subject__default_written_communication_language__id=value + ) elif column == "phone_number": result = result.filter(subject__phone_number__icontains=value) elif column == "phone_number_2": @@ -534,19 +698,26 @@ def get_subjects_filtered(subjects_to_be_filtered: QuerySet, filters) -> QuerySe ) else: result = result.filter( - customstudysubjectvalue__study_subject_field__id=field_id, customstudysubjectvalue__value="" + customstudysubjectvalue__study_subject_field__id=field_id, + customstudysubjectvalue__value="", ) elif field.type in (CUSTOM_FIELD_TYPE_INTEGER, CUSTOM_FIELD_TYPE_DOUBLE): result = result.filter( - customstudysubjectvalue__study_subject_field__id=field_id, customstudysubjectvalue__value=value + customstudysubjectvalue__study_subject_field__id=field_id, + customstudysubjectvalue__value=value, ) elif field.type == CUSTOM_FIELD_TYPE_DATE: result = result.filter( - customstudysubjectvalue__study_subject_field__id=field_id, customstudysubjectvalue__value=value + customstudysubjectvalue__study_subject_field__id=field_id, + customstudysubjectvalue__value=value, ) - elif field.type in (CUSTOM_FIELD_TYPE_INTEGER, CUSTOM_FIELD_TYPE_SELECT_LIST): + elif field.type in ( + CUSTOM_FIELD_TYPE_INTEGER, + CUSTOM_FIELD_TYPE_SELECT_LIST, + ): result = result.filter( - customstudysubjectvalue__study_subject_field__id=field_id, customstudysubjectvalue__value=value + customstudysubjectvalue__study_subject_field__id=field_id, + customstudysubjectvalue__value=value, ) elif field.type == CUSTOM_FIELD_TYPE_FILE: result = result.filter( @@ -583,7 +754,9 @@ def subjects(request: WSGIRequest, subject_list_type: str) -> HttpResponse: length = int(request_data.get("length", "10")) order = int(request_data.get("order[0][column]", "0")) order_dir = request_data.get("order[0][dir]", "asc") - order_column = request_data.get("columns[" + str(order) + "][data]", "last_name") + order_column = request_data.get( + "columns[" + str(order) + "][data]", "last_name" + ) filters = get_filters_for_data_table_request(request_data) @@ -592,11 +765,13 @@ def subjects(request: WSGIRequest, subject_list_type: str) -> HttpResponse: count = all_subjects.count() filtered_subjects = get_subjects_filtered(all_subjects, filters) - ordered_subjects = get_subjects_order(filtered_subjects, order_column, order_dir, column_filters=dict(filters)) + ordered_subjects = get_subjects_order( + filtered_subjects, order_column, order_dir, column_filters=dict(filters) + ) if length == -1: sliced_subjects = ordered_subjects else: - sliced_subjects = ordered_subjects[start: (start + length)] + sliced_subjects = ordered_subjects[start : (start + length)] result_subjects = sliced_subjects @@ -661,7 +836,9 @@ def serialize_subject(study_subject: StudySubject): else: status = "UPCOMING" - appointment_types = [f"{at.code} ({at.description})" for at in visit.appointment_types.all()] + appointment_types = [ + f"{at.code} ({at.description})" for at in visit.appointment_types.all() + ] if len(appointment_types) == 0: appointment_types = ["No appointment types set."] @@ -670,14 +847,18 @@ def serialize_subject(study_subject: StudySubject): "status": status, "appointment_types": appointment_types, "edit_visit_url": reverse("web.views.visit_details", args=(visit.id,)), - "add_appointment_url": reverse("web.views.appointment_add", args=(visit.id,)), + "add_appointment_url": reverse( + "web.views.appointment_add", args=(visit.id,) + ), "datetime_start": serialize_date(visit.datetime_begin), "datetime_end": serialize_date(visit.datetime_end), "is_finished": visit.is_finished, } ) contact_reminder = serialize_datetime(study_subject.datetime_contact_reminder) - contact_attempts = ContactAttempt.objects.filter(subject=study_subject).order_by("-datetime_when") + contact_attempts = ContactAttempt.objects.filter(subject=study_subject).order_by( + "-datetime_when" + ) if len(contact_attempts) > 0: last_contact_attempt = contact_attempts[0] last_contact_attempt_string = ( @@ -700,7 +881,9 @@ def serialize_subject(study_subject: StudySubject): health_partner_last_name = study_subject.health_partner.last_name default_written_communication_language = "" if study_subject.subject.default_written_communication_language: - default_written_communication_language = study_subject.subject.default_written_communication_language.name + default_written_communication_language = ( + study_subject.subject.default_written_communication_language.name + ) result = { "first_name": study_subject.subject.first_name, @@ -746,17 +929,25 @@ def serialize_subject(study_subject: StudySubject): val = "" result[get_study_subject_field_id(field_value.study_subject_field)] = val elif field_value.study_subject_field.type == CUSTOM_FIELD_TYPE_BOOLEAN: - result[get_study_subject_field_id(field_value.study_subject_field)] = str_to_yes_no_null(field_value.value) + result[get_study_subject_field_id(field_value.study_subject_field)] = ( + str_to_yes_no_null(field_value.value) + ) elif field_value.study_subject_field.type == CUSTOM_FIELD_TYPE_DATE: - result[get_study_subject_field_id(field_value.study_subject_field)] = field_value.value + result[get_study_subject_field_id(field_value.study_subject_field)] = ( + field_value.value + ) elif field_value.study_subject_field.type == CUSTOM_FIELD_TYPE_SELECT_LIST: - result[get_study_subject_field_id(field_value.study_subject_field)] = field_value.value + result[get_study_subject_field_id(field_value.study_subject_field)] = ( + field_value.value + ) elif field_value.study_subject_field.type == CUSTOM_FIELD_TYPE_FILE: if field_value.value is None: result[get_study_subject_field_id(field_value.study_subject_field)] = "" else: result[get_study_subject_field_id(field_value.study_subject_field)] = ( - reverse("web.views.uploaded_files") + "?file=" + str(field_value.value) + reverse("web.views.uploaded_files") + + "?file=" + + str(field_value.value) ) else: raise NotImplementedError diff --git a/smash/web/api_views/visit.py b/smash/web/api_views/visit.py index 37fb202edd14632da34c24ca17f04bc4cfdf4faf..880906734e36792a960a63f8ea9afd0b8a75a243 100644 --- a/smash/web/api_views/visit.py +++ b/smash/web/api_views/visit.py @@ -1,10 +1,10 @@ import logging -from distutils.util import strtobool from django.core.handlers.wsgi import WSGIRequest from django.db.models import Q from django.http import JsonResponse, HttpResponseNotAllowed +from web.utils import strtobool from web.api_views.serialization_utils import bool_to_yes_no, flying_team_to_str, location_to_str, add_column, \ serialize_date, get_filters_for_data_table_request from web.models import AppointmentType, Appointment diff --git a/smash/web/forms/forms.py b/smash/web/forms/forms.py index 6d6f40a39d77d5bde4a35dc2dd2ec6c4aad4784d..ab2469d2df76277ec4de740e0d5559cc8ba56118 100644 --- a/smash/web/forms/forms.py +++ b/smash/web/forms/forms.py @@ -1,11 +1,11 @@ import datetime import logging -from distutils.util import strtobool from django import forms from django.forms import ModelForm, Form from django.utils.dates import MONTHS +from web.utils import strtobool from web.models import AppointmentType, Availability, FlyingTeam, Holiday, Item, \ StudySubject, Room, Worker, Visit, ConfigurationItem, SubjectType from web.models.constants import VISIT_SHOW_VISIT_NUMBER_FROM_ZERO diff --git a/smash/web/models/configuration_item.py b/smash/web/models/configuration_item.py index 23a15f40a0db5c224757d4988d2f7c34c04409f6..a38cba7ce76980de662e831c9f0e54a522c95a41 100644 --- a/smash/web/models/configuration_item.py +++ b/smash/web/models/configuration_item.py @@ -1,11 +1,11 @@ # coding=utf-8 import re -from distutils.util import strtobool from django.core.exceptions import ValidationError from django.core.validators import validate_email from django.db import models +from web.utils import strtobool from web.models.constants import CANCELLED_APPOINTMENT_COLOR_CONFIGURATION_TYPE, \ NO_SHOW_APPOINTMENT_COLOR_CONFIGURATION_TYPE, KIT_EMAIL_HOUR_CONFIGURATION_TYPE, \ KIT_EMAIL_DAY_OF_WEEK_CONFIGURATION_TYPE, KIT_DAILY_EMAIL_TIME_FORMAT_TYPE, KIT_DAILY_EMAIL_DAYS_PERIOD_TYPE, \ diff --git a/smash/web/templatetags/filters.py b/smash/web/templatetags/filters.py index 339bd0e3753f14d34b3f39a0f73702e1ac043b96..795cde21fda8f8478a2838957dedf35a65b9cada 100644 --- a/smash/web/templatetags/filters.py +++ b/smash/web/templatetags/filters.py @@ -1,13 +1,13 @@ # See: http://stackoverflow.com/a/18962481 import datetime import os -from distutils.util import strtobool from functools import reduce from django import template from django.forms import CheckboxSelectMultiple, CheckboxInput from django.utils.safestring import mark_safe +from web.utils import strtobool from web.models import ConfigurationItem from web.models.constants import VISIT_SHOW_VISIT_NUMBER_FROM_ZERO diff --git a/smash/web/utils.py b/smash/web/utils.py index 544aa884517ada9a712b312b098563ac60a1aefc..f1a3715e43bb1dcfdb61beb9a04fcf6d787263f8 100644 --- a/smash/web/utils.py +++ b/smash/web/utils.py @@ -11,6 +11,22 @@ from django.utils.text import capfirst from web.algorithm import VerhoeffAlgorithm, LuhnAlgorithm +def strtobool (val): + """Convert a string representation of truth to true (1) or false (0). + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + + From distutils lib + """ + val = val.lower() + if val in ('y', 'yes', 't', 'true', 'on', '1'): + return 1 + elif val in ('n', 'no', 'f', 'false', 'off', '0'): + return 0 + else: + raise ValueError(f"invalid truth value {val}") def get_deleted_objects(objs: List[models.Model]): collector = NestedObjects(using='default') diff --git a/smash/web/views/subject.py b/smash/web/views/subject.py index f181b08d3e40c1376a29f5436a0af2b92e56c4bc..091090c21ddaccdf978520b1ec463ff3aaaf1f7c 100644 --- a/smash/web/views/subject.py +++ b/smash/web/views/subject.py @@ -218,15 +218,17 @@ def subject_edit(request, subject_id): curr_value = study_subject_form.cleaned_data[field_id] if prev_value != curr_value: worker = Worker.get_by_user(request.user) + mod_desc = (f'Worker "{worker}" changed study subject ' + f'"{study_subject.nd_number}" field ' + f'"{field.study_subject_field.name}"' + f' value from study ' + f'"{study_subject.study}"') p = Provenance(modified_table=StudySubject._meta.db_table, modified_table_id=study_subject.id, modification_author=worker, previous_value=prev_value, new_value=curr_value, - modification_description='Worker "{}" changed study subject "{}" field "{}" ' - 'value from study "{}"' - .format(worker, study_subject.nd_number, field.study_subject_field.name, - study_subject.study), + modification_description=mod_desc, modified_field=field.study_subject_field.name, request_path=request.path, request_ip_addr=ip