356 lines
9.7 KiB
Python
356 lines
9.7 KiB
Python
from dataclasses import dataclass
|
|
from difflib import HtmlDiff, SequenceMatcher
|
|
from django import forms
|
|
from django.http import HttpResponse, JsonResponse
|
|
from django.shortcuts import get_object_or_404, render
|
|
from django.views.generic.edit import UpdateView, CreateView
|
|
from django.views.generic.detail import DetailView
|
|
|
|
from atlas.models import Subspecialty
|
|
|
|
from .models import Entry, Formats
|
|
|
|
# Create your views here.
|
|
from .tables import EntryTable
|
|
from .filters import EntryFilter
|
|
from django_filters.views import FilterView
|
|
from django.contrib.auth.decorators import user_passes_test
|
|
|
|
from django_tables2 import SingleTableView, SingleTableMixin
|
|
|
|
|
|
class EntryUpdateView(UpdateView):
|
|
model = Entry
|
|
template_name = "oef/entry_update_view.html"
|
|
fields = ["modality", "exam_code", "exam_name", "questions", "comments", "inactive"]
|
|
|
|
|
|
class EntryDetailView(DetailView):
|
|
model = Entry
|
|
template_name = "oef/entry_detail_view.html"
|
|
|
|
|
|
class FormatsCreateView(CreateView):
|
|
model = Formats
|
|
template_name_suffix = "_update_form"
|
|
fields = ["name", "format", "inherits"]
|
|
|
|
|
|
class FormatsForm(forms.ModelForm):
|
|
class Meta:
|
|
model = Formats
|
|
fields = ["name", "format", "specialties", "inherits"]
|
|
widgets = {"specialties": forms.CheckboxSelectMultiple()}
|
|
|
|
|
|
class FormatsUpdateView(UpdateView):
|
|
model = Formats
|
|
template_name_suffix = "_update_form"
|
|
# fields = ['name', 'format', 'specialties', 'inherits']
|
|
form_class = FormatsForm
|
|
|
|
|
|
class EntryTableView(SingleTableMixin, FilterView):
|
|
model = Entry
|
|
table_class = EntryTable
|
|
|
|
template_name = "oef/entry_table.html"
|
|
|
|
filterset_class = EntryFilter
|
|
|
|
|
|
@dataclass
|
|
class FormatOutput:
|
|
name: str
|
|
action: str = ""
|
|
field_seq: int = 100
|
|
field_label: str = ""
|
|
field_name: str = ""
|
|
field_status: str = ""
|
|
field_type: str = ""
|
|
field_codeset: str = ""
|
|
|
|
|
|
def output(request):
|
|
formats = Formats.objects.all()
|
|
|
|
formats = sorted(formats, key=lambda x: len(x.format))
|
|
|
|
outputs = []
|
|
|
|
codesets = []
|
|
codeset_start = 100000
|
|
|
|
for format in formats:
|
|
seq = 100
|
|
questions = format.format.strip().split("---")
|
|
|
|
for question in questions:
|
|
print(question)
|
|
if not question:
|
|
continue
|
|
|
|
name, *other = question.strip().splitlines()
|
|
|
|
status = "OPTIONAL"
|
|
if name.endswith("*"):
|
|
status = "REQUIRED"
|
|
name = name[:-1]
|
|
|
|
field_type = ""
|
|
match other:
|
|
case ["Yes", "No"]:
|
|
field_type = "YES/NO"
|
|
case ["Date/Time"]:
|
|
field_type = "DATE/TIME"
|
|
case ["Freetext"]:
|
|
field_type = "ALPHANUMERIC"
|
|
case [*codeset]:
|
|
field_type = "CODESET"
|
|
case _:
|
|
field_type = "unknown"
|
|
|
|
o = FormatOutput(
|
|
format.name,
|
|
field_label=name,
|
|
field_name=name,
|
|
field_seq=seq,
|
|
field_status=status,
|
|
field_type=field_type,
|
|
)
|
|
|
|
if field_type == "CODESET":
|
|
o.field_codeset = codeset_start
|
|
|
|
codesets.append((codeset_start, other))
|
|
|
|
codeset_start = codeset_start + 1
|
|
|
|
outputs.append(o)
|
|
|
|
seq = seq + 100
|
|
|
|
return render(
|
|
request,
|
|
"oef/output.html",
|
|
{"formats": formats, "outputs": outputs, "codesets": codesets},
|
|
)
|
|
|
|
|
|
def formats_view(request):
|
|
formats = Formats.objects.all()
|
|
return render(request, "oef/formats_view.html", {"formats": formats})
|
|
|
|
|
|
@user_passes_test(lambda u: u.is_superuser)
|
|
def formats_delete(request, pk):
|
|
f = get_object_or_404(Formats, pk=pk)
|
|
f.delete()
|
|
|
|
return HttpResponse("Format deleted")
|
|
|
|
|
|
def formats_apply(request, pk):
|
|
format = get_object_or_404(Formats, pk=pk)
|
|
|
|
search_text = format.get_format()
|
|
|
|
entries = Entry.objects.filter(questions__icontains=search_text, inactive=False)
|
|
|
|
entry_list = []
|
|
for entry in entries:
|
|
entry_list.append((entry, entry.questions.replace(search_text, "")))
|
|
return render(
|
|
request,
|
|
"oef/formats_apply.html",
|
|
{"format": format, "entry_list": entry_list, "entries": entries},
|
|
)
|
|
|
|
|
|
def entry_detail_formats(request, pk):
|
|
entry = get_object_or_404(Entry, pk=pk)
|
|
formats = Formats.objects.all()
|
|
|
|
questions = entry.questions
|
|
|
|
matching_formats = []
|
|
for format in formats:
|
|
if format.get_format() in questions:
|
|
matching_formats.append(format)
|
|
|
|
matching_formats = sorted(matching_formats, key=lambda x: len(x.get_format()))
|
|
|
|
return render(
|
|
request,
|
|
"oef/entry_detail_formats.html",
|
|
{"entry": entry, "matching_formats": matching_formats},
|
|
)
|
|
|
|
|
|
def replace_questions(request):
|
|
if request.method == "POST":
|
|
search = request.POST.get("search")
|
|
replace = request.POST.get("replace")
|
|
|
|
if not search or not replace:
|
|
return HttpResponse("Please provide both search and replace values")
|
|
|
|
if request.POST.get("exact", False):
|
|
entries = Entry.objects.filter(questions=search, inactive=False)
|
|
formats = Formats.objects.filter(format=search)
|
|
else:
|
|
entries = Entry.objects.filter(questions__contains=search, inactive=False)
|
|
formats = Formats.objects.filter(format__contains=search)
|
|
|
|
for entry in entries:
|
|
entry.questions = entry.questions.replace(search, replace)
|
|
entry.save()
|
|
for format in formats:
|
|
format.format = format.format.replace(search, replace)
|
|
format.save()
|
|
|
|
return HttpResponse(f"{entries.count()} questions replaced")
|
|
else:
|
|
return render(request, "oef/replace_questions.html", {})
|
|
|
|
|
|
def entries(request):
|
|
entries = Entry.objects.all().order_by("exam_code")
|
|
return render(request, "oef/entries.html", {"entries": entries})
|
|
|
|
|
|
def format_search(request):
|
|
if request.method == "POST":
|
|
search = request.POST.get("search")
|
|
|
|
entries = Entry.objects.filter(questions__icontains=search, inactive=False)
|
|
|
|
return render(request, "oef/format_search_results.html", {"entries": entries})
|
|
return render(
|
|
request,
|
|
"oef/format_search.html",
|
|
)
|
|
|
|
|
|
def subspecialties(request):
|
|
subspecialties = Subspecialty.objects.all()
|
|
|
|
format_map = []
|
|
for s in subspecialties:
|
|
format_map.append((s, s.formats_set.all()))
|
|
|
|
format_map.append(
|
|
("Nuclear Medicine", Formats.objects.filter(name__startswith="NM"))
|
|
)
|
|
|
|
return render(
|
|
request, "oef/subspecialties.html", context={"format_map": format_map}
|
|
)
|
|
|
|
|
|
def questions(request):
|
|
questions = set(
|
|
Entry.objects.filter(inactive=False).values_list("questions", flat=True)
|
|
)
|
|
|
|
questions = sorted(questions, key=lambda x: len(x))
|
|
|
|
questions_and_formats = []
|
|
|
|
for question in questions:
|
|
try:
|
|
format = Formats.objects.get(format=question)
|
|
except Formats.DoesNotExist:
|
|
format = None
|
|
questions_and_formats.append((question, format))
|
|
|
|
return render(
|
|
request,
|
|
"oef/questions.html",
|
|
{"questions": questions, "questions_and_formats": questions_and_formats},
|
|
)
|
|
|
|
|
|
def entries_by_question(request):
|
|
|
|
if request.method == "POST":
|
|
question = request.POST.get("question")
|
|
entries = Entry.objects.filter(questions=question, inactive=False)
|
|
|
|
return render(request, "oef/entries_by_question.html", {"entries": entries})
|
|
|
|
return HttpResponse("Please provide a question")
|
|
|
|
|
|
def entries_by_question_codes(request):
|
|
|
|
if request.method == "POST":
|
|
question = request.POST.get("question")
|
|
entries = Entry.objects.filter(questions=question, inactive=False)
|
|
|
|
return render(
|
|
request, "oef/entries_by_question_codes.html", {"entries": entries}
|
|
)
|
|
|
|
return HttpResponse("Please provide a question")
|
|
|
|
|
|
def questions_diff(request):
|
|
if request.method == "POST":
|
|
question1 = request.POST.get("question1", False)
|
|
question2 = request.POST.get("question2", False)
|
|
|
|
if not question1:
|
|
question1 = request.POST.get("search")
|
|
question2 = request.POST.get("replace")
|
|
|
|
html = HtmlDiff().make_table(question1.split("\n"), question2.split("\n"))
|
|
|
|
return HttpResponse(html)
|
|
|
|
return HttpResponse("Please provide two questions")
|
|
|
|
|
|
def questions_sym(request):
|
|
if request.method == "POST":
|
|
question = request.POST.get("question")
|
|
|
|
questions = set(
|
|
Entry.objects.filter(inactive=False).values_list("questions", flat=True)
|
|
)
|
|
|
|
output = []
|
|
for q in questions:
|
|
ratio = SequenceMatcher(None, question, q).ratio()
|
|
|
|
if ratio > 0.5:
|
|
output.append((q, ratio))
|
|
|
|
output = sorted(output, key=lambda x: x[1], reverse=True)
|
|
|
|
return render(request, "oef/questions_sym.html", {"output": output})
|
|
|
|
return HttpResponse("Please provide a question set")
|
|
|
|
|
|
def formats_save(request):
|
|
|
|
if request.method == "POST":
|
|
question = request.POST.get("question")
|
|
format_name = request.POST.get("format_name")
|
|
|
|
if not question:
|
|
return HttpResponse("Please provide a question")
|
|
|
|
if Formats.objects.filter(name=format_name).exists():
|
|
return HttpResponse("Format name already exists")
|
|
|
|
if Formats.objects.filter(format=question).exists():
|
|
return HttpResponse("Format questions already exists")
|
|
|
|
Formats.objects.create(name=format_name, format=question)
|
|
|
|
return HttpResponse("Format saved")
|
|
|
|
return HttpResponse("Please provide a question")
|