This commit is contained in:
Ross
2021-11-24 22:24:58 +00:00
parent aae7a103c1
commit 1d1319429f
4 changed files with 219 additions and 105 deletions
+20 -15
View File
@@ -17,18 +17,21 @@ from atlas.models import (
from anatomy.models import Modality
from generic.models import Examination, Condition, Sign
#from generic.models import Examination, Site, Condition, Sign
# from generic.models import Examination, Site, Condition, Sign
from django.contrib.admin.widgets import FilteredSelectMultiple
from django.forms.widgets import RadioSelect, TextInput, Textarea
from tinymce.widgets import TinyMCE
class ExaminationForm(ModelForm):
class Meta:
model = Examination
fields = ["examination"]
class SeriesForm(ModelForm):
class Media:
# Django also includes a few javascript files necessary
@@ -43,10 +46,10 @@ class SeriesForm(ModelForm):
def __init__(self, *args, **kwargs):
super(SeriesForm, self).__init__(*args, **kwargs)
#self.fields["examination"] = ModelChoiceField(
# self.fields["examination"] = ModelChoiceField(
# queryset=Examination.objects.all(),
# widget=FilteredSelectMultiple(verbose_name="Examination", is_stacked=False),
#)
# )
self.fields["modality"] = ModelChoiceField(
required=True,
@@ -62,7 +65,7 @@ class SeriesForm(ModelForm):
class AtlasForm(ModelForm):
#exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
# exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
class Media:
# Django also includes a few javascript files necessary
@@ -76,7 +79,9 @@ class AtlasForm(ModelForm):
js = ["jsi18n.js", "tesseract.min.js"]
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user') # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
self.user = kwargs.pop(
"user"
) # To get request.user. Do not use kwargs.pop('user', None) due to potential security hole
if kwargs.get("instance"):
# We get the 'initial' keyword argument or initialize it
# as a dict if it didn't exist.
@@ -89,14 +94,13 @@ class AtlasForm(ModelForm):
super(AtlasForm, self).__init__(*args, **kwargs)
class Meta:
model = Case
# fields = ['due_back']
# fields = '__all__'
fields = [
#"examination",
#"site",
# "examination",
# "site",
"title",
"subspecialty",
"description",
@@ -111,10 +115,10 @@ class AtlasForm(ModelForm):
# "normal": RadioSelect(
# choices=[(True, 'Yes'),
# (False, 'No')])
"findings" : TinyMCE(attrs={'cols': 80, 'rows': 20}),
"mark_scheme" : TinyMCE(attrs={'cols': 80, 'rows': 30}),
"description" : Textarea(attrs={'cols': 80, 'rows': 5}),
"history" : Textarea(attrs={'cols': 80, 'rows': 5}),
"findings": TinyMCE(attrs={"cols": 80, "rows": 20}),
"mark_scheme": TinyMCE(attrs={"cols": 80, "rows": 30}),
"description": Textarea(attrs={"cols": 80, "rows": 5}),
"history": Textarea(attrs={"cols": 80, "rows": 5}),
}
def save(self, commit=True):
@@ -126,8 +130,8 @@ class AtlasForm(ModelForm):
def save_m2m():
old_save_m2m()
#instance.exams.clear()
#for exam in self.cleaned_data["exams"]:
# instance.exams.clear()
# for exam in self.cleaned_data["exams"]:
# # We need the id here
# instance.exams.add(exam.pk)
@@ -140,6 +144,7 @@ class AtlasForm(ModelForm):
return instance
SeriesFormSet = inlineformset_factory(
Case,
Series.case.through,
@@ -159,4 +164,4 @@ SeriesImageFormSet = inlineformset_factory(
extra=0,
max_num=2000,
field_classes="testing",
)
)
+6 -6
View File
@@ -2,10 +2,10 @@
{% extends "atlas/base.html" %}
{% block content %}
<a href="{% url 'atlas:series_update' pk=series.pk %}" title="Edit the Series">Edit</a>
{% if request.user.is_superuser %}
<a href="{% url 'admin:atlas_series_change' series.id %}" title="Edit the Series using the admin interface">Admin Edit</a>
{% endif %}
<a href="{% url 'atlas:series_update' pk=series.pk %}" title="Edit the Series">Edit</a>
{% if request.user.is_superuser %}
<a href="{% url 'admin:atlas_series_change' series.id %}" title="Edit the Series using the admin interface">Admin Edit</a>
{% endif %}
{% include 'atlas/series_viewer.html' %}
{% endblock %}
{% include 'atlas/series_viewer.html' %}
{% endblock %}
+9 -1
View File
@@ -197,7 +197,15 @@ SeriesFormSet = inlineformset_factory(
can_delete=True,
extra=0,
max_num=10,
field_classes="testing",
)
LongFormSet = inlineformset_factory(
LongSeries,
Long,
exclude=[],
can_delete=True,
extra=0,
max_num=10,
)
+184 -83
View File
@@ -5,7 +5,11 @@ from django import forms
# from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ViewDoesNotExist
from django.core.exceptions import (
ObjectDoesNotExist,
PermissionDenied,
ViewDoesNotExist,
)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.detail import DetailView
@@ -22,7 +26,9 @@ from django.http import HttpResponseRedirect, HttpResponse
from .forms import (
LongForm,
LongSeriesForm, LongSeriesImageFormSet,
LongFormSet,
LongSeriesForm,
LongSeriesImageFormSet,
MarkLongQuestionDoubleForm,
MarkLongQuestionSingleForm,
SeriesFormSet,
@@ -30,7 +36,9 @@ from .forms import (
ExamForm,
)
from .models import (
AnswerMarks, Long, LongSeries,
AnswerMarks,
Long,
LongSeries,
Examination,
Exam,
CidUserAnswer,
@@ -41,7 +49,15 @@ from .filters import LongFilter, LongSeriesFilter, UserAnswerFilter
from django_tables2 import SingleTableView, SingleTableMixin
from django_filters.views import FilterView
from .decorators import user_is_author_or_long_checker, user_is_author_or_long_checker_or_long_marker, user_is_author_or_long_series_checker_or_long_marker, user_is_long_checker, user_is_author_or_long_series_checker, user_is_long_marker, user_is_author_or_long_checker_or_long_marker
from .decorators import (
user_is_author_or_long_checker,
user_is_author_or_long_checker_or_long_marker,
user_is_author_or_long_series_checker_or_long_marker,
user_is_long_checker,
user_is_author_or_long_series_checker,
user_is_long_marker,
user_is_author_or_long_checker_or_long_marker,
)
from collections import defaultdict
import json
@@ -74,6 +90,7 @@ import os
logger = logging.getLogger(__name__)
def normaliseScore(score):
if score >= 25.5 and score <= 28:
return 4.5
@@ -91,14 +108,17 @@ def normaliseScore(score):
return 7.5
elif score >= 46.5 and score <= 48:
return 7.5
return 4
class AuthorOrCheckerRequiredMixin(object):
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
if self.request.user.groups.filter(name="long_checker").exists() or self.request.user.is_superuser:
if (
self.request.user.groups.filter(name="long_checker").exists()
or self.request.user.is_superuser
):
return obj
if self.request.user not in obj.get_author_objects():
raise PermissionDenied() # or Http404
@@ -126,6 +146,7 @@ def question_detail(request, pk):
# logging.debug(long.subspecialty.first().name.all())
return render(request, "longs/question_detail.html", {"question": long})
@login_required
@user_is_author_or_long_series_checker_or_long_marker
def long_series_detail(request, pk):
@@ -137,6 +158,7 @@ def long_series_detail(request, pk):
# logging.debug(long.subspecialty.first().name.all())
return render(request, "longs/long_series.html", {"series": series})
@login_required
@user_is_author_or_long_checker
def long_split(request, pk):
@@ -236,10 +258,12 @@ class LongDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
model = Long
success_url = reverse_lazy("longs:long_view")
class LongSeriesDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
model = LongSeries
success_url = reverse_lazy("longs:long_series_view")
@login_required
@user_is_author_or_long_checker
def long_clone(request, pk):
@@ -272,6 +296,7 @@ def long_clone(request, pk):
return render(request, "longs/long_form.html", context)
class LongSeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
model = LongSeries
form_class = LongSeriesForm
@@ -282,7 +307,7 @@ class LongSeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
initial = super().get_initial()
long = get_object_or_404(Long, pk=self.kwargs["pk"])
initial['long'] = long.id
initial["long"] = long.id
return initial
@@ -294,8 +319,11 @@ class LongSeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
self.request.POST, self.request.FILES
)
context["image_formset"].full_clean()
context["long_formset"] = LongFormSet(self.request.POST, self.request.FILES)
context["long_formset"].full_clean()
else:
context["image_formset"] = LongSeriesImageFormSet()
context["leng_formset"] = LongFormSet()
return context
def form_valid(self, form):
@@ -307,16 +335,22 @@ class LongSeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
context = self.get_context_data(form=form)
series_formset = context["image_formset"]
if series_formset.is_valid():
long_formset = context["long_formset"]
if series_formset.is_valid() and long_formset.is_valid():
response = super().form_valid(form)
series_formset.instance = self.object
series_formset.save()
long_formset.instance = self.object
long_formset.save()
return response
else:
return super().form_invalid(form)
class LongSeriesUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
class LongSeriesUpdate(
RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView
):
model = LongSeries
form_class = LongSeriesForm
@@ -341,9 +375,9 @@ class LongSeriesUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequire
self.object.save()
# Do this in the form.save()
#new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
#self.object.exams.clear()
#self.object.exams.add(*new_exams)
# new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
# self.object.exams.clear()
# self.object.exams.add(*new_exams)
form.instance.author.add(self.request.user.id)
@@ -358,6 +392,7 @@ class LongSeriesUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequire
else:
return super().form_invalid(form)
class LongCreateBase(RevisionMixin, LoginRequiredMixin, CreateView):
model = Long
form_class = LongForm
@@ -387,9 +422,9 @@ class LongCreateBase(RevisionMixin, LoginRequiredMixin, CreateView):
self.object.save()
# Do this in the form.save()
#new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
#self.object.exams.clear()
#self.object.exams.add(*new_exams)
# new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
# self.object.exams.clear()
# self.object.exams.add(*new_exams)
form.instance.author.add(self.request.user.id)
@@ -433,7 +468,9 @@ class LongCreate(LongCreateBase):
# return super().form_valid(form)
class LongUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
class LongUpdate(
RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView
):
model = Long
form_class = LongForm
@@ -468,9 +505,9 @@ class LongUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin
self.object.save()
# Do this in the form.save()
#new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
#self.object.exams.clear()
#self.object.exams.add(*new_exams)
# new_exams = list(form.cleaned_data['exams'].values_list("pk", flat=True))
# self.object.exams.clear()
# self.object.exams.add(*new_exams)
form.instance.author.add(self.request.user.id)
@@ -565,6 +602,7 @@ class LongView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = LongFilter
class LongSeriesView(LoginRequiredMixin, SingleTableMixin, FilterView):
model = LongSeries
table_class = LongSeriesTable
@@ -591,7 +629,7 @@ def loadJsonAnswer(answer):
exam = get_object_or_404(Exam, pk=eid)
#if not exam.active:
# if not exam.active:
# return False, JsonResponse(
# {"success": False, "error": "No active exam: {}".format(eid)}
# )
@@ -601,18 +639,16 @@ def loadJsonAnswer(answer):
)
posted_answer = answer["ans"]
# Long cases seperate sections by qidn
qidn = answer["qidn"]
# If the user answer does not exist
if not exiting_answers:
ans = CidUserAnswer(cid=answer["cid"])
ans.question_id = answer["qid"]
ans.exam_id = eid
# If the answer already exists or we have started populating it
else:
# Update an existing answer
@@ -638,6 +674,7 @@ def loadJsonAnswer(answer):
return True, None
@user_is_long_marker
@reversion.create_revision()
def mark_answer_override(request, exam_id, question_number, cid):
@@ -668,7 +705,9 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
except ObjectDoesNotExist:
raise Http404("User answer does not exist")
cid_list = list(question.cid_user_answers.filter(exam__id=exam_id).values_list("cid", flat=True))
cid_list = list(
question.cid_user_answers.filter(exam__id=exam_id).values_list("cid", flat=True)
)
previous_cid = False
next_cid = False
@@ -679,12 +718,14 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
elif cid_list[-1] == cid:
previous_cid = cid_list[-2]
else:
next_cid = cid_list[cid_list.index(cid)+1]
previous_cid = cid_list[cid_list.index(cid)-1]
next_cid = cid_list[cid_list.index(cid) + 1]
previous_cid = cid_list[cid_list.index(cid) - 1]
try:
if exam.double_mark:
unmarked = question.get_unmarked_user_answers(exam_pk=exam.id, marker=request.user)
unmarked = question.get_unmarked_user_answers(
exam_pk=exam.id, marker=request.user
)
else:
unmarked = question.get_unmarked_user_answers(exam_pk=exam.id)
next_unmarked_id = unmarked[0].cid
@@ -695,14 +736,16 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
# We use different forms if the exam should be single or double marked
if not exam.double_mark or (request.method == "POST" and request.POST['form_id'] == 'discrepancy_form'):
if not exam.double_mark or (
request.method == "POST" and request.POST["form_id"] == "discrepancy_form"
):
if request.method == "POST":
form = MarkLongQuestionSingleForm(request.POST)
if form.is_valid():
# If skip button is pressed skip the question without marking
# Skip is problematic if we skip to the next unmarked answer
#if "skip" in request.POST:
# if "skip" in request.POST:
# return redirect("longs:mark_answer", pk=exam_id, sk=question_number, cid=next_unmarked_id)
# Extract score from form and save it to the object
@@ -710,14 +753,24 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
answer.save()
if "next" in request.POST:
return redirect("longs:mark_answer", exam_id=exam_id, question_number=question_number, cid=next_unmarked_id)
return redirect(
"longs:mark_answer",
exam_id=exam_id,
question_number=question_number,
cid=next_unmarked_id,
)
if "save" in request.POST:
return redirect("longs:mark_answer", exam_id=exam_id, question_number=question_number, cid=cid)
#elif "previous" in request.POST:
return redirect(
"longs:mark_answer",
exam_id=exam_id,
question_number=question_number,
cid=cid,
)
# elif "previous" in request.POST:
# return redirect("longs:mark_question_overview", pk=exam_id, sk=n - 1)
else:
form = MarkLongQuestionSingleForm(initial={'score': answer.score})
form = MarkLongQuestionSingleForm(initial={"score": answer.score})
else:
if request.method == "POST":
@@ -726,11 +779,12 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
if form.is_valid():
# If skip button is pressed skip the question without marking
# Skip is problematic if we skip to the next unmarked answer
#if "skip" in request.POST:
# if "skip" in request.POST:
# return redirect("longs:mark_answer", pk=exam_id, sk=question_number, cid=next_unmarked_id)
mark_object = AnswerMarks.objects.get_or_create(user_answer=answer, marker=request.user)[0]
mark_object = AnswerMarks.objects.get_or_create(
user_answer=answer, marker=request.user
)[0]
# Extract score from form and save it to the object
mark_object.score = form.cleaned_data["score"]
mark_object.mark_reason = form.cleaned_data["mark_reason"]
@@ -748,19 +802,35 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
answer.score = ""
answer.save()
if "next" in request.POST:
return redirect("longs:mark_answer", exam_id=exam_id, question_number=question_number, cid=next_unmarked_id)
return redirect(
"longs:mark_answer",
exam_id=exam_id,
question_number=question_number,
cid=next_unmarked_id,
)
if "save" in request.POST:
return redirect("longs:mark_answer", exam_id=exam_id, question_number=question_number, cid=cid)
#elif "previous" in request.POST:
return redirect(
"longs:mark_answer",
exam_id=exam_id,
question_number=question_number,
cid=cid,
)
# elif "previous" in request.POST:
# return redirect("longs:mark_question_overview", pk=exam_id, sk=n - 1)
else:
try:
mark_object = AnswerMarks.objects.get(user_answer=answer, marker=request.user)
form = MarkLongQuestionDoubleForm(initial={'score': mark_object.score,'mark_reason': mark_object.mark_reason,'candidate_feedback': mark_object.candidate_feedback, })
mark_object = AnswerMarks.objects.get(
user_answer=answer, marker=request.user
)
form = MarkLongQuestionDoubleForm(
initial={
"score": mark_object.score,
"mark_reason": mark_object.mark_reason,
"candidate_feedback": mark_object.candidate_feedback,
}
)
except AnswerMarks.DoesNotExist:
form = MarkLongQuestionDoubleForm()
@@ -769,7 +839,9 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
# if they do automatically update teh scoer
marks = set(answer.mark.values_list("score", flat=True))
if len(marks) > 1 or override:
discrepancy_form = MarkLongQuestionSingleForm(initial={'score': answer.score })
discrepancy_form = MarkLongQuestionSingleForm(
initial={"score": answer.score}
)
return render(
request,
@@ -789,6 +861,7 @@ def mark_answer(request, exam_id, question_number, cid, override=False):
},
)
# @user_passes_test(user_is_admin, login_url="/accounts/login")
@login_required
@user_is_long_marker
@@ -809,13 +882,16 @@ def mark_question_overview(request, exam_id, sk):
except IndexError:
raise Http404("Exam question does not exist")
user_answers = question.cid_user_answers.filter(exam__id=exam_id)
unmarked_count = user_answers.filter(score=CidUserAnswer.ScoreOptions.UNMARKED).count()
unmarked_count = user_answers.filter(
score=CidUserAnswer.ScoreOptions.UNMARKED
).count()
if exam.double_mark:
marker_unmarked_count = question.get_unmarked_user_answer_count(exam.pk, marker=request.user)
marker_unmarked_count = question.get_unmarked_user_answer_count(
exam.pk, marker=request.user
)
return render(
request,
"longs/mark_question_double_overview.html",
@@ -875,7 +951,7 @@ def exam_scores_cid(request, pk):
if not s:
# skip if no answer, (score 4)
user_answers_marks[cid].append(4)
#user_answers[cid].append("")
# user_answers[cid].append("")
by_question[q].append(("", 4))
continue
else:
@@ -884,22 +960,19 @@ def exam_scores_cid(request, pk):
if answer_score == "":
index = exam.get_question_index(q)
unmarked.add(index)
#user_answers[cid].append(ans)
# user_answers[cid].append(ans)
user_answers_marks[cid].append(answer_score)
#user_answers_and_marks[cid].append((ans, answer_score))
# user_answers_and_marks[cid].append((ans, answer_score))
by_question[q].append((ans, answer_score))
user_scores = {}
user_scores_normalised = {}
for user in user_answers_marks:
user_scores[user] = sum(
[i for i in user_answers_marks[user] if i != ""]
user_scores[user] = sum([i for i in user_answers_marks[user] if i != ""])
user_scores_normalised[user] = normaliseScore(
sum([i for i in user_answers_marks[user] if i != ""])
)
user_scores_normalised[user] = normaliseScore(sum(
[i for i in user_answers_marks[user] if i != ""]
))
user_scores_list = list(user_scores.values())
@@ -938,13 +1011,13 @@ def exam_scores_cid(request, pk):
"unmarked": unmarked,
"questions": questions,
"by_question": by_question,
#"user_answers": dict(user_answers),
# "user_answers": dict(user_answers),
"user_answers_marks": dict(user_answers_marks),
"user_scores": user_scores,
"user_scores_normalised": user_scores_normalised,
"user_scores_list": user_scores_list,
"user_names": user_names,
#"user_answers_and_marks": user_answers_and_marks,
# "user_answers_and_marks": user_answers_and_marks,
"max_score": max_score,
"mean": mean,
"median": median,
@@ -962,12 +1035,11 @@ def exam_scores_cid_user(request, pk, sk):
questions = exam.exam_questions.all()
#answers_and_marks = []
# answers_and_marks = []
answers_marks = []
#answers = []
# answers = []
answer_text = []
view_all_results = False
if request.user.groups.filter(name="view_all_results").exists():
view_all_results = True
@@ -976,26 +1048,39 @@ def exam_scores_cid_user(request, pk, sk):
# Get user answer
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not user_answer or user_answer is None:
# skip if no answer
#answers_marks.append("")
#answers.append("")
# answers_marks.append("")
# answers.append("")
answer_score = 4
#ans = "Not answered"
answer_text.append((("Not answered"),("Not answered"),("Not answered"),("Not answered"),("Not answered")))
# ans = "Not answered"
answer_text.append(
(
("Not answered"),
("Not answered"),
("Not answered"),
("Not answered"),
("Not answered"),
)
)
else:
answer_score = user_answer.get_answer_score()
answer_text.append((user_answer.answer_observations, user_answer.answer_interpretation, user_answer.answer_principle_diagnosis, user_answer.answer_differential_diagnosis, user_answer.answer_management))
answer_text.append(
(
user_answer.answer_observations,
user_answer.answer_interpretation,
user_answer.answer_principle_diagnosis,
user_answer.answer_differential_diagnosis,
user_answer.answer_management,
)
)
if not exam.publish_results and not view_all_results:
answer_score = 0
#answers.append(ans)
# answers.append(ans)
answers_marks.append(answer_score)
#answers_and_marks.append((ans, answer_score, correct_answer))
# answers_and_marks.append((ans, answer_score, correct_answer))
answered = [i for i in answers_marks if i != ""]
if "" in answers_marks:
@@ -1015,16 +1100,17 @@ def exam_scores_cid_user(request, pk, sk):
"exam": exam,
"cid": cid,
"questions": questions,
#"answers": answers,
# "answers": answers,
"answers_marks": answers_marks,
"total_score": total_score,
"normalised_score": normalised_score,
"max_score": max_score,
"answer_text": answer_text
#"answers_and_marks": answers_and_marks,
# "answers_and_marks": answers_and_marks,
},
)
@login_required
@user_is_author_or_long_series_checker
def long_series_order_dicom(request, pk):
@@ -1032,10 +1118,11 @@ def long_series_order_dicom(request, pk):
try:
series.order_by_dicom()
except:
return HttpResponse('<h1>Series does not appear to contain dicoms</h1>')
return HttpResponse("<h1>Series does not appear to contain dicoms</h1>")
return redirect("longs:long_series_detail", pk=pk)
@login_required
@user_is_author_or_long_series_checker
def long_series_order_dicom_instance(request, pk):
@@ -1043,10 +1130,13 @@ def long_series_order_dicom_instance(request, pk):
try:
series.order_by_dicom("InstanceNumber")
except:
return HttpResponse('<h1>Series does not appear to contain dicoms (or field InstanceNumber)</h1>')
return HttpResponse(
"<h1>Series does not appear to contain dicoms (or field InstanceNumber)</h1>"
)
return redirect("longs:long_series_detail", pk=pk)
@login_required
@user_is_author_or_long_series_checker
def long_series_order_dicom_SeriesInstanceUID(request, pk):
@@ -1054,10 +1144,13 @@ def long_series_order_dicom_SeriesInstanceUID(request, pk):
try:
series.order_by_dicom("SeriesInstanceUID")
except:
return HttpResponse('<h1>Series does not appear to contain dicoms (or field SeriesInstanceUID)</h1>')
return HttpResponse(
"<h1>Series does not appear to contain dicoms (or field SeriesInstanceUID)</h1>"
)
return redirect("longs:long_series_detail", pk=pk)
@login_required
@user_is_author_or_long_series_checker
def long_series_order_upload_filename(request, pk):
@@ -1066,6 +1159,7 @@ def long_series_order_upload_filename(request, pk):
return redirect("longs:long_series_detail", pk=pk)
LongExamViews = ExamViews(Exam, Long, "longs", "long", loadJsonAnswer)
@@ -1080,6 +1174,7 @@ class ExamCreate(RevisionMixin, LoginRequiredMixin, CreateView):
form.instance.author.add(self.request.user.id)
return super().form_valid(form)
class ExamClone(ExamCloneMixin, ExamCreate):
"""Clone exam view"""
@@ -1105,9 +1200,10 @@ class ExamDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView):
class ExamViewSet(RevisionMixin, viewsets.ModelViewSet):
queryset = Exam.objects.all().order_by('name')
queryset = Exam.objects.all().order_by("name")
serializer_class = ExamSerializer
def question_json_unbased(request, pk):
"""
No (file based) caching is enabled for unbased quesitons
@@ -1117,15 +1213,16 @@ def question_json_unbased(request, pk):
question_json = question.get_question_json(based=False)
return JsonResponse(question_json)
def question_json(request, pk):
question = get_object_or_404(Long, pk=pk)
#exam = get_object_or_404(self.Exam, pk=pk)
# exam = get_object_or_404(self.Exam, pk=pk)
#if not exam.active:
# if not exam.active:
# raise Http404("No available exam")
path= "{0}longs/questions/{1}.json".format(settings.MEDIA_ROOT, pk)
url= "{0}longs/questions/{1}.json".format(settings.MEDIA_URL, pk)
path = "{0}longs/questions/{1}.json".format(settings.MEDIA_ROOT, pk)
url = "{0}longs/questions/{1}.json".format(settings.MEDIA_URL, pk)
if os.path.isfile(path) and not question.recreate_json:
return redirect(url)
@@ -1137,6 +1234,7 @@ def question_json(request, pk):
return redirect(question_json)
@login_required
@user_is_author_or_long_checker
def question_json_recreate(request, pk):
@@ -1151,7 +1249,7 @@ def question_json_recreate(request, pk):
exam.recreate_json = True
exam.save()
#question.get_question_json()
# question.get_question_json()
return redirect("longs:question_detail", pk=pk)
@@ -1173,6 +1271,7 @@ class UserAnswerDelete(SuperuserRequiredMixin, DeleteView):
template_name = "user_answer_delete.html"
success_url = reverse_lazy("longs:user_answer_table_view")
@user_passes_test(lambda u: u.is_superuser)
def user_answer_delete_multiple(request):
if request.is_ajax():
@@ -1195,14 +1294,16 @@ def refresh_exam_question_json(request, pk):
return redirect("longs:exam_overview", pk=pk)
class SeriesImagesZipView(SuperuserRequiredMixin, BaseZipView):
"""Download all images from an image series"""
def get_files(self):
series = LongSeries.objects.get(pk=self.kwargs['pk'])
series = LongSeries.objects.get(pk=self.kwargs["pk"])
return [i.image.file for i in series.images.all()]
def question_review(request, pk):
"""
Return a json representation of the question when the exam is active