From f13d1ba7e20f97f898b6f4d19deacd7180e08bd3 Mon Sep 17 00:00:00 2001 From: Ross Date: Thu, 4 Apr 2024 23:15:22 +0100 Subject: [PATCH] fix a number of issues and start adding resources --- atlas/forms.py | 41 +++++++++++++++++-- ...046_resource_caseresource_case_resource.py | 37 +++++++++++++++++ ...caseresource_pre_review_resource_author.py | 25 +++++++++++ atlas/models.py | 32 +++++++++++++++ atlas/tables.py | 3 +- atlas/templates/atlas/case_display_block.html | 1 + atlas/templates/atlas/case_form.html | 25 +++++++++++ atlas/views.py | 16 +++++++- 8 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 atlas/migrations/0046_resource_caseresource_case_resource.py create mode 100644 atlas/migrations/0047_caseresource_pre_review_resource_author.py diff --git a/atlas/forms.py b/atlas/forms.py index bdc6572e..bf431330 100755 --- a/atlas/forms.py +++ b/atlas/forms.py @@ -23,6 +23,7 @@ from atlas.models import ( CidReportAnswer, Differential, Finding, + Resource, SelfReview, Series, SeriesImage, @@ -74,7 +75,7 @@ class ConditionForm(ModelForm): class CaseCollectionForm(ModelForm): class Meta: model = CaseCollection - exclude = ["cases", "valid_cid_users"] + exclude = ["cases", "valid_cid_users", "author"] def __init__(self, *args, **kwargs): self.user = kwargs.pop( @@ -92,6 +93,18 @@ class CaseCollectionForm(ModelForm): super(CaseCollectionForm, self).__init__(*args, **kwargs) + def save(self, commit=True): + # Get the unsaved Case instance + instance = ModelForm.save(self, False) + + + # Do we need to save all changes now? + # if commit: + instance.save() + self.save_m2m() + + return instance + class FindingForm(ModelForm): class Meta: @@ -343,8 +356,6 @@ class CaseForm(ModelForm): instance = ModelForm.save(self, False) - - # Prepare a 'save_m2m' method for the form, old_save_m2m = self.save_m2m @@ -390,6 +401,21 @@ CaseDifferentialFormSet = inlineformset_factory( }, ) +class CaseResourceForm(ModelForm): + + def __init__(self, *args, user, **kwargs): + super(CaseResourceForm, self).__init__(*args, **kwargs) + + if not user.groups.filter(name="atlas_editor").exists(): + queryset = Resource.objects.filter(author__id=user.id) + else: + queryset = Resource.objects.all() + + self.fields["resource"] = ModelChoiceField( + required=False, + queryset=queryset, + # widget=Select(verbose_name="Series", is_stacked=False), + ) class CaseSeriesForm(ModelForm): @@ -446,6 +472,15 @@ CaseCollectionCaseFormSet = inlineformset_factory( max_num=50, ) +CaseResourceFormSet = inlineformset_factory( + Case, + Resource.case_set.through, + form=CaseResourceForm, + exclude=[], + can_delete=True, + extra=0, + max_num=10, +) SeriesImageFormSet = inlineformset_factory( Series, diff --git a/atlas/migrations/0046_resource_caseresource_case_resource.py b/atlas/migrations/0046_resource_caseresource_case_resource.py new file mode 100644 index 00000000..92008054 --- /dev/null +++ b/atlas/migrations/0046_resource_caseresource_case_resource.py @@ -0,0 +1,37 @@ +# Generated by Django 5.0.2 on 2024-04-04 19:24 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('atlas', '0045_casecollection_authors_only'), + ] + + operations = [ + migrations.CreateModel( + name='Resource', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255)), + ('description', models.TextField(blank=True, null=True)), + ('url', models.URLField(blank=True, null=True)), + ('file', models.FileField(blank=True, null=True, upload_to='atlas/resources/')), + ], + ), + migrations.CreateModel( + name='CaseResource', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('case', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='atlas.case')), + ('resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='atlas.resource')), + ], + ), + migrations.AddField( + model_name='case', + name='resource', + field=models.ManyToManyField(through='atlas.CaseResource', to='atlas.resource'), + ), + ] diff --git a/atlas/migrations/0047_caseresource_pre_review_resource_author.py b/atlas/migrations/0047_caseresource_pre_review_resource_author.py new file mode 100644 index 00000000..068cf7ec --- /dev/null +++ b/atlas/migrations/0047_caseresource_pre_review_resource_author.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.2 on 2024-04-04 22:07 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('atlas', '0046_resource_caseresource_case_resource'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='caseresource', + name='pre_review', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='resource', + name='author', + field=models.ManyToManyField(blank=True, help_text='Author of the resource', related_name='resources', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/atlas/models.py b/atlas/models.py index b9aa01ac..61e601b8 100644 --- a/atlas/models.py +++ b/atlas/models.py @@ -364,6 +364,8 @@ class Case(models.Model, AuthorMixin, QuestionMixin): blank=True, ) + resource = models.ManyToManyField("Resource", through="CaseResource") + def get_app_name(self): return "atlas" @@ -1142,3 +1144,33 @@ class UncategorisedDicom(models.Model): class DuplicateDicom(Exception): pass + +class Resource(models.Model, AuthorMixin): + name = models.CharField(max_length=255) + description = models.TextField(blank=True, null=True) + url = models.URLField(blank=True, null=True) + file = models.FileField(upload_to="atlas/resources/", blank=True, null=True) + author = models.ManyToManyField( + settings.AUTH_USER_MODEL, + blank=True, + help_text="Author of the resource", + related_name="resources", + ) + + def __str__(self) -> str: + return self.name + + def get_absolute_url(self): + return reverse("atlas:resource_detail", kwargs={"pk": self.pk}) + + def get_link(self): + return format_html("{}", self.get_absolute_url(), self.name) + +class CaseResource(models.Model): + resource = models.ForeignKey(Resource, on_delete=models.CASCADE) + case = models.ForeignKey(Case, on_delete=models.CASCADE) + + pre_review = models.BooleanField(default=False) + + def __str__(self) -> str: + return f"{self.resource} - {self.case}" \ No newline at end of file diff --git a/atlas/tables.py b/atlas/tables.py index 886fed87..8c4b36cb 100755 --- a/atlas/tables.py +++ b/atlas/tables.py @@ -5,6 +5,7 @@ from generic.tables import SeriesImageColumn from .models import ( Case, + CaseCollection, Condition, PathologicalProcess, Presentation, @@ -318,7 +319,7 @@ class CaseCollectionTable(tables.Table): selection = tables.CheckBoxColumn(accessor="pk", orderable=False) class Meta: - model = Case + model = CaseCollection template_name = "django_tables2/bootstrap4.html" fields = ( "name", diff --git a/atlas/templates/atlas/case_display_block.html b/atlas/templates/atlas/case_display_block.html index 08718652..a1928d54 100755 --- a/atlas/templates/atlas/case_display_block.html +++ b/atlas/templates/atlas/case_display_block.html @@ -1,5 +1,6 @@
View case in OHIF (new tab)
+
View case in OHIF
{{ case.created_date|date:"d/m/Y" }} diff --git a/atlas/templates/atlas/case_form.html b/atlas/templates/atlas/case_form.html index 3e3c81c3..f3e9d502 100755 --- a/atlas/templates/atlas/case_form.html +++ b/atlas/templates/atlas/case_form.html @@ -38,10 +38,16 @@ $('#casedifferential_formset').append($('#empty_casedifferential_form').html().replace(/__prefix__/g, form_idx)); $('#id_differentialcase-TOTAL_FORMS').val(parseInt(form_idx) + 1); } + function add_resource_input_form() { + var form_idx = $('#id_resourcecase-TOTAL_FORMS').val(); + $('#caseresource_formset').append($('#empty_caseresource_form').html().replace(/__prefix__/g, form_idx)); + $('#id_resourcecase-TOTAL_FORMS').val(parseInt(form_idx) + 1); + } $(document).ready(function () { $('#add_more_series').click(() => { add_series_input_form() }); $('#add_more_differential').click(() => { add_differential_input_form() }); + $('#add_more_resource').click(() => { add_resource_input_form() }); }) @@ -91,6 +97,20 @@ {% endfor %}
{{ casedifferential_formset.management_form }} +

Resource:

+ Add resource here. + +
+ {% for form in caseresource_formset %} +
    + {{form.non_field_errors}} + {{form.errors}} + {{ form.as_ul }} +
+ {% endfor %} +
+ {{ caseresource_formset.management_form }} +
+ {% endblock %} diff --git a/atlas/views.py b/atlas/views.py index 4fafb979..8d8efb3c 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -39,6 +39,7 @@ from .forms import ( CaseCollectionCaseFormSet, CaseCollectionForm, CaseForm, + CaseResourceFormSet, CidReportAnswerForm, CidReportAnswerMarkForm, ConditionAutocompleteForm, @@ -550,9 +551,9 @@ class CaseCollectionCreate(RevisionMixin, LoginRequiredMixin, CreateView): 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(): @@ -773,14 +774,22 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context["casedifferential_formset"] = CaseDifferentialFormSet( self.request.POST, self.request.FILES ) + context["caseresource_formset"] = CaseResourceFormSet( + self.request.POST, self.request.FILES, + form_kwargs={"user": self.request.user}, + ) context["series_formset"].full_clean() context["casedifferential_formset"].full_clean() + context["caseresource_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( form_kwargs={"user": self.request.user} ) context["casedifferential_formset"] = CaseDifferentialFormSet() + context["caseresource_formset"] = CaseResourceFormSet( + form_kwargs={"user": self.request.user} + ) return context def form_valid(self, form): @@ -795,12 +804,15 @@ class AtlasCreateBase(RevisionMixin, LoginRequiredMixin): context = self.get_context_data(form=form) series_formset = context["series_formset"] casedifferential_formset = context["casedifferential_formset"] - if series_formset.is_valid() and casedifferential_formset.is_valid(): + caseresource_formset = context["caseresource_formset"] + if series_formset.is_valid() and casedifferential_formset.is_valid() and caseresource_formset.is_valid(): response = super().form_valid(form) series_formset.instance = self.object series_formset.save() casedifferential_formset.instance = self.object casedifferential_formset.save() + caseresource_formset.instance = self.object + caseresource_formset.save() # If the normal submit button is pressed we save as normal if "submit" in self.request.POST: return response