From 1a4d770a93ae82ac501f80a54f8aeafcd63df596 Mon Sep 17 00:00:00 2001 From: Ross Date: Tue, 29 Mar 2022 22:04:03 +0100 Subject: [PATCH] . --- atlas/forms.py | 73 +++++++- .../migrations/0028_casecollection_author.py | 20 +++ .../0029_casecollection_show_report.py | 18 ++ atlas/models.py | 8 + atlas/templates/atlas/base.html | 3 +- .../templates/atlas/casecollection_form.html | 54 ++++++ .../templates/atlas/collection_case_view.html | 10 ++ .../atlas/collection_detail_view.html | 5 + atlas/templates/atlas/series_viewer.html | 1 + atlas/urls.py | 11 +- atlas/views.py | 160 +++++++++++++++++- 11 files changed, 341 insertions(+), 22 deletions(-) create mode 100644 atlas/migrations/0028_casecollection_author.py create mode 100644 atlas/migrations/0029_casecollection_show_report.py create mode 100755 atlas/templates/atlas/casecollection_form.html diff --git a/atlas/forms.py b/atlas/forms.py index 0f127ac1..19c83027 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -13,6 +13,7 @@ from django.forms import inlineformset_factory from atlas.models import ( Case, + CaseCollection, Differential, Finding, Series, @@ -50,6 +51,26 @@ class ConditionForm(ModelForm): ), } +class CaseCollectionForm(ModelForm): + class Meta: + model = CaseCollection + exclude = ["cases", "author"] + + 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 + if kwargs.get("instance"): + # We get the 'initial' keyword argument or initialize it + # as a dict if it didn't exist. + initial = kwargs.setdefault("initial", {}) + # The widget for a ModelMultipleChoiceField expects + # a list of primary key for the selected data. + # initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()] + + ModelForm.__init__(self, *args, **kwargs) + + super(CaseCollectionForm, self).__init__(*args, **kwargs) class FindingForm(ModelForm): class Meta: @@ -153,7 +174,7 @@ class SeriesForm(ModelForm): else: case_queryset = Case.objects.filter( author__id=self.user.id - ) #| Case.objects.filter(open_access=True) + ) # | Case.objects.filter(open_access=True) self.fields["case"] = ModelMultipleChoiceField( required=False, @@ -226,7 +247,6 @@ class CaseForm(ModelForm): ModelForm.__init__(self, *args, **kwargs) super(CaseForm, self).__init__(*args, **kwargs) - print(1) # self.fields["series"].queryset = @@ -313,25 +333,60 @@ CaseDifferentialFormSet = inlineformset_factory( }, ) + class BaseSeriesFormSet(BaseInlineFormSet): - def __init__(self, *args, **kwargs): - super(BaseSeriesFormSet, self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): - self.queryset = Series.case.through.objects.filter(series__author__id=99) + super(BaseSeriesFormSet, self).__init__(*args, **kwargs) - #for form in self.forms: - # form.fields['series'].queryset = series_queryset + self.queryset = Series.case.through.objects.filter(series__author__id=99) + + # for form in self.forms: + # form.fields['series'].queryset = series_queryset + + +class CaseSeriesForm(ModelForm): + def __init__(self, *args, user, **kwargs): + super(CaseSeriesForm, self).__init__(*args, **kwargs) + + self.fields["series"] = ModelChoiceField( + required=False, + queryset=Series.objects.filter(author__id=user.id), + # widget=Select(verbose_name="Series", is_stacked=False), + ) + +class CaseCollectionCaseForm(ModelForm): + def __init__(self, *args, user, **kwargs): + super(CaseCollectionCaseForm, self).__init__(*args, **kwargs) + + self.fields["case"] = ModelChoiceField( + required=False, + queryset=Case.objects.filter(author__id=user.id), + # widget=Select(verbose_name="Series", is_stacked=False), + ) SeriesFormSet = inlineformset_factory( Case, Series.case.through, - formset=BaseSeriesFormSet, + form=CaseSeriesForm, + # formset=BaseSeriesFormSet, exclude=[], can_delete=True, - extra=1, + extra=0, max_num=10, ) +CaseCollectionCaseFormSet = inlineformset_factory( + CaseCollection, + Case.casecollection_set.through, + form=CaseCollectionCaseForm, + # formset=BaseSeriesFormSet, + exclude=[], + can_delete=True, + extra=0, + max_num=50, +) + SeriesImageFormSet = inlineformset_factory( Series, diff --git a/atlas/migrations/0028_casecollection_author.py b/atlas/migrations/0028_casecollection_author.py new file mode 100644 index 00000000..1405097e --- /dev/null +++ b/atlas/migrations/0028_casecollection_author.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.10 on 2022-03-29 20:53 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('atlas', '0027_auto_20220325_2138'), + ] + + operations = [ + migrations.AddField( + model_name='casecollection', + name='author', + field=models.ManyToManyField(blank=True, help_text='Author of the collection', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/atlas/migrations/0029_casecollection_show_report.py b/atlas/migrations/0029_casecollection_show_report.py new file mode 100644 index 00000000..3c716f14 --- /dev/null +++ b/atlas/migrations/0029_casecollection_show_report.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.10 on 2022-03-29 20:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('atlas', '0028_casecollection_author'), + ] + + operations = [ + migrations.AddField( + model_name='casecollection', + name='show_report', + field=models.BooleanField(default=False, help_text='Show the case report'), + ), + ] diff --git a/atlas/models.py b/atlas/models.py index f4e12a21..9caf3de4 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -572,6 +572,14 @@ class CaseCollection(models.Model): show_title = models.BooleanField(default=False, help_text="Show the title of the cases") show_description = models.BooleanField(default=False, help_text="Show the description of the cases") show_discussion = models.BooleanField(default=False, help_text="Show the case discussion") + show_report = models.BooleanField(default=False, help_text="Show the case report") + + author = models.ManyToManyField( + settings.AUTH_USER_MODEL, + blank=True, + help_text="Author of the collection", + #related_name="atlas_authored_cases", + ) def get_absolute_url(self): return reverse("atlas:collection_detail_view", kwargs={"pk": self.pk}) diff --git a/atlas/templates/atlas/base.html b/atlas/templates/atlas/base.html index 9167abee..a2f7d33e 100755 --- a/atlas/templates/atlas/base.html +++ b/atlas/templates/atlas/base.html @@ -19,8 +19,9 @@ Atlas: {% if request.user.is_authenticated %} Cases / Series / +Collections / Categories / -Create Case / +Create Case / Create Series {% endif %} {% comment %}
diff --git a/atlas/templates/atlas/casecollection_form.html b/atlas/templates/atlas/casecollection_form.html new file mode 100755 index 00000000..08432abd --- /dev/null +++ b/atlas/templates/atlas/casecollection_form.html @@ -0,0 +1,54 @@ +{% extends "atlas/base.html" %} + + +{% block css %} +{% endblock %} +{% block js %} + +{{form.media}} + + + +{% endblock %} +{% block content %} +

Create Collection

+Use this form to create a collection of cases +
+ {% csrf_token %} + + + {{ form.as_table }} +
+

Cases:

+ Add cases here. These can only be added once created (they can also be added to cases on creation). + +
+ {% for form in case_formset %} +
    + {{form.non_field_errors}} + {{form.errors}} + {{ form.as_ul }} +
+ {% endfor %} +
+ {{ case_formset.management_form }} + +
+ +{% endblock %} \ No newline at end of file diff --git a/atlas/templates/atlas/collection_case_view.html b/atlas/templates/atlas/collection_case_view.html index f623e033..50c2da29 100644 --- a/atlas/templates/atlas/collection_case_view.html +++ b/atlas/templates/atlas/collection_case_view.html @@ -43,6 +43,16 @@ {% endif %} +{% if collection.show_report and case.report%} +
+ + Report: + +
+ {{case.report}} +
+
+{% endif %}
{% if previous %} diff --git a/atlas/templates/atlas/collection_detail_view.html b/atlas/templates/atlas/collection_detail_view.html index 0b9f37a9..37d8f668 100644 --- a/atlas/templates/atlas/collection_detail_view.html +++ b/atlas/templates/atlas/collection_detail_view.html @@ -1,6 +1,11 @@ {% extends 'atlas/base.html' %} {% block content %} +{% if request.user.is_authenticated %} +
+ Edit +
+{% endif %}

{{collection.name}}
    {% for case in collection.cases.all %} diff --git a/atlas/templates/atlas/series_viewer.html b/atlas/templates/atlas/series_viewer.html index 0a50cb3f..3510e47d 100755 --- a/atlas/templates/atlas/series_viewer.html +++ b/atlas/templates/atlas/series_viewer.html @@ -1,4 +1,5 @@
    {{ series.modality}}, {{ series.examination }}, {{ series.plane }}, {{ series.contrast }}
    +
    Description: {{series.description}}
    {% if series.case %} Associated case: diff --git a/atlas/urls.py b/atlas/urls.py index b7c6ba4f..15ce88bb 100755 --- a/atlas/urls.py +++ b/atlas/urls.py @@ -1,4 +1,6 @@ from django.urls import path, include +from django.views.generic import RedirectView + from atlas.models import Condition, Finding, Presentation, Structure from . import views @@ -7,12 +9,15 @@ app_name = "atlas" urlpatterns = [ path("", views.CaseView.as_view(), name="index"), + path("create/", RedirectView.as_view(pattern_name='atlas:case_create', permanent=False), name="create"), path("author//", views.author_detail, name="author_detail"), path("author/", views.author_list, name="author_list"), path("case/", views.CaseView.as_view(), name="case_view"), path("collection/", views.collection_index_view, name="collection_index_view"), - path("collections/", views.collection_detail_view, name="collection_detail_view"), - path("collections//", views.collection_case_view, name="collection_case_view"), + path("collection/create", views.CaseCollectionCreate.as_view(), name="collection_create"), + path("collection//update", views.CaseCollectionUpdate.as_view(), name="collection_update"), + path("collection/", views.collection_detail_view, name="collection_detail_view"), + path("collection//", views.collection_case_view, name="collection_case_view"), path("condition/", views.ConditionView.as_view(), name="condition_view"), path("categories/", views.categories_list, name="categories_list"), path("condition/", views.condition_detail, name="condition_detail"), @@ -97,7 +102,7 @@ urlpatterns = [ # path("all_questions/", views.all_questions, name="all_questions"), path("case//scrap", views.atlas_scrap, name="case_scrap"), path("case//delete", views.CaseDelete.as_view(), name="case_delete"), - path("case/create/", views.AtlasCreate.as_view(), name="create"), + path("case/create/", views.AtlasCreate.as_view(), name="case_create"), path("series/create", views.SeriesCreate.as_view(), name="series_create"), path( "series//create", diff --git a/atlas/views.py b/atlas/views.py index d4a196e6..d2f3829a 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -27,6 +27,8 @@ from django.http import Http404, JsonResponse from django.http import HttpResponseRedirect, HttpResponse from .forms import ( + CaseCollectionCaseFormSet, + CaseCollectionForm, CaseForm, ConditionForm, FindingForm, @@ -349,6 +351,60 @@ def case_clone(request, pk): return render(request, "atlas/case_form.html", context) +class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView): + model = CaseCollection + form_class = CaseCollectionForm + + def get_initial(self): + # print(self.request) + if "pk" in self.kwargs: + initial = super(CaseCollectionCreate, self).get_initial() + # case = get_object_or_404(Case, pk=self.kwargs["pk"]) + + # initial["case"] = case.id + + return initial + + def get_form_kwargs(self): + kwargs = super(CaseCollectionCreate, self).get_form_kwargs() + kwargs.update({"user": self.request.user}) + return kwargs + + def get_context_data(self, **kwargs): + context = super(CaseCollectionCreate, self).get_context_data(**kwargs) + + if self.request.POST: + context["case_formset"] = CaseCollectionCaseFormSet( + self.request.POST, + self.request.FILES, + form_kwargs={"user": self.request.user}, + ) + context["case_formset"].full_clean() + else: + context["case_formset"] = CaseCollectionCaseFormSet( + form_kwargs={"user": self.request.user} + ) + return context + + def form_valid(self, form): + + self.object = form.save(commit=False) + self.object.save() + + form.instance.author.add(self.request.user.id) + + context = self.get_context_data(form=form) + case_formset = context["case_formset"] + if case_formset.is_valid(): + response = super().form_valid(form) + case_formset.instance = self.object + case_formset.save() + return response + + else: + return super().form_invalid(form) + + class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView): model = Series form_class = SeriesForm @@ -399,6 +455,67 @@ class SeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView): return super().form_invalid(form) +class CaseCollectionUpdate(RevisionMixin, LoginRequiredMixin, UpdateView): + model = CaseCollection + form_class = CaseCollectionForm + + # fields = '__all__' + # #fields = [ 'condition' ] + # #initial = {'date_of_death': '05/01/2018'} + # exclude = [ 'created_date', 'published_date' ] + + def get_form_kwargs(self): + kwargs = super(CaseCollectionUpdate, self).get_form_kwargs() + kwargs.update({"user": self.request.user}) + return kwargs + + def get_context_data(self, **kwargs): + context = super(CaseCollectionUpdate, self).get_context_data(**kwargs) + if self.request.POST: + context["case_formset"] = CaseCollectionCaseFormSet( + self.request.POST, + self.request.FILES, + instance=self.object, + form_kwargs={"user": self.request.user}, + ) + context["case_formset"].full_clean() + else: + context["case_formset"] = CaseCollectionCaseFormSet( + instance=self.object, form_kwargs={"user": self.request.user} + ) + return context + + def form_valid(self, form): + # save exam orders (there must be a better way to do this) + # exam_orders = {} + # for exam in self.object.exams.all(): + # exam_orders[exam] = list(exam.exam_questions.all()) + + self.object = form.save(commit=False) + self.object.save() + + form.instance.author.add(self.request.user.id) + + context = self.get_context_data(form=form) + case_formset = context["case_formset"] + # logger.debug(formset.is_valid()) + if case_formset.is_valid(): + response = super().form_valid(form) + case_formset.instance = self.object + case_formset.save() + + # restore exam orders + # for exam in self.object.exams.all(): + # if exam in exam_orders and self.object in exam_orders[exam]: + # print(exam_orders[exam]) + # exam.exam_questions.set(exam_orders[exam]) + # exam.save() + + return response + else: + return super().form_invalid(form) + + class SeriesUpdate( RevisionMixin, LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView ): @@ -494,7 +611,9 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context = super(AtlasCreateBase, self).get_context_data(**kwargs) if self.request.POST: context["series_formset"] = SeriesFormSet( - self.request.POST, self.request.FILES, queryset=Series.objects.filter(author__id=self.request.user.id) + self.request.POST, + self.request.FILES, + form_kwargs={"user": self.request.user}, ) context["casedifferential_formset"] = CaseDifferentialFormSet( self.request.POST, self.request.FILES @@ -502,8 +621,10 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context["series_formset"].full_clean() context["casedifferential_formset"].full_clean() else: - #context["series_formset"] = SeriesFormSet(instance=Case.objects.filter(author__id=self.request.user.id), queryset=Series.objects.filter(author__id=self.request.user.id)) - context["series_formset"] = SeriesFormSet() + # context["series_formset"] = SeriesFormSet(instance=Case.objects.filter(author__id=self.request.user.id), queryset=Series.objects.filter(author__id=self.request.user.id)) + context["series_formset"] = SeriesFormSet( + form_kwargs={"user": self.request.user} + ) context["casedifferential_formset"] = CaseDifferentialFormSet() return context @@ -569,7 +690,10 @@ class AtlasUpdate( context = super(AtlasUpdate, self).get_context_data(**kwargs) if self.request.POST: context["series_formset"] = SeriesFormSet( - self.request.POST, self.request.FILES, instance=self.object, queryset=Series.objects.filter(author__id=self.request.user.id) + self.request.POST, + self.request.FILES, + instance=self.object, + form_kwargs={"user": self.request.user}, ) context["casedifferential_formset"] = CaseDifferentialFormSet( self.request.POST, self.request.FILES, instance=self.object @@ -577,7 +701,9 @@ class AtlasUpdate( context["series_formset"].full_clean() context["casedifferential_formset"].full_clean() else: - context["series_formset"] = SeriesFormSet(instance=self.object, queryset=Series.objects.filter(author__id=self.request.user.id)) + context["series_formset"] = SeriesFormSet( + instance=self.object, form_kwargs={"user": self.request.user} + ) context["casedifferential_formset"] = CaseDifferentialFormSet( instance=self.object ) @@ -908,12 +1034,18 @@ def categories_list(request): def collection_index_view(request): collections = CaseCollection.objects.all() - return render(request, "atlas/collection_index_view.html", {"collections": collections}) + return render( + request, "atlas/collection_index_view.html", {"collections": collections} + ) + def collection_detail_view(request, pk): collection = get_object_or_404(CaseCollection, pk=pk) - return render(request, "atlas/collection_detail_view.html", {"collection": collection}) + return render( + request, "atlas/collection_detail_view.html", {"collection": collection} + ) + def collection_case_view(request, pk, case_number): collection = get_object_or_404(CaseCollection, pk=pk) @@ -926,5 +1058,15 @@ def collection_case_view(request, pk, case_number): previous = case_number > 0 next = case_number < (len(cases) - 1) - - return render(request, "atlas/collection_case_view.html", {"collection": collection, "case": case, "series_list": series_list, "case_number": case_number, "previous": previous, "next": next}) \ No newline at end of file + return render( + request, + "atlas/collection_case_view.html", + { + "collection": collection, + "case": case, + "series_list": series_list, + "case_number": case_number, + "previous": previous, + "next": next, + }, + )