diff --git a/anatomy/migrations/0035_exam_json_creation_time.py b/anatomy/migrations/0035_exam_json_creation_time.py new file mode 100644 index 00000000..2138b523 --- /dev/null +++ b/anatomy/migrations/0035_exam_json_creation_time.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.3 on 2021-03-09 15:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('anatomy', '0034_auto_20210215_1200'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='json_creation_time', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + ] diff --git a/generic/models.py b/generic/models.py index b812654c..95ffdb55 100644 --- a/generic/models.py +++ b/generic/models.py @@ -64,6 +64,8 @@ class ExamBase(models.Model): help_text="If the json cache needs updating", default=False ) + json_creation_time = models.DateTimeField(blank=True, default=None, null=True) + #time_limit = models.IntegerField( # help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", # default=2100, diff --git a/generic/views.py b/generic/views.py index c96c7dda..f39b216e 100644 --- a/generic/views.py +++ b/generic/views.py @@ -32,6 +32,10 @@ from anatomy.models import AnatomyQuestion as AnatomyQuestion from anatomy.models import Exam as AnatomyExam from django.db.models import Case, When +from django.conf import settings + +from datetime import datetime +import os # Create your views here. @@ -177,6 +181,8 @@ class ExamViews(View, LoginRequiredMixin): exam.recreate_json = True exam.save() + exam.get_exam_json() + return redirect("{}:exam_overview".format(self.app_name), pk=pk) @method_decorator(login_required) @@ -315,13 +321,25 @@ class ExamViews(View, LoginRequiredMixin): for exam in exams: if exam.active: - active_exams["exams"].append( - { + if exam.json_creation_time: + creation_time = exam.json_creation_time.isoformat() + else: + creation_time = "None" + + obj = { "name": exam.get_exam_name(), "url": request.build_absolute_uri(exam.get_json_url()), "type": self.question_type, + "eid": "{}/{}".format(self.question_type, exam.pk), + "json_creation_time": creation_time } - ) + + if self.question_type == "long": + h = {} + for question in exam.exam_questions.all(): + h[question.pk] = question.json_creation_time.isoformat() + obj["multi_question_json"] = h + active_exams["exams"].append( obj ) if json == False: return active_exams["exams"] @@ -356,24 +374,37 @@ class ExamViews(View, LoginRequiredMixin): if not exam.active: raise Http404("No available exam") - exam_json_cache = cache.get("{}_exam_json_{}".format(self.app_name, pk)) - if exam_json_cache is not None and not exam.recreate_json: - exam_json_cache["cached"] = True + #exam_json_cache = cache.get("{}_exam_json_{}".format(self.app_name, pk)) + + path= "{0}{1}/exam/{2}.json".format(settings.MEDIA_ROOT, self.app_name, pk) + url= "{0}{1}/exam/{2}.json".format(settings.MEDIA_URL, self.app_name, pk) + + + if os.path.isfile(path) and not exam.recreate_json: + #exam_json_cache["cached"] = True + return redirect(url) return JsonResponse(exam_json_cache) - exam_json = exam.get_exam_json() + time = datetime.now() + + with open(path, "w+") as f: + exam_json = exam.get_exam_json() + exam_json["generated"] = time.isoformat() + f.write(json.dumps(exam_json)) exam.recreate_json = False + + exam.json_creation_time = time exam.save() # We also try to clear the cache of any associated questions (longs) # see exam_question_json - n = exam.exam_questions.count() - question_keys = ["{}_exam_json_{}_{}".format(self.app_name, pk, i) for i in range(1, n)] - cache.delete_many(question_keys) + #n = exam.exam_questions.count() + #question_keys = ["{}_exam_json_{}_{}".format(self.app_name, pk, i) for i in range(1, n)] + #cache.delete_many(question_keys) - cache.set("{}_exam_json_{}".format(self.app_name, pk), exam_json, 3600) + #cache.set("{}_exam_json_{}".format(self.app_name, pk), exam_json, 3600) return JsonResponse(exam_json) @@ -384,6 +415,9 @@ class ExamViews(View, LoginRequiredMixin): if not exam.active: raise Http404("No available exam") + return redirect("{}:question_json".format(self.app_name), pk=sk) + redirect() + question_json_cache = cache.get("{}_question_json_{}".format(self.app_name, sk)) if question_json_cache is not None and not question.recreate_json: diff --git a/longs/migrations/0031_auto_20210309_1527.py b/longs/migrations/0031_auto_20210309_1527.py new file mode 100644 index 00000000..9542159f --- /dev/null +++ b/longs/migrations/0031_auto_20210309_1527.py @@ -0,0 +1,23 @@ +# Generated by Django 3.1.3 on 2021-03-09 15:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('longs', '0030_long_recreate_json'), + ] + + operations = [ + migrations.AddField( + model_name='exam', + name='json_creation_time', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + migrations.AddField( + model_name='long', + name='json_creation_time', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + ] diff --git a/longs/models.py b/longs/models.py index ed2b5872..394e18a9 100644 --- a/longs/models.py +++ b/longs/models.py @@ -1,3 +1,4 @@ +import json from django.db.models.fields.files import ImageField from django.db.models.fields.related import ForeignKey from django.db import models @@ -34,6 +35,7 @@ from easy_thumbnails.files import get_thumbnailer from easy_thumbnails.exceptions import InvalidImageFormatError import pydicom +import datetime @@ -118,6 +120,10 @@ class Long(models.Model): help_text="If the json cache needs updating", default=False ) + json_creation_time = models.DateTimeField(blank=True, default=None) + + #question_file = models.FileField(upload_to=question_file_directory_path, blank=True, null=True) + def get_absolute_url(self): return reverse("longs:question_detail", kwargs={"pk": self.pk}) @@ -164,35 +170,64 @@ class Long(models.Model): return [ans for ans in answers if not ans.is_marked()] def get_json(self, question_id): + # self == q? q = get_object_or_404(Long, pk=question_id) #exam_order.append(q.id) + path= "{0}longs/questions/{1}.json".format(settings.MEDIA_ROOT, question_id) + url= "{0}longs/questions/{1}.json".format(settings.MEDIA_URL, question_id) - # Loop through longimage associations - images = [] - image_titles = [] - for series in q.series.all(): - #image_array = [] - #for i in series.images.all(): - # image_array.append(image_as_base64(i.image)) - # #image_array.append(i.image.url) - image_array = [image_as_base64(i.image) for i in series.images.all()] - images.append(image_array) - image_titles.append(series.get_examination()) + timestamp = datetime.datetime.now() + with open(path, "w+") as f: - - - exam_question = { - "title": q.history, - "images": images, - "image_titles": image_titles, - #"feedback_image": [], - #"annotations": [str(q.image_annotations)], + # We manually create the json for long questions to reducem memroy usade + f.write("""{{ + "title": "{}", "type": "long", - "cached": False, - } + "generated": "{}", + """.format(q.history, timestamp.isoformat()) + ) - return exam_question + + f.write('"images" : [') + #images = [] + image_titles = [] + + question_series = q.series.all() + # Loop through longimage associations + for i, series in enumerate(question_series): + #image_array = [] + #for i in series.images.all(): + # image_array.append(image_as_base64(i.image)) + # #image_array.append(i.image.url) + + # We are still limited by the size of a series (although this should not be too big or computers will crash...) + image_array = [image_as_base64(i.image) for i in series.images.all()] + #image_array = [i.image.url for i in series.images.all()] + f.write(json.dumps(image_array)) + #images.append(url) + if i != len(question_series) - 1: + f.write(",") + image_titles.append(series.get_examination()) + f.write("],") + + f.write('"image_titles" : {} }}'.format(json.dumps(image_titles))) + + + self.json_creation_time = timestamp + self.save() + + #exam_question = { + # "title": q.history, + # "images": images, + # "image_titles": image_titles, + # #"feedback_image": [], + # #"annotations": [str(q.image_annotations)], + # "type": "long", + # "cached": False, + #} + + return url @@ -482,6 +517,7 @@ class Exam(ExamBase): #"feedback_image": [], #"annotations": [str(q.image_annotations)], "type": "long", + "images_json": True, } return exam_question @@ -498,7 +534,7 @@ class Exam(ExamBase): for q in questions: exam_order.append(q.id) - exam_questions[q.id] = n + exam_questions[q.id] = q.json_creation_time.isoformat() continue @@ -538,7 +574,7 @@ class Exam(ExamBase): "exam_mode": True, "exam_order": exam_order, "questions": exam_questions, - "question_requests": True, + "question_requests": exam_questions, } diff --git a/longs/templates/longs/long_display_block.html b/longs/templates/longs/long_display_block.html index b486ac91..49771d4b 100755 --- a/longs/templates/longs/long_display_block.html +++ b/longs/templates/longs/long_display_block.html @@ -53,5 +53,8 @@ +