repalce rapid - long

This commit is contained in:
Ross
2021-02-02 09:35:29 +00:00
parent 38134e5fbc
commit b681a27640
28 changed files with 276 additions and 276 deletions
+14 -14
View File
@@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from .models import Rapid, RapidImage, Examination, Site, Abnormality, Region, Note, RapidCreationDefault, Answer, Exam from .models import Long, LongImage, Examination, Site, Abnormality, Region, Note, LongCreationDefault, Answer, Exam
import tagulous.admin import tagulous.admin
@@ -15,29 +15,29 @@ admin.site.register(Exam)
admin.site.register(Abnormality) admin.site.register(Abnormality)
admin.site.register(Region) admin.site.register(Region)
admin.site.register(Note) admin.site.register(Note)
admin.site.register(RapidCreationDefault) admin.site.register(LongCreationDefault)
admin.site.register(Answer) admin.site.register(Answer)
class RapidAnswersInline(admin.TabularInline): class LongAnswersInline(admin.TabularInline):
model = Answer model = Answer
extra = 1 extra = 1
class RapidImageInline(admin.TabularInline): class LongImageInline(admin.TabularInline):
model = RapidImage model = LongImage
extra = 1 extra = 1
readonly_fields = [ readonly_fields = [
"image_tag", "image_tag",
] ]
class ExamInline(admin.TabularInline): class ExamInline(admin.TabularInline):
model = Rapid.exams.through model = Long.exams.through
extra = 1 extra = 1
class RapidAdminForm(ModelForm): class LongAdminForm(ModelForm):
class Meta: class Meta:
model = Rapid model = Long
fields = [ fields = [
"normal", "abnormality", "region", "laterality", "examination", "normal", "abnormality", "region", "laterality", "examination",
@@ -49,8 +49,8 @@ class RapidAdminForm(ModelForm):
} }
class RapidAdmin(VersionAdmin): class LongAdmin(VersionAdmin):
form = RapidAdminForm form = LongAdminForm
filter_horizontal = ( filter_horizontal = (
"abnormality", "abnormality",
@@ -62,12 +62,12 @@ class RapidAdmin(VersionAdmin):
view_on_site = True view_on_site = True
inlines = [ inlines = [
RapidImageInline, LongImageInline,
RapidAnswersInline, LongAnswersInline,
ExamInline, ExamInline,
] ]
admin.site.register(Rapid, RapidAdmin) admin.site.register(Long, LongAdmin)
#tagulous.admin.register(Rapid.condition) #tagulous.admin.register(Long.condition)
+2 -2
View File
@@ -1,5 +1,5 @@
from django.apps import AppConfig from django.apps import AppConfig
class RapidsConfig(AppConfig): class LongsConfig(AppConfig):
name = 'rapids' name = 'longs'
+4 -4
View File
@@ -1,10 +1,10 @@
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from .models import Rapid from .models import Long
def user_is_author_or_rapid_checker(function): def user_is_author_or_long_checker(function):
def wrap(request, *args, **kwargs): def wrap(request, *args, **kwargs):
rapid = Rapid.objects.get(pk=kwargs['pk']) long = Long.objects.get(pk=kwargs['pk'])
if request.user in rapid.author.all() or request.user.groups.filter(name='rapid_checker').exists(): if request.user in long.author.all() or request.user.groups.filter(name='long_checker').exists():
return function(request, *args, **kwargs) return function(request, *args, **kwargs)
else: else:
raise PermissionDenied raise PermissionDenied
+3 -3
View File
@@ -1,10 +1,10 @@
import django_filters import django_filters
from .models import Rapid from .models import Long
class RapidFilter(django_filters.FilterSet): class LongFilter(django_filters.FilterSet):
class Meta: class Meta:
model = Rapid model = Long
fields = ("normal", "abnormality", "region", "examination", fields = ("normal", "abnormality", "region", "examination",
"laterality", "site", "created_date", "author") "laterality", "site", "created_date", "author")
+16 -16
View File
@@ -8,13 +8,13 @@ from django.forms import (
) )
from django.forms import inlineformset_factory from django.forms import inlineformset_factory
from rapids.models import ( from longs.models import (
Abnormality, Abnormality,
Examination, Examination,
Note, Note,
Rapid, Long,
RapidCreationDefault, LongCreationDefault,
RapidImage, LongImage,
Region, Region,
Answer, Answer,
CidUserAnswer, CidUserAnswer,
@@ -25,13 +25,13 @@ from django.contrib.admin.widgets import FilteredSelectMultiple
from django.forms.widgets import RadioSelect, TextInput, Textarea from django.forms.widgets import RadioSelect, TextInput, Textarea
class RapidAnswerForm(ModelForm): class LongAnswerForm(ModelForm):
class Meta: class Meta:
model = CidUserAnswer model = CidUserAnswer
fields = ("answer",) fields = ("answer",)
class MarkRapidQuestionForm(Form): class MarkLongQuestionForm(Form):
# correct = forms.CharField(required=False) # correct = forms.CharField(required=False)
# half_correct = forms.CharField(required=False) # half_correct = forms.CharField(required=False)
# incorrect = forms.CharField(required=False) # incorrect = forms.CharField(required=False)
@@ -62,14 +62,14 @@ class AbnormalityForm(ModelForm):
fields = ["name"] fields = ["name"]
class RapidCreationDefaultForm(ModelForm): class LongCreationDefaultForm(ModelForm):
class Meta: class Meta:
model = RapidCreationDefault model = LongCreationDefault
fields = ["site"] fields = ["site"]
exclude = ["author"] exclude = ["author"]
class RapidForm(ModelForm): class LongForm(ModelForm):
class Media: class Media:
# Django also includes a few javascript files necessary # Django also includes a few javascript files necessary
# for the operation of this form element. You need to # for the operation of this form element. You need to
@@ -82,7 +82,7 @@ class RapidForm(ModelForm):
js = ["jsi18n.js", "tesseract.min.js"] js = ["jsi18n.js", "tesseract.min.js"]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(RapidForm, self).__init__(*args, **kwargs) super(LongForm, self).__init__(*args, **kwargs)
# self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100} # self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
# self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100} # self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
self.fields["abnormality"] = ModelMultipleChoiceField( self.fields["abnormality"] = ModelMultipleChoiceField(
@@ -103,11 +103,11 @@ class RapidForm(ModelForm):
) )
self.fields["laterality"] = ChoiceField( self.fields["laterality"] = ChoiceField(
choices=Rapid.LATERALITY_CHOICES, required=True, widget=RadioSelect() choices=Long.LATERALITY_CHOICES, required=True, widget=RadioSelect()
) )
class Meta: class Meta:
model = Rapid model = Long
# fields = ['due_back'] # fields = ['due_back']
# fields = '__all__' # fields = '__all__'
fields = [ fields = [
@@ -128,8 +128,8 @@ class RapidForm(ModelForm):
ImageFormSet = inlineformset_factory( ImageFormSet = inlineformset_factory(
Rapid, Long,
RapidImage, LongImage,
fields=["image", "feedback_image"], fields=["image", "feedback_image"],
exclude=[], exclude=[],
can_delete=True, can_delete=True,
@@ -139,7 +139,7 @@ ImageFormSet = inlineformset_factory(
) )
AnswerFormSet = inlineformset_factory( AnswerFormSet = inlineformset_factory(
Rapid, Long,
Answer, Answer,
fields=["answer", "status"], fields=["answer", "status"],
widgets={ widgets={
@@ -154,7 +154,7 @@ AnswerFormSet = inlineformset_factory(
) )
AnswerUpdateFormSet = inlineformset_factory( AnswerUpdateFormSet = inlineformset_factory(
Rapid, Long,
Answer, Answer,
fields=["answer", "status"], fields=["answer", "status"],
widgets={ widgets={
+24 -24
View File
@@ -19,9 +19,9 @@ import string
image_storage = FileSystemStorage( image_storage = FileSystemStorage(
# Physical file location ROOT # Physical file location ROOT
location=u"{0}/rapids/".format(settings.MEDIA_ROOT), location=u"{0}/longs/".format(settings.MEDIA_ROOT),
# Url for file # Url for file
base_url=u"{0}rapids/".format(settings.MEDIA_URL), base_url=u"{0}longs/".format(settings.MEDIA_URL),
) )
def image_directory_path(instance, filename): def image_directory_path(instance, filename):
@@ -81,7 +81,7 @@ class Sign(tagulous.models.TagModel):
class Answer(models.Model): class Answer(models.Model):
question = models.ForeignKey( question = models.ForeignKey(
"Rapid", related_name="answers", on_delete=models.CASCADE "Long", related_name="answers", on_delete=models.CASCADE
) )
answer = models.TextField(max_length=500) answer = models.TextField(max_length=500)
answer_compare = models.TextField(max_length=500) answer_compare = models.TextField(max_length=500)
@@ -113,7 +113,7 @@ class Answer(models.Model):
self.answer_compare = s self.answer_compare = s
class Rapid(models.Model): class Long(models.Model):
#author = models.ForeignKey('auth.User', on_delete=models.CASCADE) #author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
#image = models.ImageField() #image = models.ImageField()
question = models.TextField(null=True, blank=True) question = models.TextField(null=True, blank=True)
@@ -174,7 +174,7 @@ class Rapid(models.Model):
author = models.ManyToManyField(settings.AUTH_USER_MODEL, author = models.ManyToManyField(settings.AUTH_USER_MODEL,
blank=True, blank=True,
help_text='Author of question', help_text='Author of question',
related_name="rapid_authored_questions") related_name="long_authored_questions")
scrapped = models.BooleanField( scrapped = models.BooleanField(
default=False, default=False,
@@ -186,7 +186,7 @@ class Rapid(models.Model):
def get_absolute_url(self): def get_absolute_url(self):
return reverse('rapids:rapid_detail', kwargs={'pk': self.pk}) return reverse('longs:long_detail', kwargs={'pk': self.pk})
def get_authors(self): def get_authors(self):
"""Returns a comma seperated text list of authors""" """Returns a comma seperated text list of authors"""
@@ -295,8 +295,8 @@ class Rapid(models.Model):
#return self.GetImages() #return self.GetImages()
class RapidImage(models.Model): class LongImage(models.Model):
rapid = models.ForeignKey(Rapid, long = models.ForeignKey(Long,
related_name="images", related_name="images",
on_delete=models.CASCADE) on_delete=models.CASCADE)
image = models.ImageField(upload_to=image_directory_path, storage=image_storage) image = models.ImageField(upload_to=image_directory_path, storage=image_storage)
@@ -306,7 +306,7 @@ class RapidImage(models.Model):
def image_tag(self): def image_tag(self):
if self.image: if self.image:
return mark_safe( return mark_safe(
'<img src="{}" class="admin-rapid-image" /><span class="admin-rapid-image-info">Click and hold to zoom<span>' '<img src="{}" class="admin-long-image" /><span class="admin-long-image-info">Click and hold to zoom<span>'
.format(self.image.url)) .format(self.image.url))
else: else:
return "" return ""
@@ -315,46 +315,46 @@ class RapidImage(models.Model):
class Note(models.Model): class Note(models.Model):
rapid = models.ForeignKey(Rapid, long = models.ForeignKey(Long,
related_name="rapid_notes", related_name="long_notes",
on_delete=models.CASCADE, on_delete=models.CASCADE,
null=True) null=True)
#author = models.ForeignKey(User, #author = models.ForeignKey(User,
author = models.ForeignKey( settings.AUTH_USER_MODEL, author = models.ForeignKey( settings.AUTH_USER_MODEL,
related_name="rapid_notes", related_name="long_notes",
on_delete=models.CASCADE) on_delete=models.CASCADE)
note = models.TextField() note = models.TextField()
created_on = models.DateTimeField(auto_now_add=True) created_on = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self): def get_absolute_url(self):
self.pk = self.rapid_id self.pk = self.long_id
return reverse('rapids:rapid_detail', kwargs={'pk': self.pk}) return reverse('longs:long_detail', kwargs={'pk': self.pk})
def __str__(self): def __str__(self):
return "{} [{}] {}".format(self.rapid, self.author, self.created_on) return "{} [{}] {}".format(self.long, self.author, self.created_on)
class RapidCreationDefault(models.Model): class LongCreationDefault(models.Model):
#author = models.OneToOneField(User, #author = models.OneToOneField(User,
author = models.OneToOneField( author = models.OneToOneField(
settings.AUTH_USER_MODEL, settings.AUTH_USER_MODEL,
related_name="rapid_default", related_name="long_default",
on_delete=models.CASCADE) on_delete=models.CASCADE)
site = models.ManyToManyField( site = models.ManyToManyField(
Site, Site,
blank=True, blank=True,
default=1, default=1,
help_text="Default site to use when creating a new rapid") help_text="Default site to use when creating a new long")
def get_absolute_url(self): def get_absolute_url(self):
return reverse('rapids:rapid_create') return reverse('longs:long_create')
class Exam(models.Model): class Exam(models.Model):
name = models.CharField(max_length=200) name = models.CharField(max_length=200)
exam_questions = SortedManyToManyField( exam_questions = SortedManyToManyField(
Rapid, related_name="exams", blank="true" Long, related_name="exams", blank="true"
) )
active = models.BooleanField( active = models.BooleanField(
@@ -377,13 +377,13 @@ class Exam(models.Model):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
return reverse("rapids:exam_overview", kwargs={"pk": self.pk}) return reverse("longs:exam_overview", kwargs={"pk": self.pk})
def get_exam_name(self): def get_exam_name(self):
return self.name return self.name
def get_json_url(self): def get_json_url(self):
return reverse("rapids:exam_json", args=(self.pk,)) return reverse("longs:exam_json", args=(self.pk,))
def get_question_index(self, question): def get_question_index(self, question):
return list(self.exam_questions.all()).index(question) return list(self.exam_questions.all()).index(question)
@@ -392,10 +392,10 @@ class CidUserAnswer(models.Model):
"""User answers by candidate""" """User answers by candidate"""
question = models.ForeignKey( question = models.ForeignKey(
Rapid, related_name="cid_user_answers", on_delete=models.CASCADE Long, related_name="cid_user_answers", on_delete=models.CASCADE
) )
# For rapids the answer can be normal in which case the below field is true # For longs the answer can be normal in which case the below field is true
normal = models.BooleanField(default=False) normal = models.BooleanField(default=False)
answer = models.TextField(max_length=500, blank=True) answer = models.TextField(max_length=500, blank=True)
+6 -6
View File
@@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import A from django_tables2.utils import A
from .models import Rapid from .models import Long
from django.utils.html import format_html from django.utils.html import format_html
@@ -25,23 +25,23 @@ class ImageColumn(tables.Column):
return format_html('<span title="{}">Invalid image url<span>', image_object) return format_html('<span title="{}">Invalid image url<span>', image_object)
class RapidTable(tables.Table): class LongTable(tables.Table):
edit = tables.LinkColumn('rapids:rapid_update', edit = tables.LinkColumn('longs:long_update',
text='Edit', text='Edit',
args=[A('pk')], args=[A('pk')],
orderable=False) orderable=False)
view = tables.LinkColumn('rapids:rapid_detail', view = tables.LinkColumn('longs:long_detail',
text='View', text='View',
args=[A('pk')], args=[A('pk')],
orderable=False) orderable=False)
clone = tables.LinkColumn('rapids:rapid_clone', clone = tables.LinkColumn('longs:long_clone',
text='Clone', text='Clone',
args=[A('pk')], args=[A('pk')],
orderable=False) orderable=False)
images = ImageColumn("images", orderable=False) images = ImageColumn("images", orderable=False)
class Meta: class Meta:
model = Rapid model = Long
template_name = "django_tables2/bootstrap4.html" template_name = "django_tables2/bootstrap4.html"
fields = ("normal", "abnormality", "region", "examination", fields = ("normal", "abnormality", "region", "examination",
"laterality", "site", "created_date", "author") "laterality", "site", "created_date", "author")
+2 -2
View File
@@ -1,8 +1,8 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
{% for author in authors %} {% for author in authors %}
<p>Author: <a href="{% url 'rapids:author_detail' pk=author.pk %}">{{author.username}}</a>, </p> <p>Author: <a href="{% url 'longs:author_detail' pk=author.pk %}">{{author.username}}</a>, </p>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
+6 -6
View File
@@ -1,7 +1,7 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% block title %} {% block title %}
Rapids Longs
{% endblock %} {% endblock %}
{% block css %} {% block css %}
@@ -15,13 +15,13 @@ Rapids
{% block content %} {% block content %}
{% endblock %} {% endblock %}
{% block navigation %} {% block navigation %}
Rapids: Longs:
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<a href="{% url 'rapids:exam_list' %}">Exams</a> / <a href="{% url 'longs:exam_list' %}">Exams</a> /
<a href="{% url 'rapids:rapid_view' %}">Questions</a> / <a href="{% url 'longs:long_view' %}">Questions</a> /
<a href="{% url 'rapids:rapid_create' %}" title="Create a new question">Create Question</a> <a href="{% url 'longs:long_create' %}" title="Create a new question">Create Question</a>
{% endif %} {% endif %}
{% comment %} </br> {% comment %} </br>
Questions by: Questions by:
<span id="authors-link"><a href="{% url 'rapids:author_list' %}">author</a></span> {% endcomment %} <span id="authors-link"><a href="{% url 'longs:author_list' %}">author</a></span> {% endcomment %}
{% endblock %} {% endblock %}
+4 -4
View File
@@ -1,11 +1,11 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
{{category}}: {{category}}:
<ul> <ul>
{% for rapid in rapids %} {% for long in longs %}
<li><a href="{% url 'rapids:rapid_detail' pk=rapid.pk %}">{{rapid}} <li><a href="{% url 'longs:long_detail' pk=long.pk %}">{{long}}
[{{rapid.get_authors}}]</a></li> [{{long.get_authors}}]</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
+3 -3
View File
@@ -1,4 +1,4 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
<script> <script>
@@ -7,7 +7,7 @@
$("#flagged-button").click(function () { $("#flagged-button").click(function () {
$.ajax({ $.ajax({
url: "{% url 'rapids:flag_question' %}", url: "{% url 'longs:flag_question' %}",
data: { data: {
'pk': {{ question.pk }} 'pk': {{ question.pk }}
}, },
@@ -64,7 +64,7 @@
<ul id=question-list> <ul id=question-list>
{% for question in questions %} {% for question in questions %}
<li><a class={% if question.pk in answered_questions %}answered{% else %}unanswered{% endif %} <li><a class={% if question.pk in answered_questions %}answered{% else %}unanswered{% endif %}
href="{% url 'rapids:exam_take' pk=exam.pk sk=forloop.counter0 %}">{{ forloop.counter }}{% if question.pk in flagged_questions %}!{% endif %}</a> href="{% url 'longs:exam_take' pk=exam.pk sk=forloop.counter0 %}">{{ forloop.counter }}{% if question.pk in flagged_questions %}!{% endif %}</a>
</li> </li>
+4 -4
View File
@@ -1,14 +1,14 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
<h1>Examinations</h1> <h1>Examinations</h1>
<div class="rapids"> <div class="longs">
Active exams:<br/> Active exams:<br/>
<ul> <ul>
{% for exam in exams %} {% for exam in exams %}
{% if exam.active %} {% if exam.active %}
<li> <li>
<a href="{% url 'rapids:exam_overview' pk=exam.pk %}">{{exam.name}}</a> <a href="{% url 'rapids:mark_overview' pk=exam.pk %}">(mark)</a> <a href="{% url 'rapids:exam_scores_cid' pk=exam.pk %}">(scores)</a> [Results are {% if not exam.publish_results %} not {% endif %}published] <a href="{% url 'longs:exam_overview' pk=exam.pk %}">{{exam.name}}</a> <a href="{% url 'longs:mark_overview' pk=exam.pk %}">(mark)</a> <a href="{% url 'longs:exam_scores_cid' pk=exam.pk %}">(scores)</a> [Results are {% if not exam.publish_results %} not {% endif %}published]
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
@@ -19,7 +19,7 @@
{% for exam in exams %} {% for exam in exams %}
{% if not exam.active %} {% if not exam.active %}
<li> <li>
<a href="{% url 'rapids:exam_overview' pk=exam.pk %}">{{exam.name}}</a> <a href="{% url 'rapids:mark_overview' pk=exam.pk %}">(mark)</a> <a href="{% url 'rapids:exam_scores_cid' pk=exam.pk %}">(scores)</a> [Results are {% if not exam.publish_results %} not {% endif %}published] <a href="{% url 'longs:exam_overview' pk=exam.pk %}">{{exam.name}}</a> <a href="{% url 'longs:mark_overview' pk=exam.pk %}">(mark)</a> <a href="{% url 'longs:exam_scores_cid' pk=exam.pk %}">(scores)</a> [Results are {% if not exam.publish_results %} not {% endif %}published]
</li> </li>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
+11 -11
View File
@@ -1,10 +1,10 @@
{% extends 'rapids/exams.html' %} {% extends 'longs/exams.html' %}
{% block content %} {% block content %}
{% load thumbnail %} {% load thumbnail %}
<div class="rapids"> <div class="longs">
<a href="{% url 'admin:rapids_exam_change' exam.id %}" title="Edit the Exam using the admin interface">Admin Edit</a> <a href="{% url 'admin:longs_exam_change' exam.id %}" title="Edit the Exam using the admin interface">Admin Edit</a>
<h1>Exam: {{ exam.name }}</h1> <h1>Exam: {{ exam.name }}</h1>
This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds. This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
@@ -14,7 +14,7 @@
<div class="parent-help" title="Click to enable / disable the exam results"> <div class="parent-help" title="Click to enable / disable the exam results">
Publish results: <input type="checkbox" id="exam-publish-results-switch" {% if exam.publish_results %}checked{% endif %}> <span class="help-text">[When checked the exam results will be available on this site]</span> Publish results: <input type="checkbox" id="exam-publish-results-switch" {% if exam.publish_results %}checked{% endif %}> <span class="help-text">[When checked the exam results will be available on this site]</span>
</div> </div>
<p><a href="{% url 'rapids:mark_overview' pk=exam.pk %}"><button>Mark exam</button></a></p> <p><a href="{% url 'longs:mark_overview' pk=exam.pk %}"><button>Mark exam</button></a></p>
<ol id="full-question-list"> <ol id="full-question-list">
{% for question in questions.all %} {% for question in questions.all %}
@@ -31,12 +31,12 @@
<b>Normal</b> <b>Normal</b>
{% endif %} {% endif %}
<br /> <br />
Examination: {{ question.get_examinations }}, <a href="{% url 'rapids:exam_question_detail' pk=exam.pk sk=forloop.counter0 %}">View</a>, <a href="{% url 'rapids:mark' pk=exam.pk sk=forloop.counter0 %}">Mark</a> Examination: {{ question.get_examinations }}, <a href="{% url 'longs:exam_question_detail' pk=exam.pk sk=forloop.counter0 %}">View</a>, <a href="{% url 'longs:mark' pk=exam.pk sk=forloop.counter0 %}">Mark</a>
</li> </li>
{% endfor %} {% endfor %}
</ol> </ol>
<a href="{% url 'rapids:exam_json' pk=exam.pk %}">JSON</a> <a href="{% url 'longs:exam_json' pk=exam.pk %}">JSON</a>
<a href="{% url 'rapids:exam_json_recreate' pk=exam.pk %}">Refresh JSON cache</a> <a href="{% url 'longs:exam_json_recreate' pk=exam.pk %}">Refresh JSON cache</a>
<button id='button-open-access'>Make questions open access</button> <button id='button-open-access'>Make questions open access</button>
<button id='button-closed-access'>Make questions closed access</button> <button id='button-closed-access'>Make questions closed access</button>
@@ -46,7 +46,7 @@
// send request to change the is_private state on customSwitches toggle // send request to change the is_private state on customSwitches toggle
$("#exam-active-switch").on("change", function () { $("#exam-active-switch").on("change", function () {
$.ajax({ $.ajax({
url: "{% url 'rapids:exam_toggle_active' pk=exam.pk %}", url: "{% url 'longs:exam_toggle_active' pk=exam.pk %}",
data: { data: {
csrfmiddlewaretoken: "{{ csrf_token }}", csrfmiddlewaretoken: "{{ csrf_token }}",
active: this.checked // true if checked else false active: this.checked // true if checked else false
@@ -70,7 +70,7 @@
}) })
$("#exam-publish-results-switch").on("change", function () { $("#exam-publish-results-switch").on("change", function () {
$.ajax({ $.ajax({
url: "{% url 'rapids:exam_toggle_results_published' pk=exam.pk %}", url: "{% url 'longs:exam_toggle_results_published' pk=exam.pk %}",
data: { data: {
csrfmiddlewaretoken: "{{ csrf_token }}", csrfmiddlewaretoken: "{{ csrf_token }}",
publish_results: this.checked // true if checked else false publish_results: this.checked // true if checked else false
@@ -94,7 +94,7 @@
}) })
$("#button-open-access").click(function () { $("#button-open-access").click(function () {
$.ajax({ $.ajax({
url: "{% url 'rapids:exam_json_edit' pk=exam.pk %}", url: "{% url 'longs:exam_json_edit' pk=exam.pk %}",
data: { data: {
csrfmiddlewaretoken: "{{ csrf_token }}", csrfmiddlewaretoken: "{{ csrf_token }}",
set_open_access: true, set_open_access: true,
@@ -116,7 +116,7 @@
}) })
$("#button-closed-access").click(function () { $("#button-closed-access").click(function () {
$.ajax({ $.ajax({
url: "{% url 'rapids:exam_json_edit' pk=exam.pk %}", url: "{% url 'longs:exam_json_edit' pk=exam.pk %}",
data: { data: {
csrfmiddlewaretoken: "{{ csrf_token }}", csrfmiddlewaretoken: "{{ csrf_token }}",
set_open_access: false, set_open_access: false,
+3 -3
View File
@@ -1,13 +1,13 @@
{% extends 'rapids/exams.html' %} {% extends 'longs/exams.html' %}
{% block content %} {% block content %}
<div class="rapids"> <div class="longs">
<h2>{{ exam.name }}</h2> <h2>{{ exam.name }}</h2>
{% if unmarked %} {% if unmarked %}
The following questions need marking The following questions need marking
{% for exam_index in unmarked %} {% for exam_index in unmarked %}
<a href="{% url 'rapids:mark' exam.pk exam_index %}">{{ exam_index|add:1 }}</a> <a href="{% url 'longs:mark' exam.pk exam_index %}">{{ exam_index|add:1 }}</a>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
+2 -2
View File
@@ -1,7 +1,7 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
<div class="rapids"> <div class="longs">
<h2>Exam: {{ exam.name }}</h2> <h2>Exam: {{ exam.name }}</h2>
<h3>Candidate: {{ cid }}</h3> <h3>Candidate: {{ cid }}</h3>
Answers: Answers:
+2 -2
View File
@@ -1,7 +1,7 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block navigation %} {% block navigation %}
{{block.super}} {{block.super}}
<br/> <br/>
Exams: {{exam.name}}-> <a href="{% url 'rapids:exam_overview' pk=exam.pk %}">Overview</a> / <a href="{% url 'rapids:mark_overview' pk=exam.pk %}">Mark</a> / <a href="{% url 'rapids:exam_scores_cid' pk=exam.pk %}">Scores</a> Exams: {{exam.name}}-> <a href="{% url 'longs:exam_overview' pk=exam.pk %}">Overview</a> / <a href="{% url 'longs:mark_overview' pk=exam.pk %}">Mark</a> / <a href="{% url 'longs:exam_scores_cid' pk=exam.pk %}">Scores</a>
{% endblock %} {% endblock %}
+5 -5
View File
@@ -1,11 +1,11 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
{% for exam in exams %} {% for exam in exams %}
<div class="rapids"> <div class="longs">
<h1><a href="{% url 'rapids:exam_overview' pk=exam.pk %}">Exam: {{ exam.name }} </a></h1> <h1><a href="{% url 'longs:exam_overview' pk=exam.pk %}">Exam: {{ exam.name }} </a></h1>
{% if request.user.is_staff %}<a href="{% url 'rapids:mark' pk=exam.pk sk=0 %}">Mark answers</a>{% endif %} {% if request.user.is_staff %}<a href="{% url 'longs:mark' pk=exam.pk sk=0 %}">Mark answers</a>{% endif %}
{% if request.user.is_staff %}<a href="{% url 'rapids:exam_scores_cid' pk=exam.pk %}">Scores</a>{% endif %} {% if request.user.is_staff %}<a href="{% url 'longs:exam_scores_cid' pk=exam.pk %}">Scores</a>{% endif %}
</div> </div>
{% endfor %} {% endfor %}
{% endblock %} {% endblock %}
+8 -8
View File
@@ -1,21 +1,21 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
My Questions: My Questions:
<ul> <ul>
{% for rapid in user_rapids %} {% for long in user_longs %}
<li{% if rapid.scrapped %} class='rapid-scrapped' {% endif %}><a <li{% if long.scrapped %} class='long-scrapped' {% endif %}><a
href="{% url 'rapids:rapid_detail' pk=rapid.pk %}">{{rapid}} href="{% url 'longs:long_detail' pk=long.pk %}">{{long}}
[{{rapid.get_authors}}]</a></li> [{{long.get_authors}}]</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
Other Questions: Other Questions:
<ul> <ul>
{% for rapid in other_rapids %} {% for long in other_longs %}
<li{% if rapid.scrapped %} class='rapid-scrapped' {% endif %}><a <li{% if long.scrapped %} class='long-scrapped' {% endif %}><a
href="{% url 'rapids:rapid_detail' pk=rapid.pk %}">{{rapid}} [{{rapid.get_authors}}]</a></li> href="{% url 'longs:long_detail' pk=long.pk %}">{{long}} [{{long.get_authors}}]</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
+3 -3
View File
@@ -1,9 +1,9 @@
{% extends 'rapids/exams.html' %} {% extends 'longs/exams.html' %}
{% block content %} {% block content %}
<h2>Marking question {{question_details.current}} of {{question_details.total}}</h2> <h2>Marking question {{question_details.current}} of {{question_details.total}}</h2>
<a href="{% url 'rapids:rapid_update' question.id %}" title="Edit the Question">Edit</a> <a <a href="{% url 'longs:long_update' question.id %}" title="Edit the Question">Edit</a> <a
href="{% url 'admin:rapids_rapid_change' question.id %}" title="Edit the Question using the admin interface">Admin href="{% url 'admin:longs_long_change' question.id %}" title="Edit the Question using the admin interface">Admin
Edit</a> Edit</a>
{% if question.normal %} {% if question.normal %}
<h3>This question is normal</h3> <h3>This question is normal</h3>
+4 -4
View File
@@ -1,18 +1,18 @@
{% extends 'rapids/exams.html' %} {% extends 'longs/exams.html' %}
{% block content %} {% block content %}
<div class="rapids"> <div class="longs">
<h2>Marking exam: {{ exam.name }}</h2> <h2>Marking exam: {{ exam.name }}</h2>
You can start marking from a particular question by clicking on it below. You can start marking from a particular question by clicking on it below.
<div> <div>
<button class="show-all-button">Show all</button><button class="show-unmarked-button">Show unmarked</button> <button class="show-all-button">Show all</button><button class="show-unmarked-button">Show unmarked</button>
</div> </div>
<div id="stark-marking-button"><a href="{% url 'rapids:mark' pk=exam.pk sk=0 %}"><button>Click here to start marking</button></a></div> <div id="stark-marking-button"><a href="{% url 'longs:mark' pk=exam.pk sk=0 %}"><button>Click here to start marking</button></a></div>
<ul id="question-mark-list"> <ul id="question-mark-list">
{% for question in questions.all %} {% for question in questions.all %}
<li data-markcount={{question.GetUnmarkedAnswerCount}}><a href="{% url 'rapids:mark' pk=exam.pk sk=forloop.counter0 %}">Question {{forloop.counter }}: <li data-markcount={{question.GetUnmarkedAnswerCount}}><a href="{% url 'longs:mark' pk=exam.pk sk=forloop.counter0 %}">Question {{forloop.counter }}:
{{ question }}</a><br /> {{ question.GetUnmarkedAnswersString }}</li> {{ question }}</a><br /> {{ question.GetUnmarkedAnswersString }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
+1 -1
View File
@@ -1,4 +1,4 @@
{% extends "rapids/base.html" %} {% extends "longs/base.html" %}
{% block content %} {% block content %}
<h2>Add Note</h2> <h2>Add Note</h2>
+8 -8
View File
@@ -1,4 +1,4 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% block content %} {% block content %}
@@ -7,20 +7,20 @@
<div> <div>
{% if previous > -1 %} {% if previous > -1 %}
<a href="{% url 'rapids:exam_question_detail' exam.id previous %}">Previous question</a> <a href="{% url 'longs:exam_question_detail' exam.id previous %}">Previous question</a>
{% endif %} {% endif %}
This question is part of exam: {{exam.name}} [{{pos}}/{{exam_length}}] This question is part of exam: {{exam.name}} [{{pos}}/{{exam_length}}]
{% if next %} {% if next %}
<a href="{% url 'rapids:exam_question_detail' exam.id next %}">Next question</a> <a href="{% url 'longs:exam_question_detail' exam.id next %}">Next question</a>
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
<a href="{% url 'rapids:rapid_update' pk=question.pk %}" title="Edit the Rapid">Edit</a> <a href="{% url 'longs:long_update' pk=question.pk %}" title="Edit the Long">Edit</a>
<a href="{% url 'rapids:rapid_clone' pk=question.pk %}" title="Clone the Rapid (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 'rapids:rapid_add_note' pk=question.pk %}"> Add Note</a> <a href="{% url 'longs:long_add_note' pk=question.pk %}"> Add Note</a>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<a href="{% url 'admin:rapids_rapid_change' question.id %}" title="Edit the Rapid using the admin interface">Admin Edit</a> <a href="{% url 'admin:longs_long_change' question.id %}" title="Edit the Long using the admin interface">Admin Edit</a>
{% endif %} {% endif %}
{% include 'rapids/rapid_display_block.html' %} {% include 'longs/long_display_block.html' %}
{% endblock %} {% endblock %}
@@ -1,9 +1,9 @@
<div class="rapid {% if question.scrapped %}rapid-scrapped{% endif %}"> <div class="long {% if question.scrapped %}long-scrapped{% endif %}">
<div class="date"> <div class="date">
{{ question.created_date }} {{ question.created_date }}
</div> </div>
<p class="pre-whitespace"><b>Rapid:</b> {{ question }}</p> <p class="pre-whitespace"><b>Long:</b> {{ question }}</p>
<p class="pre-whitespace"><b>Region:</b> {{ question.get_regions }}</p> <p class="pre-whitespace"><b>Region:</b> {{ question.get_regions }}</p>
<p class="pre-whitespace"><b>Examination:</b> {{ question.get_examinations }}</p> <p class="pre-whitespace"><b>Examination:</b> {{ question.get_examinations }}</p>
<p class="pre-whitespace"><b>Laterality:</b> {{ question.laterality }}</p> <p class="pre-whitespace"><b>Laterality:</b> {{ question.laterality }}</p>
@@ -12,23 +12,23 @@
{% for image in question.images.all %} {% for image in question.images.all %}
<span class="image-block"> <span class="image-block">
Image {{ forloop.counter }}{% if image.feedback_image %} [feedback image]{% endif %}: Image {{ forloop.counter }}{% if image.feedback_image %} [feedback image]{% endif %}:
<div class="dicom-image rapid-img {% if image.feedback_image %}feedback-img{% endif %}" data-url="http://penracourses.org.uk{{ image.image.url}}"></div> <div class="dicom-image long-img {% if image.feedback_image %}feedback-img{% endif %}" data-url="http://penracourses.org.uk{{ image.image.url}}"></div>
</span> </span>
{% endfor %} {% endfor %}
</div> </div>
<p class="pre-whitespace"><b>Feedback:</b> {{ question.feedback }}</p> <p class="pre-whitespace"><b>Feedback:</b> {{ question.feedback }}</p>
<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 'rapids: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 'rapids:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p> href="{% url 'longs:verified_detail' pk=verified.pk %}">{{verified}}</a>, {% endfor %}</p>
<p><b>Scrapped:</b> {{ question.scrapped }} <a href="{% url 'rapids:rapid_scrap' pk=question.pk %}">(toggle)</a> <p><b>Scrapped:</b> {{ question.scrapped }} <a href="{% url 'longs:long_scrap' pk=question.pk %}">(toggle)</a>
<p class="pre-whitespace"><b>Answers:</b> {{ question.GetMarkedAnswers }}</p> <p class="pre-whitespace"><b>Answers:</b> {{ question.GetMarkedAnswers }}</p>
</p> </p>
</div> </div>
<div> <div>
Notes: Notes:
<ul> <ul>
{% for note in question.rapid_notes.all %} {% for note in question.long_notes.all %}
<li> <li>
{{ note.created_on }} by {{ note.author }}: {{ note.note }} {{ note.created_on }} by {{ note.author }}: {{ note.note }}
</li> </li>
+9 -9
View File
@@ -1,4 +1,4 @@
{% extends "rapids/base.html" %} {% extends "longs/base.html" %}
{% load static from static %} {% load static from static %}
{% block js %} {% block js %}
@@ -71,7 +71,7 @@
$(evt.target).removeClass("drop-target-active"); $(evt.target).removeClass("drop-target-active");
// Get all input elements // Get all input elements
inputs = $("#rapid-form input[type=file][id^=id_images-]"); inputs = $("#long-form input[type=file][id^=id_images-]");
//fileInput = document.getElementById("id_images-0-image"); //fileInput = document.getElementById("id_images-0-image");
// Make sure we have enough input targets // Make sure we have enough input targets
@@ -84,7 +84,7 @@
} }
// Need to make sure we include the new ones... // Need to make sure we include the new ones...
inputs = $("#rapid-form input[type=file][id^=id_images-]"); inputs = $("#long-form input[type=file][id^=id_images-]");
} }
// Loop through each dropped file and try to assign to an // Loop through each dropped file and try to assign to an
@@ -234,15 +234,15 @@
{{ form.media }} {{ form.media }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h2>Submit Rapid</h2> <h2>Submit Long</h2>
<a href="{% url 'rapids:rapid_create_defaults' %}">Edit defaults</a> <a href="{% url 'longs:long_create_defaults' %}">Edit defaults</a>
<form action="" method="post" enctype="multipart/form-data" id="rapid-form"> <form action="" method="post" enctype="multipart/form-data" id="long-form">
{% csrf_token %} {% csrf_token %}
<a href="/rapids/abnormality/create" id="add_abnormality" class="add-popup" <a href="/longs/abnormality/create" id="add_abnormality" class="add-popup"
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a> onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
<a href="/rapids/examination/create" id="add_examination" class="add-popup" <a href="/longs/examination/create" id="add_examination" class="add-popup"
onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a> onclick="return showAddPopup(this);"><img src="{% static '/img/icon-addlink.svg' %}"></a>
<a href="/rapids/region/create" id="add_region" class="add-popup" onclick="return showAddPopup(this);"><img <a href="/longs/region/create" id="add_region" class="add-popup" onclick="return showAddPopup(this);"><img
src="{% static '/img/icon-addlink.svg' %}"></a> src="{% static '/img/icon-addlink.svg' %}"></a>
<table> <table>
@@ -1,8 +1,8 @@
{% extends "rapids/base.html" %} {% extends "longs/base.html" %}
{% block content %} {% block content %}
<h2>Defaults for creating new rapids</h2> <h2>Defaults for creating new longs</h2>
<form method="POST" class="post-form">{% csrf_token %} <form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }} {{ form.as_p }}
<button type="submit" class="save btn btn-primary">Save</button> <button type="submit" class="save btn btn-primary">Save</button>
+2 -2
View File
@@ -1,4 +1,4 @@
{% extends 'rapids/base.html' %} {% extends 'longs/base.html' %}
{% load render_table from django_tables2 %} {% load render_table from django_tables2 %}
{% block css %} {% block css %}
@@ -7,7 +7,7 @@
{% block content %} {% block content %}
<div id="view-filter-options"> <div id="view-filter-options">
<h3>Filter Rapids</h3> <h3>Filter Longs</h3>
<form action="" method="get"> <form action="" method="get">
{{ filter.form }} {{ filter.form }}
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" /> <input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
+12 -12
View File
@@ -1,22 +1,22 @@
from django.urls import path, include from django.urls import path, include
from . import views from . import views
app_name = "rapids" app_name = "longs"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.index, name="index"), path("", views.index, name="index"),
path("author/<int:pk>/", views.author_detail, name="author_detail"), path("author/<int:pk>/", views.author_detail, name="author_detail"),
path("author/", views.author_list, name="author_list"), path("author/", views.author_list, name="author_list"),
path("question/", views.RapidView.as_view(), name="rapid_view"), path("question/", views.LongView.as_view(), name="long_view"),
#path("unchecked/", views.unchecked_list, name="unchecked_list"), #path("unchecked/", views.unchecked_list, name="unchecked_list"),
#path("verified/<int:pk>/", views.verified_detail, name="verified_detail"), #path("verified/<int:pk>/", views.verified_detail, name="verified_detail"),
path("question/<int:pk>/", views.rapid_detail, name="rapid_detail"), path("question/<int:pk>/", views.long_detail, name="long_detail"),
path("question/<int:pk>/split", views.rapid_split, name="rapid_split"), path("question/<int:pk>/split", views.long_split, name="long_split"),
path("question/<int:pk>/clone", views.RapidClone.as_view(), name="rapid_clone"), path("question/<int:pk>/clone", views.LongClone.as_view(), name="long_clone"),
#path("verified/", views.verified, name="verified"), #path("verified/", views.verified, name="verified"),
#path("all_questions/", views.all_questions, name="all_questions"), #path("all_questions/", views.all_questions, name="all_questions"),
path("question/<int:pk>/scrap", views.rapid_scrap, name="rapid_scrap"), path("question/<int:pk>/scrap", views.long_scrap, name="long_scrap"),
path("exam/<int:pk>/<int:sk>/mark", views.mark, name="mark"), path("exam/<int:pk>/<int:sk>/mark", views.mark, name="mark"),
path("exam/<int:pk>/mark", views.mark_overview, name="mark_overview"), path("exam/<int:pk>/mark", views.mark_overview, name="mark_overview"),
# path("exam/<int:pk>/<int:sk>/", views.exam_take, name="exam_take"), # path("exam/<int:pk>/<int:sk>/", views.exam_take, name="exam_take"),
@@ -34,10 +34,10 @@ urlpatterns = [
path("exam/json/", views.active_exams, name="active_exams"), path("exam/json/", views.active_exams, name="active_exams"),
path("exam/json/<int:pk>", views.exam_json, name="exam_json"), path("exam/json/<int:pk>", views.exam_json, name="exam_json"),
path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"), path("exam/json/<int:pk>/recreate", views.exam_json_recreate, name="exam_json_recreate"),
path("create/", views.RapidCreate.as_view(), name="rapid_create"), path("create/", views.LongCreate.as_view(), name="long_create"),
path("create/defaults", path("create/defaults",
views.RapidCreationDefaultView.as_view(), views.LongCreationDefaultView.as_view(),
name="rapid_create_defaults"), name="long_create_defaults"),
path("region/create/", views.create_region, name="create_region"), path("region/create/", views.create_region, name="create_region"),
path("region/ajax/get_region_id", path("region/ajax/get_region_id",
views.get_region_id, views.get_region_id,
@@ -56,8 +56,8 @@ urlpatterns = [
name="get_examination_id"), name="get_examination_id"),
path( path(
"question/<int:pk>/update", "question/<int:pk>/update",
views.RapidUpdate.as_view(), views.LongUpdate.as_view(),
name="rapid_update", name="long_update",
), ),
path("<int:pk>/add_note", views.AddNote.as_view(), name="rapid_add_note"), path("<int:pk>/add_note", views.AddNote.as_view(), name="long_add_note"),
] ]
+109 -109
View File
@@ -19,8 +19,8 @@ from django.http import Http404, JsonResponse
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from .forms import ( from .forms import (
RapidForm, LongForm,
MarkRapidQuestionForm, MarkLongQuestionForm,
ImageFormSet, ImageFormSet,
NoteForm, NoteForm,
RegionForm, RegionForm,
@@ -30,7 +30,7 @@ from .forms import (
AnswerUpdateFormSet, AnswerUpdateFormSet,
) )
from .models import ( from .models import (
Rapid, Long,
Note, Note,
Abnormality, Abnormality,
Region, Region,
@@ -39,13 +39,13 @@ from .models import (
Answer, Answer,
CidUserAnswer, CidUserAnswer,
) )
from .tables import RapidTable from .tables import LongTable
from .filters import RapidFilter from .filters import LongFilter
from django_tables2 import SingleTableView, SingleTableMixin from django_tables2 import SingleTableView, SingleTableMixin
from django_filters.views import FilterView from django_filters.views import FilterView
from .decorators import user_is_author_or_rapid_checker from .decorators import user_is_author_or_long_checker
from collections import defaultdict from collections import defaultdict
import json import json
@@ -59,8 +59,8 @@ from helpers.images import image_as_base64
import logging import logging
from copy import deepcopy from copy import deepcopy
from django.forms.models import model_to_dict from django.forms.models import model_to_dict
from rapids.forms import RapidCreationDefaultForm from longs.forms import LongCreationDefaultForm
from rapids.models import RapidCreationDefault from longs.models import LongCreationDefault
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -68,7 +68,7 @@ logger = logging.getLogger(__name__)
class AuthorOrCheckerRequiredMixin(object): class AuthorOrCheckerRequiredMixin(object):
def get_object(self, *args, **kwargs): def get_object(self, *args, **kwargs):
obj = super(UpdateView, self).get_object(*args, **kwargs) obj = super(UpdateView, self).get_object(*args, **kwargs)
if self.request.user.groups.filter(name="rapid_checker").exists(): if self.request.user.groups.filter(name="long_checker").exists():
return obj return obj
if self.request.user not in obj.author.all(): if self.request.user not in obj.author.all():
raise PermissionDenied() # or Http404 raise PermissionDenied() # or Http404
@@ -78,67 +78,67 @@ class AuthorOrCheckerRequiredMixin(object):
@login_required @login_required
def index(request): def index(request):
exams = Exam.objects.all() exams = Exam.objects.all()
return render(request, "rapids/index.html", {"exams": exams}) return render(request, "longs/index.html", {"exams": exams})
# def index(request): # def index(request):
# other_rapids = Rapid.objects.exclude(author=request.user.pk) # other_longs = Long.objects.exclude(author=request.user.pk)
# user_rapids = Rapid.objects.filter(author=request.user.pk) # user_longs = Long.objects.filter(author=request.user.pk)
# return render( # return render(
# request, # request,
# "rapids/index.html", # "longs/index.html",
# {"other_rapids": other_rapids, "user_rapids": user_rapids}, # {"other_longs": other_longs, "user_longs": user_longs},
# ) # )
@login_required @login_required
def rapid_detail(request, pk): def long_detail(request, pk):
rapid = get_object_or_404(Rapid, pk=pk) long = get_object_or_404(Long, pk=pk)
# if request.user not in rapid.author.all(): # if request.user not in long.author.all():
# raise PermissionDenied # raise PermissionDenied
# logging.debug(rapid.rapid_notes.first()) # logging.debug(long.long_notes.first())
# logging.debug(rapid.subspecialty.first().name.all()) # logging.debug(long.subspecialty.first().name.all())
return render(request, "rapids/rapid_detail.html", {"question": rapid}) return render(request, "longs/long_detail.html", {"question": long})
@login_required @login_required
def rapid_split(request, pk): def long_split(request, pk):
rapid = get_object_or_404(Rapid, pk=pk) long = get_object_or_404(Long, pk=pk)
images = rapid.images.all() images = long.images.all()
old_abnormality = rapid.abnormality.all() old_abnormality = long.abnormality.all()
old_region = rapid.region.all() old_region = long.region.all()
old_examination = rapid.examination.all() old_examination = long.examination.all()
old_site = rapid.site.all() old_site = long.site.all()
old_author = rapid.author.all() old_author = long.author.all()
if not images: if not images:
raise Http404 raise Http404
for n in range(len(images) - 1): for n in range(len(images) - 1):
rapid.pk = None long.pk = None
rapid.save() long.save()
rapid.abnormality.set(old_abnormality) long.abnormality.set(old_abnormality)
rapid.region.set(old_region) long.region.set(old_region)
rapid.examination.set(old_examination) long.examination.set(old_examination)
rapid.site.set(old_site) long.site.set(old_site)
rapid.author.set(old_author) long.author.set(old_author)
images[n].rapid = rapid images[n].long = long
images[n].save() images[n].save()
# images[-1].rapid # images[-1].long
# if request.user not in rapid.author.all(): # if request.user not in long.author.all():
# raise PermissionDenied # raise PermissionDenied
# logging.debug(rapid.rapid_notes.first()) # logging.debug(long.long_notes.first())
# logging.debug(rapid.subspecialty.first().name.all()) # logging.debug(long.subspecialty.first().name.all())
return render(request, "rapids/rapid_detail.html", {"question": rapid}) return render(request, "longs/long_detail.html", {"question": long})
@login_required @login_required
@@ -147,22 +147,22 @@ def author_detail(request, pk):
# author = get_object_or_404(Author, pk=pk) # author = get_object_or_404(Author, pk=pk)
author = User.objects.get(pk=pk) author = User.objects.get(pk=pk)
rapids = Rapid.objects.filter(author=pk) longs = Long.objects.filter(author=pk)
return render( return render(
request, "rapids/category_detail.html", {"category": author, "rapids": rapids} request, "longs/category_detail.html", {"category": author, "longs": longs}
) )
def author_list(request): def author_list(request):
authors = User.objects.all() authors = User.objects.all()
return render(request, "rapids/author_list.html", {"authors": authors}) return render(request, "longs/author_list.html", {"authors": authors})
class RapidCreationDefaultView(LoginRequiredMixin, UpdateView): class LongCreationDefaultView(LoginRequiredMixin, UpdateView):
model = RapidCreationDefault model = LongCreationDefault
form_class = RapidCreationDefaultForm form_class = LongCreationDefaultForm
# fields = '__all__' # fields = '__all__'
# #fields = [ 'condition' ] # #fields = [ 'condition' ]
@@ -170,13 +170,13 @@ class RapidCreationDefaultView(LoginRequiredMixin, UpdateView):
# exclude = [ 'created_date', 'published_date' ] # exclude = [ 'created_date', 'published_date' ]
# def dispatch(self, request, *args, **kwargs): # def dispatch(self, request, *args, **kwargs):
# """ # """
# Overridden so we can make sure the `Rapid` instance exists # Overridden so we can make sure the `Long` instance exists
# before going any further. # before going any further.
# """ # """
# self.pk = get_object_or_404(Rapid, pk=kwargs['pk']) # self.pk = get_object_or_404(Long, pk=kwargs['pk'])
# return super().dispatch(request, *args, **kwargs) # return super().dispatch(request, *args, **kwargs)
def get_object(self, queryset=None): def get_object(self, queryset=None):
obj, create = RapidCreationDefault.objects.get_or_create( obj, create = LongCreationDefault.objects.get_or_create(
author=self.request.user author=self.request.user
) )
@@ -206,17 +206,17 @@ class AddNote(LoginRequiredMixin, CreateView):
# exclude = [ 'created_date', 'published_date' ] # exclude = [ 'created_date', 'published_date' ]
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
""" """
Overridden so we can make sure the `Rapid` instance exists Overridden so we can make sure the `Long` instance exists
before going any further. before going any further.
""" """
self.pk = get_object_or_404(Rapid, pk=kwargs["pk"]) self.pk = get_object_or_404(Long, pk=kwargs["pk"])
return super().dispatch(request, *args, **kwargs) return super().dispatch(request, *args, **kwargs)
def form_valid(self, form): def form_valid(self, form):
note = form.save(commit=False) note = form.save(commit=False)
note.rapid = self.pk note.long = self.pk
note.author = self.request.user note.author = self.request.user
note.save() note.save()
@@ -229,12 +229,12 @@ class AddNote(LoginRequiredMixin, CreateView):
@login_required @login_required
def rapid_clone(request, pk): def long_clone(request, pk):
new_item = get_object_or_404(Rapid, pk=pk) new_item = get_object_or_404(Long, pk=pk)
new_item.pk = None # autogen a new pk (item_id) new_item.pk = None # autogen a new pk (item_id)
# new_item.name = "Copy of " + new_item.name #need to change uniques # new_item.name = "Copy of " + new_item.name #need to change uniques
form = RapidForm(request.POST or None, instance=new_item) form = LongForm(request.POST or None, instance=new_item)
image_formset = ImageFormSet() image_formset = ImageFormSet()
answer_formset = AnswerFormSet() answer_formset = AnswerFormSet()
@@ -261,15 +261,15 @@ def rapid_clone(request, pk):
# other context # other context
} }
return render(request, "rapids/rapid_form.html", context) return render(request, "longs/long_form.html", context)
class RapidCreateBase(LoginRequiredMixin, CreateView): class LongCreateBase(LoginRequiredMixin, CreateView):
model = Rapid model = Long
form_class = RapidForm form_class = LongForm
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RapidCreateBase, self).get_context_data(**kwargs) context = super(LongCreateBase, self).get_context_data(**kwargs)
if self.request.POST: if self.request.POST:
context["image_formset"] = ImageFormSet( context["image_formset"] = ImageFormSet(
self.request.POST, self.request.FILES self.request.POST, self.request.FILES
@@ -303,21 +303,21 @@ class RapidCreateBase(LoginRequiredMixin, CreateView):
return response return response
# else we redirect to the clone url # else we redirect to the clone url
else: else:
return redirect("rapids:rapid_clone", pk=self.object.pk) return redirect("longs:long_clone", pk=self.object.pk)
else: else:
return super().form_invalid(form) return super().form_invalid(form)
# @login_required # @login_required
class RapidCreate(RapidCreateBase): class LongCreate(LongCreateBase):
initial = {"laterality": Rapid.NONE} initial = {"laterality": Long.NONE}
def get_initial(self): def get_initial(self):
# There has to be a better way... # There has to be a better way...
try: try:
s = (i.pk for i in self.request.user.rapid_default.site.all()) s = (i.pk for i in self.request.user.long_default.site.all())
self.initial.update({"site": s}) self.initial.update({"site": s})
except AttributeError: except AttributeError:
pass pass
@@ -335,16 +335,16 @@ class RapidCreate(RapidCreateBase):
# return super().form_valid(form) # return super().form_valid(form)
class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView): class LongUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
model = Rapid model = Long
form_class = RapidForm form_class = LongForm
# fields = '__all__' # fields = '__all__'
# #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_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RapidUpdate, self).get_context_data(**kwargs) context = super(LongUpdate, self).get_context_data(**kwargs)
if self.request.POST: if self.request.POST:
context["image_formset"] = ImageFormSet( context["image_formset"] = ImageFormSet(
self.request.POST, self.request.FILES, instance=self.object self.request.POST, self.request.FILES, instance=self.object
@@ -381,8 +381,8 @@ class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
return super().form_invalid(form) return super().form_invalid(form)
class RapidClone(RapidCreateBase): class LongClone(LongCreateBase):
"""Clones a existing rapid""" """Clones a existing long"""
# fields = '__all__' # fields = '__all__'
# #fields = [ 'condition' ] # #fields = [ 'condition' ]
@@ -390,23 +390,23 @@ class RapidClone(RapidCreateBase):
# exclude = [ 'created_date', 'published_date' ] # exclude = [ 'created_date', 'published_date' ]
def get_initial(self): def get_initial(self):
# print(self.request) # print(self.request)
old_object = get_object_or_404(Rapid, pk=self.kwargs["pk"]) old_object = get_object_or_404(Long, pk=self.kwargs["pk"])
initial_data = model_to_dict(old_object, exclude=["id"]) initial_data = model_to_dict(old_object, exclude=["id"])
return initial_data return initial_data
@login_required @login_required
@user_is_author_or_rapid_checker @user_is_author_or_long_checker
def rapid_scrap(request, pk): def long_scrap(request, pk):
try: try:
rapid = Rapid.objects.get(pk=pk) long = Long.objects.get(pk=pk)
except Rapid.DoesNotExist: except Long.DoesNotExist:
raise Http404("Rapid does not exist") raise Http404("Long does not exist")
rapid.scrapped = not rapid.scrapped long.scrapped = not long.scrapped
rapid.save() long.save()
return HttpResponseRedirect(reverse("rapids:rapid_detail", args=(pk,))) return HttpResponseRedirect(reverse("longs:long_detail", args=(pk,)))
# @login_required # @login_required
@@ -416,7 +416,7 @@ def rapid_scrap(request, pk):
# if form.is_valid(): # if form.is_valid():
# instance = form.save() # instance = form.save()
# return HttpResponse('<script>opener.closePopup(window, "%s", "%s", "#id_abnormality");</script>' % (instance.pk, instance)) # return HttpResponse('<script>opener.closePopup(window, "%s", "%s", "#id_abnormality");</script>' % (instance.pk, instance))
# return render(request, "rapids/create_simple.html", {'form': form}) # return render(request, "longs/create_simple.html", {'form': form})
@login_required @login_required
@@ -429,7 +429,7 @@ def create_abnormality(request):
% (instance.pk, instance) % (instance.pk, instance)
) )
return render( return render(
request, "rapids/create_simple.html", {"form": form, "name": "Abnormality"} request, "longs/create_simple.html", {"form": form, "name": "Abnormality"}
) )
@@ -455,7 +455,7 @@ def create_examination(request):
% (instance.pk, instance) % (instance.pk, instance)
) )
return render( return render(
request, "rapids/create_simple.html", {"form": form, "name": "Examination"} request, "longs/create_simple.html", {"form": form, "name": "Examination"}
) )
@@ -481,7 +481,7 @@ def create_region(request):
% (instance.pk, instance) % (instance.pk, instance)
) )
return render( return render(
request, "rapids/create_simple.html", {"form": form, "name": "Region"} request, "longs/create_simple.html", {"form": form, "name": "Region"}
) )
@@ -497,12 +497,12 @@ def get_region_id(request):
return HttpResponse("/") return HttpResponse("/")
class RapidView(SingleTableMixin, FilterView): class LongView(SingleTableMixin, FilterView):
model = Rapid model = Long
table_class = RapidTable table_class = LongTable
template_name = "rapids/view.html" template_name = "longs/view.html"
filterset_class = RapidFilter filterset_class = LongFilter
def loadJsonAnswer(answer): def loadJsonAnswer(answer):
@@ -617,7 +617,7 @@ def mark_overview(request, pk):
questions = exam.exam_questions.all() questions = exam.exam_questions.all()
return render( return render(
request, "rapids/mark_overview.html", {"exam": exam, "questions": questions} request, "longs/mark_overview.html", {"exam": exam, "questions": questions}
) )
@@ -659,14 +659,14 @@ def mark(request, pk, sk):
if request.method == "POST": if request.method == "POST":
form = MarkRapidQuestionForm(request.POST) form = MarkLongQuestionForm(request.POST)
# ******************************* # *******************************
# TODO: convert to JSON request # TODO: convert to JSON request
# ******************************* # *******************************
if form.is_valid(): if form.is_valid():
# If skip button is pressed skip the question without marking # If skip button is pressed skip the question without marking
if "skip" in request.POST: if "skip" in request.POST:
return redirect("rapids:mark", pk=pk, sk=n + 1) return redirect("longs:mark", pk=pk, sk=n + 1)
cd = form.cleaned_data cd = form.cleaned_data
# correct = cd.get("correct") # correct = cd.get("correct")
@@ -738,14 +738,14 @@ def mark(request, pk, sk):
# answer.published_date = timezone.now() # answer.published_date = timezone.now()
# answer.save() # answer.save()
if "next" in request.POST: if "next" in request.POST:
return redirect("rapids:mark", pk=pk, sk=n + 1) return redirect("longs:mark", pk=pk, sk=n + 1)
elif "previous" in request.POST: elif "previous" in request.POST:
return redirect("rapids:mark", pk=pk, sk=n - 1) return redirect("longs:mark", pk=pk, sk=n - 1)
# Reset user answers (relies on the functional javascript) # Reset user answers (relies on the functional javascript)
unmarked_user_answers = set() unmarked_user_answers = set()
else: else:
form = MarkRapidQuestionForm() form = MarkLongQuestionForm()
correct_answers = question.answers.filter(status=Answer.MarkOptions.CORRECT) correct_answers = question.answers.filter(status=Answer.MarkOptions.CORRECT)
half_mark_answers = question.answers.filter(status=Answer.MarkOptions.HALF_MARK) half_mark_answers = question.answers.filter(status=Answer.MarkOptions.HALF_MARK)
@@ -753,7 +753,7 @@ def mark(request, pk, sk):
return render( return render(
request, request,
"rapids/mark.html", "longs/mark.html",
{ {
"exam": exam, "exam": exam,
"form": form, "form": form,
@@ -808,7 +808,7 @@ def active_exams(request, json=True):
{ {
"name": exam.get_exam_name(), "name": exam.get_exam_name(),
"url": request.build_absolute_uri(exam.get_json_url()), "url": request.build_absolute_uri(exam.get_json_url()),
"type": "rapid", "type": "long",
} }
) )
@@ -825,7 +825,7 @@ def exam_json(request, pk):
if not exam.active: if not exam.active:
raise Http404("No available exam") raise Http404("No available exam")
exam_json_cache = cache.get("rapids_exam_json_{}".format(pk)) exam_json_cache = cache.get("longs_exam_json_{}".format(pk))
if exam_json_cache is not None and not exam.recreate_json: if exam_json_cache is not None and not exam.recreate_json:
exam_json_cache["cached"] = True exam_json_cache["cached"] = True
@@ -840,7 +840,7 @@ def exam_json(request, pk):
for q in questions: for q in questions:
exam_order.append(q.id) exam_order.append(q.id)
# Loop through rapidimage associations # Loop through longimage associations
images = [] images = []
feedback_images = [] feedback_images = []
for i in q.images.all(): for i in q.images.all():
@@ -857,7 +857,7 @@ def exam_json(request, pk):
"images": images, "images": images,
#"feedback_image": [], #"feedback_image": [],
#"annotations": [str(q.image_annotations)], #"annotations": [str(q.image_annotations)],
"type": "rapid", "type": "long",
} }
#if feedback_images: #if feedback_images:
@@ -865,9 +865,9 @@ def exam_json(request, pk):
exam_json = { exam_json = {
"eid": "rapid/{}".format(exam.id), "eid": "long/{}".format(exam.id),
"cached": False, "cached": False,
"exam_type": "rapid", "exam_type": "long",
"exam_name": exam.name, "exam_name": exam.name,
"exam_mode": True, "exam_mode": True,
"exam_order": exam_order, "exam_order": exam_order,
@@ -880,7 +880,7 @@ def exam_json(request, pk):
exam.recreate_json = False exam.recreate_json = False
exam.save() exam.save()
cache.set("rapids_exam_json_{}".format(pk), exam_json, 3600) cache.set("longs_exam_json_{}".format(pk), exam_json, 3600)
return JsonResponse(exam_json) return JsonResponse(exam_json)
@@ -892,7 +892,7 @@ def exam_json_recreate(request, pk):
exam.recreate_json = True exam.recreate_json = True
exam.save() exam.save()
return redirect("rapids:exam_overview", pk=pk) return redirect("longs:exam_overview", pk=pk)
@login_required @login_required
@@ -980,7 +980,7 @@ def exam_scores_cid(request, pk):
return render( return render(
request, request,
"rapids/exam_scores.html", "longs/exam_scores.html",
{ {
"cids": cids, "cids": cids,
"exam": exam, "exam": exam,
@@ -1053,7 +1053,7 @@ def exam_scores_cid_user(request, pk, sk):
return render( return render(
request, request,
"rapids/exam_scores_user.html", "longs/exam_scores_user.html",
{ {
"exam": exam, "exam": exam,
"cid": cid, "cid": cid,
@@ -1088,7 +1088,7 @@ def exam_question_detail(request, pk, sk):
return render( return render(
request, request,
"rapids/rapid_detail.html", "longs/long_detail.html",
{ {
"question": question, "question": question,
"exam": exam, "exam": exam,
@@ -1103,7 +1103,7 @@ def exam_question_detail(request, pk, sk):
@login_required @login_required
def exam_list(request): def exam_list(request):
exams = Exam.objects.all() exams = Exam.objects.all()
return render(request, "rapids/exam_list.html", {"exams": exams}) return render(request, "longs/exam_list.html", {"exams": exams})
@login_required @login_required
@@ -1121,6 +1121,6 @@ def exam_overview(request, pk):
return render( return render(
request, request,
"rapids/exam_overview.html", "longs/exam_overview.html",
{"exam": exam, "questions": questions, "question_number": question_number}, {"exam": exam, "questions": questions, "question_number": question_number},
) )