From 48109e5bf7918b2a3735f821ddde8e353533fb4d Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 2 Oct 2021 15:42:31 +0100 Subject: [PATCH 1/4] . --- .../anatomy/exam_confirm_delete.html | 4 -- anatomy/views.py | 54 +++++++++++-------- templates/exam_confirm_delete.html | 1 + 3 files changed, 33 insertions(+), 26 deletions(-) delete mode 100644 anatomy/templates/anatomy/exam_confirm_delete.html diff --git a/anatomy/templates/anatomy/exam_confirm_delete.html b/anatomy/templates/anatomy/exam_confirm_delete.html deleted file mode 100644 index 41ddc888..00000000 --- a/anatomy/templates/anatomy/exam_confirm_delete.html +++ /dev/null @@ -1,4 +0,0 @@ -
{% csrf_token %} -

Are you sure you want to delete "{{ object }}"?

- -
\ No newline at end of file diff --git a/anatomy/views.py b/anatomy/views.py index 9621b0c8..c2d17058 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -33,13 +33,13 @@ from .forms import ( MarkAnatomyQuestionForm, AnatomyQuestionForm, StructureForm, - ExamForm + ExamForm, ) from .models import ( AnatomyQuestion, BodyPart, CidUserAnswer, - #Examination, + # Examination, Structure, Exam, Answer, @@ -84,6 +84,7 @@ class AuthorOrCheckerRequiredMixin(object): raise PermissionDenied() # or Http404 return obj + @register.filter def get_item(dictionary, key): return dictionary.get(key) @@ -96,18 +97,16 @@ def user_is_admin(user): return False - def question_list(request): questions = AnatomyQuestion.objects.all() - if not request.user.groups.filter(name="anatomy_checker").exists() : + if not request.user.groups.filter(name="anatomy_checker").exists(): questions = questions.filter(open_access=False) - #raise PermissionDenied() + # raise PermissionDenied() return render(request, "anatomy/question_list.html", {"questions": questions}) - @login_required def answer_question(request, pk): question = get_object_or_404(AnatomyQuestion, pk=pk) @@ -133,7 +132,6 @@ def answer_question(request, pk): ) - @login_required def exam_take(request, pk, sk): """ @@ -228,7 +226,9 @@ def loadJsonAnswer(answer): if (not isinstance(answer["cid"], int)) or ( not isinstance(eid, int) or (not isinstance(answer["ans"], str)) ): - return False, JsonResponse({"success": False, "error": "cid or eid or answers not defined"}) + return False, JsonResponse( + {"success": False, "error": "cid or eid or answers not defined"} + ) # The model should catch invalid data but this should be less intensive max_int = 999999999999999999999 @@ -237,7 +237,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)} # ) @@ -265,8 +265,8 @@ def loadJsonAnswer(answer): return True, None -#@csrf_exempt -#def postExamAnswers(request): +# @csrf_exempt +# def postExamAnswers(request): # if request.is_ajax and request.method == "POST": # # n = 0 @@ -435,7 +435,6 @@ def mark(request, pk, sk): ) - @login_required def exam_scores_cid(request, pk): exam = get_object_or_404(Exam, pk=pk) @@ -552,7 +551,6 @@ def exam_scores_cid_user(request, pk, sk): answers_marks = [] answers = [] - view_all_results = False if request.user.groups.filter(name="view_all_results").exists(): view_all_results = True @@ -696,7 +694,7 @@ class AnatomyQuestionCreateBase(RevisionMixin, LoginRequiredMixin, CreateView): def get_form_kwargs(self): kwargs = super(AnatomyQuestionCreateBase, self).get_form_kwargs() - kwargs.update({'user': self.request.user}) + kwargs.update({"user": self.request.user}) return kwargs def get_context_data(self, **kwargs): @@ -801,7 +799,7 @@ class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateV def get_form_kwargs(self): kwargs = super(AnatomyQuestionUpdate, self).get_form_kwargs() - kwargs.update({'user': self.request.user}) + kwargs.update({"user": self.request.user}) return kwargs def get_context_data(self, **kwargs): @@ -826,7 +824,6 @@ class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateV self.object = form.save(commit=False) self.object.save() - form.instance.author.add(self.request.user.id) context = self.get_context_data(form=form) @@ -949,6 +946,7 @@ class AnatomyQuestionView(LoginRequiredMixin, SingleTableMixin, FilterView): filterset_class = AnatomyQuestionFilter + @user_is_author_or_anatomy_checker def question_save_annotation(request, pk): if request.is_ajax() and request.method == "POST": @@ -965,11 +963,15 @@ def question_save_annotation(request, pk): return JsonResponse(data, status=400) -AnatomyExamViews = ExamViews(Exam, AnatomyQuestion, "anatomy", "anatomy", loadJsonAnswer) +AnatomyExamViews = ExamViews( + Exam, AnatomyQuestion, "anatomy", "anatomy", loadJsonAnswer +) + class UserAnswerView(LoginRequiredMixin, DetailView): model = CidUserAnswer + class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): model = CidUserAnswer table_class = AnatomyUserAnswerTable @@ -978,16 +980,17 @@ class UserAnswerTableView(LoginRequiredMixin, SingleTableMixin, FilterView): filterset_class = AnatomyUserAnswerFilter - class UserAnswerDelete(SuperuserRequiredMixin, DeleteView): model = CidUserAnswer template_name = "user_answer_delete.html" success_url = reverse_lazy("anatomy:user_answer_table_view") + class QuestionDelete(AuthorOrCheckerRequiredMixin, DeleteView): model = AnatomyQuestion success_url = reverse_lazy("anatomy:question_list") + class ExamCreate(RevisionMixin, LoginRequiredMixin, CreateView): model = Exam form_class = ExamForm @@ -999,7 +1002,10 @@ class ExamCreate(RevisionMixin, LoginRequiredMixin, CreateView): form.instance.author.add(self.request.user.id) return super().form_valid(form) -class ExamUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView): + +class ExamUpdate( + RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView +): model = Exam form_class = ExamForm @@ -1010,8 +1016,9 @@ class ExamUpdate(RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin form.instance.author.add(self.request.user.id) return super().form_valid(form) + class ExamViewSet(RevisionMixin, viewsets.ModelViewSet): - #queryset = Exam.objects.all().order_by('name') + # queryset = Exam.objects.all().order_by('name') serializer_class = ExamSerializer permission_classes = [permissions.IsAuthenticated] @@ -1022,15 +1029,18 @@ class ExamViewSet(RevisionMixin, viewsets.ModelViewSet): user = self.request.user if user.groups.filter(name="rapid_checker").exists(): return Exam.objects.all() - + return Exam.objects.filter(author__id=user.id) + class ExamDelete(RevisionMixin, AuthorOrCheckerRequiredMixin, DeleteView): model = Exam template_name = "exam_confirm_delete.html" success_url = reverse_lazy("anatomy:index") + GenericViews = GenericViewBase("anatomy", AnatomyQuestion, CidUserAnswer, Exam) + class ExamClone(ExamCloneMixin, ExamCreate): - """Clone exam view""" \ No newline at end of file + """Clone exam view""" diff --git a/templates/exam_confirm_delete.html b/templates/exam_confirm_delete.html index c46a5ccf..169815b2 100644 --- a/templates/exam_confirm_delete.html +++ b/templates/exam_confirm_delete.html @@ -5,6 +5,7 @@
{% csrf_token %}

Are you sure you want to delete the exam "{{ object }}"?

+ Cancel
{% endblock content %} \ No newline at end of file From 57cbf601aa5c13a68b90d805e0c50b1c4babe69f Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 2 Oct 2021 15:46:54 +0100 Subject: [PATCH 2/4] . --- anatomy/templates/anatomy/question_detail.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/anatomy/templates/anatomy/question_detail.html b/anatomy/templates/anatomy/question_detail.html index 3ec246bc..ca381164 100644 --- a/anatomy/templates/anatomy/question_detail.html +++ b/anatomy/templates/anatomy/question_detail.html @@ -69,7 +69,12 @@ {% include 'question_notes.html' %}
Annotation JSON (+/-): + + {% if question.image_annotations %}
{{ question.image_annotations }}
+ {% else %} + No saved annotations. + {% endif %}
From fc09097958b1127ad3f86701b792316898f1a482 Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 2 Oct 2021 15:48:00 +0100 Subject: [PATCH 3/4] . --- .../templates/anatomy/question_detail.html | 68 ++++++++++--------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/anatomy/templates/anatomy/question_detail.html b/anatomy/templates/anatomy/question_detail.html index ca381164..d6da1fb5 100644 --- a/anatomy/templates/anatomy/question_detail.html +++ b/anatomy/templates/anatomy/question_detail.html @@ -10,21 +10,23 @@ Clone Delete Delete - Add Note + + Add Note Admin Edit -{% if exam %} -
+ {% if exam %} +
- {% if previous > -1 %} - Previous question + {% if previous > -1 %} + Previous question + {% endif %} + Viewing question as part of exam: {{exam.name}} [{{pos}}/{{exam_length}}] + {% if next %} + Next question + {% endif %} +
{% endif %} - Viewing question as part of exam: {{exam.name}} [{{pos}}/{{exam_length}}] - {% if next %} - Next question - {% endif %} -
-{% endif %}
{% include 'question_notes.html' %}
- Annotation JSON (+/-): - - {% if question.image_annotations %} +
+ + Annotation JSON (+/-): + + + {% if question.image_annotations %}
{{ question.image_annotations }}
- {% else %} - No saved annotations. - {% endif %} - + {% else %} + No saved annotations. + {% endif %} + +
{% endblock %} \ No newline at end of file From 686fb2bd35279ef18a1173a1c47b9bc24b14edfc Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 2 Oct 2021 15:58:45 +0100 Subject: [PATCH 4/4] . --- anatomy/models.py | 10 ++++++++++ anatomy/templates/anatomy/mark.html | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/anatomy/models.py b/anatomy/models.py index 03698670..1a330132 100644 --- a/anatomy/models.py +++ b/anatomy/models.py @@ -1,3 +1,4 @@ +import json from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.utils import timezone @@ -256,6 +257,15 @@ class AnatomyQuestion(models.Model): return json + def get_image_url(self): + return "https://www.penracourses.org.uk{}".format(self.image.url) + + def get_image_url_array(self): + return json.dumps(["https://www.penracourses.org.uk{}".format(self.image.url)]) + + def get_image_annotations(self): + return json.dumps([self.image_annotations]) + @reversion.register class Answer(models.Model): diff --git a/anatomy/templates/anatomy/mark.html b/anatomy/templates/anatomy/mark.html index 5a9a415c..77a6ea72 100644 --- a/anatomy/templates/anatomy/mark.html +++ b/anatomy/templates/anatomy/mark.html @@ -5,7 +5,7 @@ View Edit Admin Edit

{{ question.question_type }}

-
+
{% csrf_token %}