diff --git a/atlas/forms.py b/atlas/forms.py
index 4bdb6e27..2ad8edaa 100755
--- a/atlas/forms.py
+++ b/atlas/forms.py
@@ -28,6 +28,7 @@ from atlas.models import (
Condition,
Structure,
Subspecialty,
+ UserReportAnswer,
)
from anatomy.models import Modality
@@ -440,10 +441,8 @@ SeriesImageFormSet = inlineformset_factory(
max_num=2000,
)
-
-class CidReportAnswerForm(ModelForm):
+class BaseReportAnswerForm(ModelForm):
class Meta:
- model = CidReportAnswer
fields = ["answer"]
widgets = {
@@ -460,9 +459,16 @@ class CidReportAnswerForm(ModelForm):
# }
def __init__(self, *args, **kwargs):
- super(CidReportAnswerForm, self).__init__(*args, **kwargs)
+ super(BaseReportAnswerForm, self).__init__(*args, **kwargs)
self.fields["answer"].required = False
+class CidReportAnswerForm(BaseReportAnswerForm):
+ class Meta(BaseReportAnswerForm.Meta):
+ model = CidReportAnswer
+
+class UserReportAnswerForm(BaseReportAnswerForm):
+ class Meta(BaseReportAnswerForm.Meta):
+ model = UserReportAnswer
class CidReportAnswerMarkForm(ModelForm):
class Meta:
diff --git a/atlas/models.py b/atlas/models.py
index 191b72f4..1b2e835a 100644
--- a/atlas/models.py
+++ b/atlas/models.py
@@ -542,6 +542,16 @@ class BaseReportAnswer(models.Model):
def get_answer_score(self):
return self.score
+ def set_cid_or_user(self, cid=None, user=None):
+ if cid is not None:
+ self.cid = cid
+ elif user is not None:
+ self.user = user
+ else:
+ raise ValueError("No cid or user specified")
+
+
+
class Meta:
abstract = True
diff --git a/atlas/templates/atlas/collection_take.html b/atlas/templates/atlas/collection_take.html
index c1dba53d..bd604c6a 100644
--- a/atlas/templates/atlas/collection_take.html
+++ b/atlas/templates/atlas/collection_take.html
@@ -4,6 +4,9 @@
{{collection.name}}
Start: {{exam.name}}
+ {% if request.user.is_authenticated and valid_user %}
+ Start
+ {% else %}
Enter your CID and passcode in the below boxes.
@@ -45,5 +48,6 @@
});
});
+ {% endif %}
{% endblock %}
diff --git a/atlas/templates/atlas/collection_take_overview.html b/atlas/templates/atlas/collection_take_overview.html
index 4ed3baa6..e4815f97 100644
--- a/atlas/templates/atlas/collection_take_overview.html
+++ b/atlas/templates/atlas/collection_take_overview.html
@@ -1,7 +1,9 @@
{% extends 'base.html' %}
{% block content %}
- CID: {{cid}}
+ {% if cid is not None %}
+ CID: {{cid}}
+ {% endif %}
Collection: {{collection.name}}
@@ -9,9 +11,21 @@
{{answer_count}} out of {{collection_length}} cases answered. Click to go to case.
diff --git a/atlas/urls.py b/atlas/urls.py
index ddb46977..d7f7d01a 100755
--- a/atlas/urls.py
+++ b/atlas/urls.py
@@ -71,10 +71,15 @@ urlpatterns = [
name="collection_scores_cid",
),
path(
- "collection//take//",
+ "collection//take_overview//",
views.collection_take_overview,
name="collection_take_overview",
),
+ path(
+ "collection//take_overview",
+ views.collection_take_overview_user,
+ name="collection_take_overview_user",
+ ),
path(
"collection//",
views.collection_case_view,
@@ -85,6 +90,11 @@ urlpatterns = [
views.collection_case_view_take,
name="collection_case_view_take",
),
+ path(
+ "collection///take/",
+ views.collection_case_view_take_user,
+ name="collection_case_view_take_user",
+ ),
path(
"collection///review",
views.collection_case_view_review,
diff --git a/atlas/views.py b/atlas/views.py
index 4ed6a035..9cc98442 100755
--- a/atlas/views.py
+++ b/atlas/views.py
@@ -44,6 +44,7 @@ from .forms import (
SeriesFindingForm,
CaseDifferentialFormSet,
StructureForm,
+ UserReportAnswerForm,
)
from .models import (
Case,
@@ -60,6 +61,7 @@ from .models import (
Subspecialty,
SeriesFinding,
SeriesImage,
+ UserReportAnswer,
)
from .tables import (
CaseCollectionTable,
@@ -371,7 +373,6 @@ class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView):
return context
def form_valid(self, form):
-
self.object = form.save(commit=False)
self.object.save()
@@ -421,7 +422,6 @@ class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
return context
def form_valid(self, form):
-
self.object = form.save(commit=False)
self.object.save()
@@ -528,7 +528,6 @@ class SeriesUpdate(
return kwargs
def form_valid(self, form):
-
self.object = form.save(commit=False)
self.object.save()
@@ -613,7 +612,6 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin):
return context
def form_valid(self, form):
-
self.object = form.save(commit=False)
# Add exam objects
@@ -653,12 +651,12 @@ class AtlasCreate(AtlasCreateBase, CreateView):
return initial
## There has to be a better way...
- #try:
+ # try:
# s = (i.pk for i in self.request.user.atlas_default.site.all())
# self.initial.update({"site": s})
- #except AttributeError:
+ # except AttributeError:
# pass
- #return self.initial
+ # return self.initial
class AtlasUpdate(
@@ -701,7 +699,6 @@ class AtlasUpdate(
return context
def form_valid(self, form):
-
self.object = form.save(commit=False)
self.object.save()
@@ -722,24 +719,30 @@ class AtlasUpdate(
else:
return super().form_invalid(form)
+
def add_collection_to_case_form(request, case_id):
- if request.method == 'POST':
+ if request.method == "POST":
form = AddCollectionToCaseForm(request.POST, user=request.user)
if form.is_valid():
case = get_object_or_404(Case, pk=case_id)
case.casecollection_set.add(*form.cleaned_data["casecollection"])
- #do_something_with_form_data(form.cleaned_data)
+ # do_something_with_form_data(form.cleaned_data)
return HttpResponse("Done")
- return render(request, 'web/htmx_contact_form_confirm.html')
+ return render(request, "web/htmx_contact_form_confirm.html")
else:
form = AddCollectionToCaseForm(user=request.user)
- return render(request, 'generic_form.html', {
- 'form': form,
- 'target_url': reverse("atlas:case_collection_form", args=(case_id,))
- })
+ return render(
+ request,
+ "generic_form.html",
+ {
+ "form": form,
+ "target_url": reverse("atlas:case_collection_form", args=(case_id,)),
+ },
+ )
-#class AddCollectionToCaseView(FormView):
+
+# class AddCollectionToCaseView(FormView):
# form_class = AddCollectionToCaseForm
# template_name = "generic_form.html"
#
@@ -756,6 +759,7 @@ def add_collection_to_case_form(request, case_id):
# pk = self.kwargs["pk"]
# return reverse("atlas:case_detail", kwargs={"pk": pk})
+
class AtlasClone(AtlasCreateBase, CreateView):
"""Clones a existing atlas"""
@@ -1085,18 +1089,26 @@ def collection_detail(request, pk):
cases = collection.cases.all().order_by("casedetail__sort_order")
- return render(request, "atlas/collection_detail.html", {"collection": collection, "cases": cases})
+ return render(
+ request,
+ "atlas/collection_detail.html",
+ {"collection": collection, "cases": cases},
+ )
def collection_take(request, pk):
collection = get_object_or_404(CaseCollection, pk=pk)
+ template_variables = {
+ "collection": collection,
+ "valid_user": collection.check_logged_in_user(request),
+ }
+
match collection.collection_type:
case "REP":
- return render(request, "atlas/collection_take.html", {"collection": collection})
+ return render(request, "atlas/collection_take.html", template_variables)
case "REV":
- return render(request, "atlas/collection_review.html", {"collection": collection})
-
+ return render(request, "atlas/collection_review.html", template_variables)
@user_is_collection_author_or_atlas_editor
@@ -1234,7 +1246,13 @@ def exam_cids(request, pk):
raise PermissionDenied
-def collection_take_overview(request, pk, cid, passcode):
+def collection_take_overview_user(request, pk):
+ return collection_take_overview(request, pk)
+
+
+def collection_take_overview(
+ request, pk: int, cid: int | None = None, passcode: str | None = None
+):
collection = get_object_or_404(CaseCollection, pk=pk)
if not collection.active:
@@ -1246,7 +1264,11 @@ def collection_take_overview(request, pk, cid, passcode):
cases = collection.cases.all().order_by("casedetail__sort_order").prefetch_related()
case_details = CaseDetail.objects.filter(case__in=cases, collection=collection)
- answers = CidReportAnswer.objects.filter(cid=cid, question__in=case_details)
+
+ if cid is not None:
+ answers = CidReportAnswer.objects.filter(cid=cid, question__in=case_details)
+ else:
+ answers = UserReportAnswer.objects.filter(user=request.user, question__in=case_details)
answer_question_map = {}
for ans in answers:
@@ -1261,8 +1283,7 @@ def collection_take_overview(request, pk, cid, passcode):
else:
question_answer_tuples.append((q, None))
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = collection.get_or_create_cid_user_exam(cid_user=c)
+ cid_user_exam = collection.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
return render(
request,
@@ -1278,14 +1299,22 @@ def collection_take_overview(request, pk, cid, passcode):
},
)
+
def collection_case_view_review(request, pk: int, case_number: int):
return collection_case_view_take(request, pk, case_number, None, None)
-def collection_case_view_take(request, pk: int, case_number: int, cid=None, passcode=None):
+
+def collection_case_view_take_user(request, pk: int, case_number: int):
+ return collection_case_view_take(request, pk, case_number)
+
+
+def collection_case_view_take(
+ request, pk: int, case_number: int, cid=None, passcode=None
+):
collection = get_object_or_404(CaseCollection, pk=pk)
form = None
- answer = None
+ answer: CidReportAnswer | UserReportAnswer
if collection.collection_type != collection.COLLECTION_TYPE_CHOICES.REVIEW:
if not collection.active:
@@ -1294,32 +1323,36 @@ def collection_case_view_take(request, pk: int, case_number: int, cid=None, pass
if cid is not None and not collection.check_cid_user(cid, passcode, request):
raise Http404("Error accessing exam")
-
- if cid is not None:
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = collection.get_or_create_cid_user_exam(cid_user=c)
- else:
- cid_user_exam = collection.get_or_create_cid_user_exam(user_user=request.user)
+ cid_user_exam = collection.get_or_create_cid_user_exam(
+ cid=cid, user_user=request.user
+ )
cases = collection.cases.all().order_by("casedetail__sort_order").prefetch_related()
case = cases[case_number]
if collection.collection_type == "REP":
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = collection.get_or_create_cid_user_exam(cid_user=c)
+ cid_user_exam = collection.get_or_create_cid_user_exam(
+ cid=cid, user_user=request.user
+ )
case_detail = CaseDetail.objects.get(case=case, collection=collection)
- answer = case_detail.cidreportanswer_set.filter(cid=cid).first()
+
+ if cid is not None:
+ answer = case_detail.cidreportanswer_set.filter(cid=cid).first()
+ ReportAnswerForm = CidReportAnswerForm
+ else:
+ answer = case_detail.userreportanswer_set.filter(user=request.user).first()
+ ReportAnswerForm = UserReportAnswerForm
if request.method == "POST":
if collection.collection_type == "REP":
if not collection.publish_results:
if answer:
- form = CidReportAnswerForm(request.POST, instance=answer)
+ form = ReportAnswerForm(request.POST, instance=answer)
else:
- form = CidReportAnswerForm(request.POST)
+ form = ReportAnswerForm(request.POST)
if form.is_valid():
answer = form.save(commit=False)
- answer.cid = cid
+ answer.set_cid_or_user(cid=cid, user=request.user)
answer.question = case_detail
# answer.published_date = timezone.now()
answer.save()
@@ -1327,24 +1360,25 @@ def collection_case_view_take(request, pk: int, case_number: int, cid=None, pass
cid_user_exam.end_time = timezone.now()
cid_user_exam.save()
- kwargs = {"pk": pk, "cid": cid, "passcode": passcode}
- redirect_url = "atlas:collection_case_view_take"
+ if cid is not None:
+ kwargs = {"pk": pk, "cid": cid, "passcode": passcode}
+ redirect_url = "atlas:collection_case_view_take"
+ overview_url = "atlas:collection_take_overview"
+ else:
+ kwargs = {"pk": pk}
+ redirect_url = "atlas:collection_case_view_take_user"
+ overview_url = "atlas:collection_take_overview_user"
else:
kwargs = {"pk": pk}
redirect_url = "atlas:collection_case_view_review"
if "next" in request.POST:
- return redirect(
- redirect_url, case_number=case_number + 1, **kwargs
- )
+ return redirect(redirect_url, case_number=case_number + 1, **kwargs)
elif "previous" in request.POST:
- return redirect(
- redirect_url, case_number=case_number - 1, **kwargs
- )
+ return redirect(redirect_url, case_number=case_number - 1, **kwargs)
elif "finish" in request.POST:
- redirect_url = "atlas:collection_take"
- return redirect(redirect_url, **kwargs)
+ return redirect(overview_url, **kwargs)
elif "goto" in request.POST:
return redirect(
redirect_url,
@@ -1352,7 +1386,8 @@ def collection_case_view_take(request, pk: int, case_number: int, cid=None, pass
**kwargs,
)
else:
- form = CidReportAnswerForm(instance=answer)
+ if collection.collection_type == "REP":
+ form = ReportAnswerForm(instance=answer)
series_list = case.series.all().prefetch_related("images", "examination", "plane")
@@ -1431,6 +1466,7 @@ def collection_case_view(request, pk, case_number):
},
)
+
@user_is_collection_author_or_atlas_editor
def delete_collection_cid_answers(request, exam_id, cid):
collection = get_object_or_404(CaseCollection, pk=exam_id)
@@ -1441,17 +1477,18 @@ def delete_collection_cid_answers(request, exam_id, cid):
case__in=cases, collection=collection
).prefetch_related("case")
- cid_user_answers = CidReportAnswer.objects.filter(question__in=case_details, cid=cid)
-
+ cid_user_answers = CidReportAnswer.objects.filter(
+ question__in=case_details, cid=cid
+ )
temp = {}
for ans in cid_user_answers:
temp[ans.pk] = (ans.question.pk, ans.score, ans.cid, ans.answer)
ans.delete()
-
return JsonResponse(temp)
+
@user_is_collection_author_or_atlas_editor
def delete_collection_answers(request, exam_id):
collection = get_object_or_404(CaseCollection, pk=exam_id)
@@ -1464,15 +1501,14 @@ def delete_collection_answers(request, exam_id):
cid_user_answers = CidReportAnswer.objects.filter(question__in=case_details)
-
temp = {}
for ans in cid_user_answers:
temp[ans.pk] = (ans.question.pk, ans.score, ans.cid, ans.answer)
ans.delete()
-
return JsonResponse(temp)
+
# TODO: this needs a major cleanup
@user_is_collection_author_or_atlas_editor
def collection_scores_cid(request, pk):
@@ -1541,7 +1577,6 @@ def collection_scores_cid(request, pk):
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 != "unmarked" and i != None)]
)
@@ -1587,7 +1622,7 @@ def collection_scores_cid(request, pk):
collection.stats_min = min(user_scores_list)
collection.stats_max = max(user_scores_list)
- #collection.stats_graph = fig_html
+ # collection.stats_graph = fig_html
collection.user_scores = user_scores
@@ -1619,6 +1654,7 @@ def collection_scores_cid(request, pk):
},
)
+
GenericExamViews = ExamViews(
CaseCollection, Case, None, CidReportAnswer, "atlas", "casecollection"
-)
\ No newline at end of file
+)
diff --git a/generic/models.py b/generic/models.py
index 2f5e6793..8f186166 100644
--- a/generic/models.py
+++ b/generic/models.py
@@ -470,12 +470,14 @@ class ExamCollectionGenericBase(models.Model):
if c:
return c
- if user_user is not None:
+ elif user_user is not None:
c = CidUserExam.objects.filter(
content_type=content_type, object_id=self.pk, user_user=user_user
).first()
if c:
return c
+ else:
+ raise ValueError("Invalid cid / cid_user / user_user")
if start_time is None:
start_time = timezone.now()
@@ -488,13 +490,15 @@ class ExamCollectionGenericBase(models.Model):
start_time=start_time,
)
- if user_user is not None:
+ elif user_user is not None:
new = CidUserExam(
content_type=content_type,
object_id=self.pk,
user_user=user_user,
start_time=start_time,
)
+ else:
+ raise ValueError("Invalid cid / cid_user / user_user")
new.save()
return new
diff --git a/physics/views.py b/physics/views.py
index a2bef598..18a18d22 100644
--- a/physics/views.py
+++ b/physics/views.py
@@ -235,11 +235,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
else:
question_answer_tuples.append((q, None))
- if cid is not None:
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
- else:
- cid_user_exam = exam.get_or_create_cid_user_exam(user_user=request.user)
+ cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
return render(
request,
@@ -256,7 +252,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
)
-def exam_take(request, pk: int, sk: int, cid: str = None, passcode: str = None):
+def exam_take(request, pk: int, sk: int, cid: str| None = None, passcode: str| None = None):
exam = get_object_or_404(Exam, pk=pk)
if not exam.active:
@@ -265,11 +261,9 @@ def exam_take(request, pk: int, sk: int, cid: str = None, passcode: str = None):
if not exam.check_cid_user(cid, passcode, request):
raise Http404("Error accessing exam")
- if cid is not None:
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
- else:
- cid_user_exam = exam.get_or_create_cid_user_exam(user_user=request.user)
+ print(cid, passcode, request.user)
+
+ cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
question = exam.exam_questions.all()[sk]
diff --git a/sbas/views.py b/sbas/views.py
index cd914eab..d121ee79 100644
--- a/sbas/views.py
+++ b/sbas/views.py
@@ -202,11 +202,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
else:
question_answer_tuples.append((q, None))
- if cid is not None:
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
- else:
- cid_user_exam = exam.get_or_create_cid_user_exam(user_user=request.user)
+ cid_user_exam = exam.get_or_create_cid_user_exam(cid=cid, user_user=request.user)
return render(
request,
@@ -223,7 +219,7 @@ def exam_take_overview(request, pk, cid=None, passcode=None):
)
-def exam_take(request, pk: int, sk: int, cid: str = None, passcode: str = None):
+def exam_take(request, pk: int, sk: int, cid: int = None, passcode: str = None):
exam = get_object_or_404(Exam, pk=pk)
if not exam.active:
@@ -232,11 +228,7 @@ def exam_take(request, pk: int, sk: int, cid: str = None, passcode: str = None):
if not exam.check_cid_user(cid, passcode, request):
raise Http404("Error accessing exam")
- if cid is not None:
- c = CidUser.objects.filter(cid=cid).first()
- cid_user_exam = exam.get_or_create_cid_user_exam(cid_user=c)
- else:
- cid_user_exam = exam.get_or_create_cid_user_exam(user_user=request.user)
+ cid_user_exam = exam.get_or_create_cid_user_exam(cid = cid, user_user=request.user)
question = exam.exam_questions.all()[sk]