From e0b73c70f516dae5eff96f202af2ba36ca0c87e5 Mon Sep 17 00:00:00 2001 From: Ross Date: Sat, 6 Feb 2021 21:48:04 +0000 Subject: [PATCH] . --- anatomy/static/css/anatomy.css | 2 +- anatomy/static/js/anatomy.js | 2 +- generic/models.py | 44 +++++++++ longs/migrations/0011_auto_20210206_1531.py | 19 ++++ longs/migrations/0012_auto_20210206_1541.py | 24 +++++ longs/migrations/0013_auto_20210206_2147.py | 18 ++++ longs/models.py | 89 +++++++++++-------- longs/tables.py | 19 ++-- longs/templates/longs/exam_overview.html | 21 +++-- longs/templates/longs/long_series_viewer.html | 6 ++ longs/templates/longs/view.html | 10 +-- longs/views.py | 2 +- 12 files changed, 194 insertions(+), 62 deletions(-) create mode 100644 longs/migrations/0011_auto_20210206_1531.py create mode 100644 longs/migrations/0012_auto_20210206_1541.py create mode 100644 longs/migrations/0013_auto_20210206_2147.py diff --git a/anatomy/static/css/anatomy.css b/anatomy/static/css/anatomy.css index f16decec..5caa8433 100644 --- a/anatomy/static/css/anatomy.css +++ b/anatomy/static/css/anatomy.css @@ -447,6 +447,6 @@ td.user-answer-score-2::after { display: block; } -.multi-image-block { +.multi-image-block, .series-block { display: inline-flex; } \ No newline at end of file diff --git a/anatomy/static/js/anatomy.js b/anatomy/static/js/anatomy.js index 2bdeca31..278fdd79 100644 --- a/anatomy/static/js/anatomy.js +++ b/anatomy/static/js/anatomy.js @@ -365,7 +365,7 @@ function keyDownHandler(e) { function create_popup_window(url, title) { - newwindow=window.open(url,title,'height=600,width=500'); + newwindow=window.open(url,title,'height=800,width=600'); if (window.focus) {newwindow.focus()} return false; } diff --git a/generic/models.py b/generic/models.py index 7a23b1f6..51ded685 100644 --- a/generic/models.py +++ b/generic/models.py @@ -1,8 +1,12 @@ from django.db import models +from django.urls import reverse + import tagulous import tagulous.models +from sortedm2m.fields import SortedManyToManyField + class Examination(models.Model): examination = models.CharField(max_length=200) @@ -25,3 +29,43 @@ class Condition(tagulous.models.TagModel): class Sign(tagulous.models.TagModel): pass + + +class ExamBase(models.Model): + name = models.CharField(max_length=200) + #exam_questions = SortedManyToManyField(Long, related_name="exams", blank="true") + + active = models.BooleanField( + help_text="If an exam should be available", default=True + ) + + publish_results = models.BooleanField( + help_text="If an exams results should be available", default=True + ) + + recreate_json = models.BooleanField( + help_text="If the json cache needs updating", default=False + ) + + #time_limit = models.IntegerField( + # help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", + # default=2100, + #) + + class Meta: + abstract = True + + def __str__(self): + return self.name + + def get_absolute_url(self): + return reverse("{}:exam_overview".format(self.app_name), kwargs={"pk": self.pk}) + + def get_exam_name(self): + return self.name + + def get_json_url(self): + return reverse("{}:exam_json".format(self.app_name), args=(self.pk,)) + + def get_question_index(self, question): + return list(self.exam_questions.all()).index(question) \ No newline at end of file diff --git a/longs/migrations/0011_auto_20210206_1531.py b/longs/migrations/0011_auto_20210206_1531.py new file mode 100644 index 00000000..6fab140c --- /dev/null +++ b/longs/migrations/0011_auto_20210206_1531.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.3 on 2021-02-06 15:31 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0010_auto_20210206_0905'), + ] + + operations = [ + migrations.AlterField( + model_name='longseries', + name='long', + field=models.ForeignKey(blank=True, help_text='The question this series should be associated with', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='series', to='longs.long'), + ), + ] diff --git a/longs/migrations/0012_auto_20210206_1541.py b/longs/migrations/0012_auto_20210206_1541.py new file mode 100644 index 00000000..441a0874 --- /dev/null +++ b/longs/migrations/0012_auto_20210206_1541.py @@ -0,0 +1,24 @@ +# Generated by Django 3.1.3 on 2021-02-06 15:41 + +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('longs', '0011_auto_20210206_1531'), + ] + + operations = [ + migrations.RemoveField( + model_name='longseries', + name='author', + ), + migrations.AddField( + model_name='longseries', + name='author', + field=models.ManyToManyField(blank=True, related_name='long_series', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/longs/migrations/0013_auto_20210206_2147.py b/longs/migrations/0013_auto_20210206_2147.py new file mode 100644 index 00000000..da99394d --- /dev/null +++ b/longs/migrations/0013_auto_20210206_2147.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.3 on 2021-02-06 21:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0012_auto_20210206_1541'), + ] + + operations = [ + migrations.AlterField( + model_name='exam', + name='time_limit', + field=models.IntegerField(default=4500, help_text='Exam time limit (in seconds). Default is 4500 secondse (75 minutes)'), + ), + ] diff --git a/longs/models.py b/longs/models.py index f9114214..7c504ce7 100644 --- a/longs/models.py +++ b/longs/models.py @@ -21,7 +21,7 @@ import string from anatomy.models import Modality -from generic.models import Examination, Condition, Sign +from generic.models import Examination, Condition, Sign, ExamBase # from generic.models import Examination, Site, Condition, Sign @@ -164,23 +164,26 @@ class LongSeries(models.Model): related_name="series", on_delete=models.SET_NULL, null=True, + blank=True, ) description = models.TextField( blank=True, help_text="Description of stack, for admin organisation, will not be visible when taking", ) - author = models.ForeignKey( + author = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, - null=True, related_name="long_series", - on_delete=models.CASCADE, ) def __str__(self): + if self.long: + long_id = self.long.pk + else: + long_id = "None" return "{} : {} [{}]".format( - self.get_examination(), self.description, self.long.pk + self.get_examination(), self.description, long_id ) def get_author_objects(self): @@ -223,9 +226,9 @@ class LongSeries(models.Model): img = findMiddle(images).image try: thumbnailer = get_thumbnailer(img) + thumbnail = thumbnailer["exam-list"] except InvalidImageFormatError: - return format_html('Invalid image url', image_object) - thumbnail = thumbnailer["exam-list"] + return format_html('Invalid image url', img), len(images) return format_html('', thumbnail), len(images) def get_block(self): @@ -290,43 +293,55 @@ class LongCreationDefault(models.Model): return reverse("longs:long_create") -class Exam(models.Model): - name = models.CharField(max_length=200) +class Exam(ExamBase): + app_name = "longs" + exam_questions = SortedManyToManyField(Long, related_name="exams", blank="true") - active = models.BooleanField( - help_text="If an exam should be available", default=True - ) - - publish_results = models.BooleanField( - help_text="If an exams results should be available", default=True - ) - - recreate_json = models.BooleanField( - help_text="If the json cache needs updating", default=False - ) - time_limit = models.IntegerField( - help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", - default=2100, + help_text="Exam time limit (in seconds). Default is 4500 secondse (75 minutes)", + default=4500, ) - def __str__(self): - return self.name - - def get_absolute_url(self): - return reverse("longs:exam_overview", kwargs={"pk": self.pk}) - - def get_exam_name(self): - return self.name - - def get_json_url(self): - return reverse("longs:exam_json", args=(self.pk,)) - - def get_question_index(self, question): - return list(self.exam_questions.all()).index(question) +#class Exam(models.Model): +# name = models.CharField(max_length=200) +# exam_questions = SortedManyToManyField(Long, related_name="exams", blank="true") +# +# active = models.BooleanField( +# help_text="If an exam should be available", default=True +# ) +# +# publish_results = models.BooleanField( +# help_text="If an exams results should be available", default=True +# ) +# +# recreate_json = models.BooleanField( +# help_text="If the json cache needs updating", default=False +# ) +# +# time_limit = models.IntegerField( +# help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", +# default=2100, +# ) +# +# def __str__(self): +# return self.name +# +# def get_absolute_url(self): +# return reverse("longs:exam_overview", kwargs={"pk": self.pk}) +# +# def get_exam_name(self): +# return self.name +# +# def get_json_url(self): +# return reverse("longs:exam_json", args=(self.pk,)) +# +# def get_question_index(self, question): +# return list(self.exam_questions.all()).index(question) +# +# class CidUserAnswer(models.Model): """User answers by candidate""" diff --git a/longs/tables.py b/longs/tables.py index 278bba6c..64c5a07a 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 +from .models import Long, LongSeries from django.utils.html import format_html @@ -67,6 +67,10 @@ class PopupLinkColumn(tables.Column): return obj.get_thumbnail()[0] +def create_link(test): + print(test) + return "Hello" + class LongSeriesTable(tables.Table): edit = tables.LinkColumn( "longs:long_series_update", text="Edit", args=[A("pk")], orderable=False @@ -74,13 +78,16 @@ class LongSeriesTable(tables.Table): view = tables.LinkColumn( "longs:long_series_detail", text="View", args=[A("pk")], orderable=False ) - popup = PopupLinkColumn( - "View in popup", orderable=False - ) + popup = tables.Column(empty_values=(), orderable=False) + images = LongSeriesImageColumn("Images", orderable=False) class Meta: - model = Long + model = LongSeries template_name = "django_tables2/bootstrap4.html" fields = ("modality", "examination", "long", "description", "author") - sequence = ("view", "popup", "images") \ No newline at end of file + sequence = ("view", "popup", "images") + + def render_popup(self, value, record): + print(self) + return format_html("""Popup""", record.pk) \ No newline at end of file diff --git a/longs/templates/longs/exam_overview.html b/longs/templates/longs/exam_overview.html index 3bbc7b6e..167b3ccc 100644 --- a/longs/templates/longs/exam_overview.html +++ b/longs/templates/longs/exam_overview.html @@ -20,18 +20,17 @@ {% for question in questions.all %}
  • - {% for image in question.GetImages %} - thumbail + History: {{ question.history}} +
    + {% for series in question.series.all %} +
    + Series {{forloop.counter }}:
    + {{series.get_block}} +
    {% endfor %} - {% if not question.normal %} - Abnormality: {{ question.get_abnormalities }} Region: {{ question.get_regions }} -
    - {{ question.GetPrimaryAnswer }} - {% else %} - Normal - {% endif %} -
    - Examination: {{ question.get_examinations }}, View, Mark +
    + Author(s): {{question.get_authors}} +
  • {% endfor %} diff --git a/longs/templates/longs/long_series_viewer.html b/longs/templates/longs/long_series_viewer.html index 78bfa7dc..a1308d5f 100755 --- a/longs/templates/longs/long_series_viewer.html +++ b/longs/templates/longs/long_series_viewer.html @@ -1,6 +1,12 @@
    {{ series.modality}}, {{ series.examination }}
    +{% if series.long %} +Associated case: {{series.long}} +{% else %} +This series is not associated with any cases. +{% endif %} +
    Author: {{ series.get_author_display }}
    \ No newline at end of file diff --git a/longs/templates/longs/view.html b/longs/templates/longs/view.html index 208e20b5..98d5a11f 100755 --- a/longs/templates/longs/view.html +++ b/longs/templates/longs/view.html @@ -7,11 +7,11 @@ {% block content %}
    -

    Filter Longs

    -
    - {{ filter.form }} - -
    +

    Filter

    +
    + {{ filter.form }} + +
    {% render_table table %} diff --git a/longs/views.py b/longs/views.py index ceca3128..574138f4 100755 --- a/longs/views.py +++ b/longs/views.py @@ -62,7 +62,7 @@ logger = logging.getLogger(__name__) class AuthorOrCheckerRequiredMixin(object): def get_object(self, *args, **kwargs): obj = super(UpdateView, self).get_object(*args, **kwargs) - if self.request.user.groups.filter(name="long_checker").exists(): + if self.request.user.groups.filter(name="long_checker").exists() or self.request.user.is_superuser: return obj if self.request.user not in obj.get_author_objects(): raise PermissionDenied() # or Http404