diff --git a/anatomy/static/css/anatomy.css b/anatomy/static/css/anatomy.css index b62659d1..f47d2658 100644 --- a/anatomy/static/css/anatomy.css +++ b/anatomy/static/css/anatomy.css @@ -485,4 +485,20 @@ td.user-answer-score-2::after { .notes .complete { color: darkslategray; + } + + table.longs .user-answer-score-4, table.longs .user-answer-score-4\.5 { + color: red + } + + table.longs .user-answer-score-5\.0, table.longs .user-answer-score-5\.5 { + color: yellow + } + + table.longs .user-answer-score-6\.0, table.longs .user-answer-score-6\.5 { + color: yellowgreen + } + + table.longs .user-answer-score-7\.0, table.longs .user-answer-score-7\.5 { + color: green } \ No newline at end of file diff --git a/anatomy/templates/anatomy/exam_overview.html b/anatomy/templates/anatomy/exam_overview.html index 4899985c..b1ca3117 100644 --- a/anatomy/templates/anatomy/exam_overview.html +++ b/anatomy/templates/anatomy/exam_overview.html @@ -17,7 +17,7 @@ Exam active: [When checked the exam will be available to take in the test system]
- Publish results: [When checked the exam results will be available on this site] + Publish results: [When checked the exam results will be available to users on this site]
{% endif %}

diff --git a/anatomy/templates/anatomy/exam_scores.html b/anatomy/templates/anatomy/exam_scores.html index 8dd68c4a..97b7dec8 100644 --- a/anatomy/templates/anatomy/exam_scores.html +++ b/anatomy/templates/anatomy/exam_scores.html @@ -22,7 +22,7 @@
{{plot|safe}}
- +
@@ -36,8 +36,9 @@
Candidate ID Score
-

Answers as a table

- +

Results as a table

+
+ {% for cid in cids %} @@ -45,6 +46,7 @@ {% endfor %} + {% for question in questions %} diff --git a/longs/filters.py b/longs/filters.py index 98cdb4d3..fe664067 100755 --- a/longs/filters.py +++ b/longs/filters.py @@ -1,6 +1,6 @@ import django_filters -from .models import Long, LongSeries, Exam +from .models import Long, LongSeries, Exam, CidUserAnswer from django.contrib.auth.models import User def get_exams(request): @@ -51,4 +51,23 @@ class LongSeriesFilter(django_filters.FilterSet): #queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id) queryset = queryset.filter(author__id=request.user.id) super(LongSeriesFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) + pass + +class UserAnswerFilter(django_filters.FilterSet): + class Meta: + model = CidUserAnswer + fields = ( + "cid", + #"normal", + #"answer", + #"answer_compare", + "exam", + "created", + "updated", + ) + + def __init__(self, data=None, queryset=None, prefix=None, strict=None, user=None, request=None): + if not request.user.groups.filter(name="long_checker").exists(): + queryset = queryset.filter(open_access=True) | queryset.filter(author__id=request.user.id) + super(UserAnswerFilter, self).__init__(data=data, queryset=queryset, prefix=prefix, request=request) pass \ No newline at end of file diff --git a/longs/tables.py b/longs/tables.py index c1aebc63..5351ba23 100755 --- a/longs/tables.py +++ b/longs/tables.py @@ -1,7 +1,7 @@ import django_tables2 as tables from django_tables2.utils import A -from .models import Long, LongSeries +from .models import Long, LongSeries, CidUserAnswer from django.utils.html import format_html @@ -111,4 +111,28 @@ class LongSeriesTable(tables.Table): def render_popup(self, value, record): print(self) - return format_html("""Popup""", record.pk) \ No newline at end of file + return format_html("""Popup""", record.pk) + +class UserAnswerTable(tables.Table): + select = tables.CheckBoxColumn(accessor=("pk")) + delete = tables.LinkColumn( + "longs:user_answer_delete", text="Delete", args=[A("pk")], orderable=False + ) + view = tables.LinkColumn('longs:user_answer_view', + text='View', + args=[A('pk')], + orderable=False) + class Meta: + model = CidUserAnswer + template_name = "django_tables2/bootstrap4.html" + fields = ( + "cid", + "question", + #"normal", + #"answer", + #"answer_compare", + "exam", + "created", + "updated", + ) + \ No newline at end of file diff --git a/longs/templates/longs/ciduseranswer_detail.html b/longs/templates/longs/ciduseranswer_detail.html new file mode 100644 index 00000000..508aedd9 --- /dev/null +++ b/longs/templates/longs/ciduseranswer_detail.html @@ -0,0 +1,19 @@ + +{% extends 'rapids/base.html' %} + +{% block content %} +CID: {{ciduseranswer.cid}} + +

Question

+{{ciduseranswer.question}} + +

Answers

+{{ciduseranswer.model_observations}}
+{{ciduseranswer.model_interpretation}}
+{{ciduseranswer.model_principle_diagnosis}}
+{{ciduseranswer.model_differential_diagnosis}}
+{{ciduseranswer.model_management}}
+ + + +{% endblock content %} \ No newline at end of file diff --git a/longs/templates/longs/exam_overview.html b/longs/templates/longs/exam_overview.html index 97239ec9..032586af 100644 --- a/longs/templates/longs/exam_overview.html +++ b/longs/templates/longs/exam_overview.html @@ -62,6 +62,8 @@ JSONRefresh JSON cache + Refresh Question JSON cache + diff --git a/longs/templates/longs/exam_scores.html b/longs/templates/longs/exam_scores.html index 6579fcc5..d7e8f5b8 100644 --- a/longs/templates/longs/exam_scores.html +++ b/longs/templates/longs/exam_scores.html @@ -16,13 +16,13 @@

Stats

Candidates: {{cids|length}}
- Max score: {{max_score}}
+ Max score: {{max_score}}
Mean: {{mean}}, Median {{median}}, Mode {{mode}} - +
{{plot|safe}}
-
-
Candidate
Question {{forloop.counter}}
+
+
@@ -35,30 +35,32 @@ {% endfor %}
Candidate ID Score
-
-

Answers as a table

- - - - {% for cid in cids %} - - {% endfor %} +
+

Results as a table

+
Candidate{{cid}}
+ + + + {% for cid in cids %} + + {% endfor %} - - {% for question in questions %} - - - {% for ans, score in by_question|get_item:question %} - + + + {% for question in questions %} + + + {% for ans, score in by_question|get_item:question %} + + {% endfor %} + {% endfor %} - - {% endfor %} - - - {% for score in user_scores_list %} - - {% endfor %} - + + + {% for score in user_scores_list %} + + {% endfor %} +
Candidate{{cid}}
Question {{forloop.counter}}{{score}}
Question {{forloop.counter}}{{score}}
Score:{{score}}
Score:{{score}}
diff --git a/longs/templates/longs/question_view.html b/longs/templates/longs/question_view.html new file mode 100644 index 00000000..c271bdf0 --- /dev/null +++ b/longs/templates/longs/question_view.html @@ -0,0 +1,56 @@ +{% extends 'longs/base.html' %} + +{% load render_table from django_tables2 %} +{% block css %} +{% endblock %} + +{% block content %} + +
+

Filter Long

+
+ {{ filter.form }} + +
+
+ +{% render_table table %} + +{% endblock %} + +{% block js %} + +{% endblock %} \ No newline at end of file diff --git a/longs/urls.py b/longs/urls.py index 7edf2ffa..367e1db5 100755 --- a/longs/urls.py +++ b/longs/urls.py @@ -39,6 +39,7 @@ urlpatterns = [ ), path("exam//", views.LongExamViews.exam_overview, name="exam_overview"), path("exam//json_edit", views.LongExamViews.exam_json_edit, name="exam_json_edit"), + path("exam//question_json_refresh", views.refresh_exam_question_json, name="refresh_exam_question_json"), path("exam//scores", views.exam_scores_cid, name="exam_scores_cid"), path( "exam//scores//", @@ -104,4 +105,8 @@ urlpatterns = [ name="long_series_update", ), path("/add_note", views.AddNote.as_view(), name="long_add_note"), + path("user_answers/", views.UserAnswerTableView.as_view(), name="user_answer_table_view"), + path("user_answers/", views.UserAnswerView.as_view(), name="user_answer_view"), + path("user_answers//delete", views.UserAnswerDelete.as_view(), name="user_answer_delete"), + path("user_answers/delete", views.user_answer_delete_multiple, name="user_answer_delete_multiple"), ] diff --git a/longs/views.py b/longs/views.py index f02aa1f8..337883a6 100755 --- a/longs/views.py +++ b/longs/views.py @@ -8,6 +8,8 @@ from django.contrib.auth.models import User from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ViewDoesNotExist from django.contrib.auth.mixins import LoginRequiredMixin +from django.views.generic.detail import DetailView +from generic.mixins import SuperuserRequiredMixin from django.views.generic.edit import CreateView, UpdateView, DeleteView from django.views.generic import ListView @@ -33,8 +35,8 @@ from .models import ( Exam, CidUserAnswer, ) -from .tables import LongTable, LongSeriesTable -from .filters import LongFilter, LongSeriesFilter +from .tables import LongTable, LongSeriesTable, UserAnswerTable +from .filters import LongFilter, LongSeriesFilter, UserAnswerFilter from django_tables2 import SingleTableView, SingleTableMixin from django_filters.views import FilterView @@ -998,4 +1000,44 @@ def question_json_recreate(request, pk): #question.get_question_json() - return redirect("longs:question_detail", pk=pk) \ No newline at end of file + return redirect("longs:question_detail", pk=pk) + + +class UserAnswerView(LoginRequiredMixin, DetailView): + model = CidUserAnswer + + +class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): + model = CidUserAnswer + table_class = UserAnswerTable + template_name = "longs/question_view.html" + + filterset_class = UserAnswerFilter + + +class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): + model = CidUserAnswer + 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(): + answer_ids = json.loads(request.POST["answer_ids"]) + + # We could probably delete them all at once.... + for id in answer_ids: + CidUserAnswer.objects.get(pk=id).delete() + return HttpResponseRedirect(request.path_info) + return HttpResponse("/") + + +@user_passes_test(lambda u: u.is_superuser) +def refresh_exam_question_json(request, pk): + exam = Exam.objects.get(pk=pk) + + for question in exam.exam_questions.all(): + question.recreate_json = True + question.save() + + return redirect("longs:exam_overview", pk=pk) + diff --git a/physics/templates/physics/exam_scores.html b/physics/templates/physics/exam_scores.html index c1e712c2..96c987e9 100644 --- a/physics/templates/physics/exam_scores.html +++ b/physics/templates/physics/exam_scores.html @@ -16,7 +16,7 @@
- +
@@ -31,13 +31,14 @@

Answers as a table

-
Candidate ID Score
+
+ {% for cid in cids %} {% endfor %} - + {% for question in questions %} diff --git a/rapids/templates/rapids/exam_scores.html b/rapids/templates/rapids/exam_scores.html index 918eba05..c92f5c1e 100644 --- a/rapids/templates/rapids/exam_scores.html +++ b/rapids/templates/rapids/exam_scores.html @@ -22,7 +22,7 @@
{{plot|safe}}
-
Candidate{{cid}}
+
@@ -37,7 +37,8 @@

Answers as a table

-
Candidate ID Score
+
+ {% for cid in cids %} @@ -45,6 +46,7 @@ {% endfor %} + {% for question in questions %} diff --git a/rapids/urls.py b/rapids/urls.py index 44ccbcec..6eab01b0 100755 --- a/rapids/urls.py +++ b/rapids/urls.py @@ -66,7 +66,7 @@ urlpatterns = [ name="rapid_update", ), path("/add_note", views.AddNote.as_view(), name="rapid_add_note"), - path("user_answers/", views.RapidUserAnswerTableView.as_view(), name="rapid_user_answer_table_view"), - path("user_answers/", views.RapidUserAnswerView.as_view(), name="rapid_user_answer_view"), + path("user_answers/", views.UserAnswerTableView.as_view(), name="rapid_user_answer_table_view"), + path("user_answers/", views.UserAnswerView.as_view(), name="rapid_user_answer_view"), path("user_answers//delete", views.UserAnswerDelete.as_view(), name="rapid_user_answer_delete"), ] diff --git a/rapids/views.py b/rapids/views.py index b0a470ed..9657ad8f 100755 --- a/rapids/views.py +++ b/rapids/views.py @@ -985,11 +985,11 @@ class ExamUpdate( return super().form_valid(form) -class RapidUserAnswerView(LoginRequiredMixin, DetailView): +class UserAnswerView(LoginRequiredMixin, DetailView): model = CidUserAnswer -class RapidUserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): +class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer table_class = RapidUserAnswerTable template_name = "rapids/rapid_question_view.html" diff --git a/sbas/templates/sbas/exam_scores.html b/sbas/templates/sbas/exam_scores.html index 99fd57bc..15e56721 100644 --- a/sbas/templates/sbas/exam_scores.html +++ b/sbas/templates/sbas/exam_scores.html @@ -16,7 +16,7 @@
-
Candidate
Question {{forloop.counter}}
+
@@ -30,8 +30,9 @@
Candidate ID Score
-

Answers as a table

- +

Results as a table

+
+ {% for cid in cids %} @@ -39,6 +40,7 @@ {% endfor %} + {% for question in questions %} diff --git a/static/css/anatomy.css b/static/css/anatomy.css index b62659d1..f47d2658 100644 --- a/static/css/anatomy.css +++ b/static/css/anatomy.css @@ -485,4 +485,20 @@ td.user-answer-score-2::after { .notes .complete { color: darkslategray; + } + + table.longs .user-answer-score-4, table.longs .user-answer-score-4\.5 { + color: red + } + + table.longs .user-answer-score-5\.0, table.longs .user-answer-score-5\.5 { + color: yellow + } + + table.longs .user-answer-score-6\.0, table.longs .user-answer-score-6\.5 { + color: yellowgreen + } + + table.longs .user-answer-score-7\.0, table.longs .user-answer-score-7\.5 { + color: green } \ No newline at end of file
Candidate
Question {{forloop.counter}}