add a redirct view mixin

This commit is contained in:
Ross
2024-08-12 11:58:28 +01:00
parent 8beb6890a7
commit c2185f73a6
8 changed files with 126 additions and 106 deletions
+2 -19
View File
@@ -52,7 +52,7 @@ from .models import (
# IncorrectAnswers, # IncorrectAnswers,
) )
from generic.models import CidUser, Examination from generic.models import CidUser, Examination
from generic.views import AuthorRequiredMixin, ExamCloneMixin, ExamCreateBase, ExamDeleteBase, ExamGroupsUpdateBase, ExamUpdateBase, ExamViews, GenericViewBase from generic.views import AuthorRequiredMixin, ExamCloneMixin, ExamCreateBase, ExamDeleteBase, ExamGroupsUpdateBase, ExamUpdateBase, ExamViews, GenericViewBase, UpdateQuestionMixin
from reversion.views import RevisionMixin from reversion.views import RevisionMixin
from .decorators import user_is_author_or_anatomy_checker from .decorators import user_is_author_or_anatomy_checker
@@ -598,27 +598,10 @@ class AnatomyQuestionAnswerUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, U
return super().form_invalid(form) return super().form_invalid(form)
# class AnatomyQuestionUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, # class AnatomyQuestionUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin,
class AnatomyQuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView): class AnatomyQuestionUpdate(UpdateQuestionMixin,AuthorOrCheckerRequiredMixin):
model = AnatomyQuestion model = AnatomyQuestion
form_class = AnatomyQuestionForm form_class = AnatomyQuestionForm
def get_form_kwargs(self):
kwargs = super(AnatomyQuestionUpdate, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs):
context = super(AnatomyQuestionUpdate, self).get_context_data(**kwargs)
#if self.request.POST:
# context["answer_formset"] = AnswerUpdateFormSet(
# self.request.POST, self.request.FILES, instance=self.object
# )
# context["answer_formset"].full_clean()
#else:
# context["answer_formset"] = AnswerUpdateFormSet(instance=self.object)
context["question"] = context["object"]
return context
def form_valid(self, form): def form_valid(self, form):
self.object = form.save(commit=False) self.object = form.save(commit=False)
self.object.save() self.object.save()
+10
View File
@@ -186,6 +186,16 @@ class QuestionBase(models.Model, AuthorMixin, QuestionMixin):
"""If this makes sense in the question/answer context override""" """If this makes sense in the question/answer context override"""
return None return None
def can_edit(self, user: User) -> bool:
"""Returns True if the user can edit the question"""
if user.is_superuser:
return True
if user in self.get_author_objects():
return True
return False
class SeriesImageBase(models.Model): class SeriesImageBase(models.Model):
""" """
+22 -1
View File
@@ -1515,6 +1515,8 @@ class ExamViews(View, LoginRequiredMixin):
): ):
view_feedback = True view_feedback = True
can_edit = question.can_edit(request.user)
return render( return render(
request, request,
"{}/question_detail.html".format(self.app_name), "{}/question_detail.html".format(self.app_name),
@@ -1526,6 +1528,7 @@ class ExamViews(View, LoginRequiredMixin):
"exam_length": exam_length, "exam_length": exam_length,
"pos": pos, "pos": pos,
"view_feedback": view_feedback, "view_feedback": view_feedback,
"can_edit": can_edit,
}, },
) )
@@ -3512,4 +3515,22 @@ class ExamGroupsUpdateBase(
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = super(ExamGroupsUpdateBase, self).get_form_kwargs() kwargs = super(ExamGroupsUpdateBase, self).get_form_kwargs()
kwargs.update({"user": self.request.user}) kwargs.update({"user": self.request.user})
return kwargs return kwargs
class RedirectMixin():
def get_success_url(self) -> str:
if "redirect" in self.request.GET:
return self.request.GET["redirect"]
return super().get_success_url()
class UpdateQuestionMixin(RedirectMixin, RevisionMixin, UpdateView):
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["question"] = context["object"]
return context
+66 -57
View File
@@ -11,77 +11,86 @@
<div class="pre-whitespace multi-image-block"><b>Series:</b> <div class="pre-whitespace multi-image-block"><b>Series:</b>
{% for series in question.series.all %} {% for series in question.series.all %}
<span class="series-block"> <span class="series-block">
<span> <span>
<span class="series-block-series-number">Series {{ forloop.counter }}:</span> <span class="series-block-series-number">Series {{ forloop.counter }}:</span>
<a href="{% url 'longs:series_detail' pk=series.pk %}"> <a href="{% url 'longs:series_detail' pk=series.pk %}">
{{series.get_block}} {{series.get_block}}
</a> </a>
<br> <br>
<span class="series-block-popup-link"> <span class="series-block-popup-link">
<a href="#" <a href="#"
onclick="return window.create_popup_window('/longs/series/{{series.pk}}', 'Series')">Popup</a> onclick="return window.create_popup_window('/longs/series/{{series.pk}}', 'Series')">Popup</a>
</span>
</span> </span>
</span> </span>
</span>
{% endfor %} {% endfor %}
<a href="{% url 'longs:long_series_id_create' pk=question.pk %}">Add new series</a><br /> <a href="{% url 'longs:long_series_id_create' pk=question.pk %}">Add new series</a><br />
</div> </div>
<p><b>Author(s):</b> {% for author in question.author.all %} <a <p><b>Author(s):</b> {% for author in question.author.all %} <a
href="{% url 'longs:author_detail' pk=author.pk %}">{{author}}</a>, {% endfor %}</p> href="{% url 'longs:author_detail' pk=author.pk %}">{{author}}</a>, {% endfor %}</p>
<p><b>Checked by:</b> {% for verified in question.verified.all %} <a <p><b>Checked by:</b> {% for verified in question.verified.all %} <a
href="{% url 'longs:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p> href="{% url 'longs:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p>
{% comment %} <p><b>Scrapped:</b> {{ question.scrapped }} <a {% comment %} <p><b>Scrapped:</b> {{ question.scrapped }} <a
href="{% url 'longs:long_scrap' pk=question.pk %}">(toggle)</a> {% endcomment %} href="{% url 'longs:long_scrap' pk=question.pk %}">(toggle)</a> {% endcomment %}
<div class="long-answer"> <div class="long-answer">
<p class="pre-whitespace"><b>Feedback:</b> <p class="pre-whitespace"><b>Feedback:</b>
<pre>{{ question.feedback | safe}}</pre> <pre>{{ question.feedback | safe}}</pre>
</p>
<details>
<summary>
<b>Model answers</b>
</summary>
{% if not question.model_differential_diagnosis and not question.model_interpretation and not question.model_management and not question.model_observations and not question.model_principle_diagnosis %}
<div class="alert alert-warning">No model answers.
{% if can_edit %}
<a href="{% url 'longs:long_update' pk=question.pk %}">Add some nowr.</a>
{% endif %}
</div>
{% endif %}
<p class="pre-whitespace"><b>Observations:</b>
<pre>{{ question.model_observations|default:"None" }}</pre>
</p> </p>
<p class="pre-whitespace"><b>Interpretation:</b>
<pre>{{ question.model_interpretation|default:"None" }}</pre>
</p>
<p class="pre-whitespace"><b>Principle Diagnosis:</b>
<pre>{{ question.model_principle_diagnosis|default:"None" }}</pre>
</p>
<p class="pre-whitespace"><b>Differential Diagnosis:</b>
<pre>{{ question.model_differential_diagnosis|default:"None" }}</pre>
</p>
<p class="pre-whitespace"><b>Managment:</b>
<pre>{{ question.model_management|default:"None" }}</pre>
</p>
</details>
<p class="pre-whitespace">
<details> <details>
<summary> <summary><b>Mark Scheme:</b></summary>
<b>Model answers</b>
</summary>
<p class="pre-whitespace"><b>Observations:</b>
<pre>{{ question.model_observations }}</pre>
</p>
<p class="pre-whitespace"><b>Interpretation:</b>
<pre>{{ question.model_interpretation }}</pre>
</p>
<p class="pre-whitespace"><b>Principle Diagnosis:</b>
<pre>{{ question.model_principle_diagnosis }}</pre>
</p>
<p class="pre-whitespace"><b>Differential Diagnosis:</b>
<pre>{{ question.model_differential_diagnosis }}</pre>
</p>
<p class="pre-whitespace"><b>Managment:</b>
<pre>{{ question.model_management }}</pre>
</p>
</details>
<p class="pre-whitespace">
<details>
<summary><b>Mark Scheme:</b></summary>
<pre>{{ question.mark_scheme | safe}}</pre> <pre>{{ question.mark_scheme | safe}}</pre>
</details> </details>
</p> </p>
</div> </div>
</p> </p>
<div> <div>
Exam(s): {% for exam in question.exams.all %} Exam(s): {% for exam in question.exams.all %}
<a href="{% url 'longs:exam_overview' pk=exam.pk %}">{{ exam }}</a>, <a href="{% url 'longs:exam_overview' pk=exam.pk %}">{{ exam }}</a>,
{% endfor %} {% endfor %}
</div> </div>
<div> <div>
{% include 'question_notes.html' %} {% include 'question_notes.html' %}
</div> </div>
<div> <div>
JSON creation time: {{question.json_creation_time}} ({{question.json_creation_time|date:"c"}}), JSON creation time: {{question.json_creation_time}} ({{question.json_creation_time|date:"c"}}),
JSON creation id: {{question.question_json_id}} JSON creation id: {{question.question_json_id}}
{% if question.recreate_json %}[JSON out of date]{% endif %} {% if question.recreate_json %}[JSON out of date]{% endif %}
</div> </div>
<a href="{% url 'longs:question_json' pk=question.pk %}">JSON</a> <a href="{% url 'longs:question_json' pk=question.pk %}">JSON</a>
<a href="{% url 'longs:question_json_unbased' pk=question.pk %}">JSON (unbased)</a> <a href="{% url 'longs:question_json_unbased' pk=question.pk %}">JSON (unbased)</a>
<a href="{% url 'longs:question_json_recreate' pk=question.pk %}">Refresh JSON cache</a> <a href="{% url 'longs:question_json_recreate' pk=question.pk %}">Refresh JSON cache</a>
+1 -1
View File
@@ -5,7 +5,7 @@
<div class="floating-header"> <div class="floating-header">
<a href="{% url 'longs:long_update' pk=question.pk %}" title="Edit the Long">Edit</a> <a href="{% url 'longs:long_update' pk=question.pk %}?redirect={{request.path}}" title="Edit the Long">Edit</a>
<a href="{% url 'longs:long_clone' pk=question.pk %}" title="Clone the Long (duplicate everything but the images)">Clone</a> <a href="{% url 'longs:long_clone' pk=question.pk %}" title="Clone the Long (duplicate everything but the images)">Clone</a>
<a href="{% url 'longs:long_delete' pk=question.pk %}" title="Delete the Rapid">Delete</a> <a href="{% url 'longs:long_delete' pk=question.pk %}" title="Delete the Rapid">Delete</a>
<a href="#" onclick="return window.create_popup_window('{% url 'feedback_create' question_type='long' pk=question.pk %}')"> Add Note</a> <a href="#" onclick="return window.create_popup_window('{% url 'feedback_create' question_type='long' pk=question.pk %}')"> Add Note</a>
+19 -13
View File
@@ -85,7 +85,9 @@ from generic.views import (
ExamGroupsUpdateBase, ExamGroupsUpdateBase,
ExamUpdateBase, ExamUpdateBase,
ExamViews, ExamViews,
RedirectMixin,
SeriesImagesZipViewBase, SeriesImagesZipViewBase,
UpdateQuestionMixin,
) )
from reversion.views import RevisionMixin from reversion.views import RevisionMixin
import reversion import reversion
@@ -155,7 +157,10 @@ def question_detail(request, pk):
# raise PermissionDenied # raise PermissionDenied
# logging.debug(long.subspecialty.first().name.all()) # logging.debug(long.subspecialty.first().name.all())
return render(request, "longs/question_detail.html", {"question": long}) can_edit = long.can_edit(request.user)
return render(
request, "longs/question_detail.html", {"question": long, "can_edit": can_edit}
)
@login_required @login_required
@@ -500,7 +505,7 @@ class LongCreate(LongCreateBase):
class LongUpdate( class LongUpdate(
RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView UpdateQuestionMixin,AuthorOrCheckerRequiredMixin
): ):
model = Long model = Long
form_class = LongForm form_class = LongForm
@@ -510,13 +515,9 @@ class LongUpdate(
# #initial = {'date_of_death': '05/01/2018'} # #initial = {'date_of_death': '05/01/2018'}
# exclude = [ 'created_date', 'published_date' ] # exclude = [ 'created_date', 'published_date' ]
def get_form_kwargs(self):
kwargs = super(LongUpdate, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(LongUpdate, self).get_context_data(**kwargs) context = super().get_context_data(**kwargs)
if self.request.POST: if self.request.POST:
context["series_formset"] = SeriesFormSet( context["series_formset"] = SeriesFormSet(
self.request.POST, self.request.FILES, instance=self.object self.request.POST, self.request.FILES, instance=self.object
@@ -563,6 +564,7 @@ class LongUpdate(
return super().form_invalid(form) return super().form_invalid(form)
class LongClone(LongCreateBase): class LongClone(LongCreateBase):
"""Clones a existing long""" """Clones a existing long"""
@@ -643,12 +645,12 @@ class LongSeriesView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = LongSeriesFilter filterset_class = LongSeriesFilter
#@user_is_long_marker # @user_is_long_marker
def mark_answer_override(request, exam_id, question_number, cid): def mark_answer_override(request, exam_id, question_number, cid):
return mark_answer(request, exam_id, question_number, cid, override=True) return mark_answer(request, exam_id, question_number, cid, override=True)
#@user_is_long_marker # @user_is_long_marker
@reversion.create_revision() @reversion.create_revision()
def mark_answer(request, exam_id, question_number, answer_id, override=False): def mark_answer(request, exam_id, question_number, answer_id, override=False):
exam = get_object_or_404(Exam, pk=exam_id) exam = get_object_or_404(Exam, pk=exam_id)
@@ -847,7 +849,7 @@ def mark_answer(request, exam_id, question_number, answer_id, override=False):
# @user_passes_test(user_is_admin, login_url="/accounts/login") # @user_passes_test(user_is_admin, login_url="/accounts/login")
@login_required @login_required
#@user_is_long_marker # @user_is_long_marker
def mark(request, exam_id, sk): def mark(request, exam_id, sk):
exam = get_object_or_404(Exam, pk=exam_id) exam = get_object_or_404(Exam, pk=exam_id)
@@ -902,8 +904,6 @@ def mark(request, exam_id, sk):
) )
@login_required @login_required
@user_is_author_or_long_series_checker @user_is_author_or_long_series_checker
def long_series_order_dicom(request, pk): def long_series_order_dicom(request, pk):
@@ -985,14 +985,20 @@ class ExamAuthorUpdate(
form_class = ExamAuthorForm form_class = ExamAuthorForm
template_name = "author_form.html" template_name = "author_form.html"
class ExamMarkersUpdate( class ExamMarkersUpdate(
RevisionMixin, CheckCanEditMixin, LoginRequiredMixin, AuthorRequiredMixin, UpdateView RevisionMixin,
CheckCanEditMixin,
LoginRequiredMixin,
AuthorRequiredMixin,
UpdateView,
): ):
model = Exam model = Exam
form_class = ExamMarkerForm form_class = ExamMarkerForm
template_name = "markers_form.html" template_name = "markers_form.html"
class ExamGroupsUpdate(ExamGroupsUpdateBase): class ExamGroupsUpdate(ExamGroupsUpdateBase):
model = Exam model = Exam
form_class = ExamGroupsForm form_class = ExamGroupsForm
+4 -5
View File
@@ -54,6 +54,7 @@ from generic.views import (
ExamUpdateBase, ExamUpdateBase,
ExamViews, ExamViews,
GenericViewBase, GenericViewBase,
UpdateQuestionMixin,
) )
from reversion.views import RevisionMixin from reversion.views import RevisionMixin
@@ -374,7 +375,9 @@ class RapidAnswerUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView)
return super().form_invalid(form) return super().form_invalid(form)
class RapidUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView): class RapidUpdate(
UpdateQuestionMixin,AuthorOrCheckerRequiredMixin
):
model = Rapid model = Rapid
form_class = RapidForm form_class = RapidForm
@@ -382,10 +385,6 @@ class RapidUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView):
# #fields = [ 'condition' ] # #fields = [ 'condition' ]
# #initial = {'date_of_death': '05/01/2018'} # #initial = {'date_of_death': '05/01/2018'}
# exclude = [ 'created_date', 'published_date' ] # exclude = [ 'created_date', 'published_date' ]
def get_form_kwargs(self):
kwargs = super(RapidUpdate, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RapidUpdate, self).get_context_data(**kwargs) context = super(RapidUpdate, self).get_context_data(**kwargs)
+2 -10
View File
@@ -50,6 +50,7 @@ from generic.views import (
ExamUpdateBase, ExamUpdateBase,
ExamViews, ExamViews,
GenericViewBase, GenericViewBase,
UpdateQuestionMixin,
exam_inactive, exam_inactive,
) )
@@ -317,19 +318,10 @@ class QuestionCreate(QuestionCreateBase):
return initial return initial
class QuestionUpdate(RevisionMixin, AuthorOrCheckerRequiredMixin, UpdateView): class QuestionUpdate(AuthorOrCheckerRequiredMixin, UpdateQuestionMixin):
model = Question model = Question
form_class = QuestionForm form_class = QuestionForm
def get_form_kwargs(self):
kwargs = super(QuestionUpdate, self).get_form_kwargs()
kwargs.update({"user": self.request.user})
return kwargs
def get_context_data(self, **kwargs):
context = super(QuestionUpdate, self).get_context_data(**kwargs)
return context
def form_valid(self, form): def form_valid(self, form):
self.object = form.save(commit=False) self.object = form.save(commit=False)
self.object.save() self.object.save()