lots of updates
This commit is contained in:
@@ -1,10 +0,0 @@
|
|||||||
# serializers.py
|
|
||||||
from rest_framework import serializers, permissions
|
|
||||||
|
|
||||||
|
|
||||||
from .models import Exam
|
|
||||||
|
|
||||||
class ExamSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Exam
|
|
||||||
fields = ('name', 'id', 'active', "publish_results")
|
|
||||||
@@ -80,10 +80,6 @@ from django.template.defaulttags import register
|
|||||||
|
|
||||||
from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin
|
from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin
|
||||||
|
|
||||||
from rest_framework import viewsets, permissions
|
|
||||||
|
|
||||||
from .serializers import ExamSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorOrCheckerRequiredMixin(object):
|
class AuthorOrCheckerRequiredMixin(object):
|
||||||
def get_object(self, *args, **kwargs):
|
def get_object(self, *args, **kwargs):
|
||||||
@@ -818,22 +814,6 @@ class ExamDelete(AuthorOrCheckerRequiredMixin, ExamDeleteBase):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#class ExamViewSet(RevisionMixin, viewsets.ModelViewSet):
|
|
||||||
# # queryset = Exam.objects.all().order_by('name')
|
|
||||||
# serializer_class = ExamSerializer
|
|
||||||
# permission_classes = [permissions.IsAuthenticated]
|
|
||||||
#
|
|
||||||
# def get_queryset(self):
|
|
||||||
# """
|
|
||||||
# This view should return a list exams available to a user.
|
|
||||||
# """
|
|
||||||
# user = self.request.user
|
|
||||||
# if user.groups.filter(name="anatomy_checker").exists():
|
|
||||||
# return Exam.objects.all()
|
|
||||||
#
|
|
||||||
# return Exam.objects.filter(author__id=user.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ExamAuthorUpdate(RevisionMixin, CheckCanEditMixin, LoginRequiredMixin, AuthorRequiredMixin, UpdateView):
|
class ExamAuthorUpdate(RevisionMixin, CheckCanEditMixin, LoginRequiredMixin, AuthorRequiredMixin, UpdateView):
|
||||||
model = Exam
|
model = Exam
|
||||||
form_class = ExamAuthorForm
|
form_class = ExamAuthorForm
|
||||||
|
|||||||
+9
-3
@@ -55,7 +55,7 @@ from tinymce.widgets import TinyMCE
|
|||||||
|
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
|
|
||||||
from autocomplete import widgets as htmx_widgets
|
from autocomplete import widgets as htmx_widgets, Autocomplete, AutocompleteWidget, ModelAutocomplete, register as autocomplete_register
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -782,11 +782,17 @@ class UncategorisedDicomForm(ModelForm):
|
|||||||
# )
|
# )
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
class ConditionAutocomplete(ModelAutocomplete):
|
||||||
|
model = Condition
|
||||||
|
search_attrs = ["name"]
|
||||||
|
|
||||||
class ConditionAutocompleteForm(Form):
|
class ConditionAutocompleteForm(Form):
|
||||||
condition = ModelChoiceField(queryset=Condition.objects.all(), widget=htmx_widgets.Autocomplete(
|
condition = ModelChoiceField(queryset=Condition.objects.all(), widget=AutocompleteWidget(
|
||||||
name="conditions", options=dict(model=Condition)
|
ac_class=ConditionAutocomplete#, options=dict(model=Condition)
|
||||||
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
autocomplete_register(ConditionAutocomplete)
|
||||||
|
|
||||||
class CaseCollectionAuthorForm(ExamAuthorFormMixin):
|
class CaseCollectionAuthorForm(ExamAuthorFormMixin):
|
||||||
class Meta(ExamAuthorFormMixin.Meta):
|
class Meta(ExamAuthorFormMixin.Meta):
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# serializers.py
|
|
||||||
from rest_framework import serializers, permissions
|
|
||||||
+1
-3
@@ -118,7 +118,7 @@ from .filters import (
|
|||||||
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 autocomplete import HTMXAutoComplete
|
#from autocomplete import HTMXAutoComplete
|
||||||
|
|
||||||
|
|
||||||
from .decorators import (
|
from .decorators import (
|
||||||
@@ -156,8 +156,6 @@ from reversion.views import RevisionMixin
|
|||||||
import reversion
|
import reversion
|
||||||
|
|
||||||
|
|
||||||
from rest_framework import viewsets
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import difflib
|
import difflib
|
||||||
|
|
||||||
|
|||||||
@@ -24,55 +24,47 @@
|
|||||||
|
|
||||||
{% if object.anatomy_exams.all %}
|
{% if object.anatomy_exams.all %}
|
||||||
<h2>Anatomy Exams:</h2>
|
<h2>Anatomy Exams:</h2>
|
||||||
<ul>
|
{% with exams=object.anatomy_exams.all app_name="anatomy" %}
|
||||||
{% for exam in object.anatomy_exams.all %}
|
{% include "exam_list.html#exam-list" %}
|
||||||
<li><a href="{% url 'anatomy:exam_overview' exam.pk %}">{{ exam }}</a> - <a href="{% url 'anatomy:exam_update' exam.pk %}">(Edit)</a></li>
|
{% endwith %}
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a href="{% url 'anatomy:exam_list_collection' object.pk %}">View exam list</a>
|
<a href="{% url 'anatomy:exam_list_collection' object.pk %}">View exam list</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if object.longs_exams.all %}
|
{% if object.longs_exams.all %}
|
||||||
<h2>Longs Exams:</h2>
|
<h2>Longs Exams:</h2>
|
||||||
<ul>
|
{% with exams=object.longs_exams.all app_name="longs" %}
|
||||||
{% for exam in object.longs_exams.all %}
|
{% include "exam_list.html#exam-list" %}
|
||||||
<li><a href="{% url 'longs:exam_overview' exam.pk %}">{{ exam }}</a> - <a href="{% url 'longs:exam_update' exam.pk %}">(Edit)</a></li>
|
{% endwith %}
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a href="{% url 'longs:exam_list_collection' object.pk %}">View exam list</a>
|
<a href="{% url 'longs:exam_list_collection' object.pk %}">View exam list</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if object.rapids_exams.all %}
|
{% if object.rapids_exams.all %}
|
||||||
<h2>Rapids Exams:</h2>
|
<h2>Rapids Exams:</h2>
|
||||||
<ul>
|
{% with exams=object.rapids_exams.all app_name="rapids" %}
|
||||||
{% for exam in object.rapids_exams.all %}
|
{% include "exam_list.html#exam-list" %}
|
||||||
<li><a href="{% url 'rapids:exam_overview' exam.pk %}">{{ exam }}</a> - <a href="{% url 'rapids:exam_update' exam.pk %}">(Edit)</a></li>
|
{% endwith %}
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a href="{% url 'rapids:exam_list_collection' object.pk %}">View exam list</a>
|
<a href="{% url 'rapids:exam_list_collection' object.pk %}">View exam list</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if object.physics_exams.all %}
|
{% if object.physics_exams.all %}
|
||||||
<h2>Physics Exams:</h2>
|
<h2>Physics Exams:</h2>
|
||||||
<ul>
|
{% with exams=object.physics_exams.all app_name="physics" %}
|
||||||
{% for exam in object.physics_exams.all %}
|
{% include "exam_list.html#exam-list" %}
|
||||||
<li><a href="{% url 'physics:exam_overview' exam.pk %}">{{ exam }}</a> - <a href="{% url 'physics:exam_update' exam.pk %}">(Edit)</a></li>
|
{% endwith %}
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a href="{% url 'physics:exam_list_collection' object.pk %}">View exam list</a>
|
<a href="{% url 'physics:exam_list_collection' object.pk %}">View exam list</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if object.sbas_exams.all %}
|
{% if object.sbas_exams.all %}
|
||||||
<h2>SBAs Exams:</h2>
|
<h2>SBAs Exams:</h2>
|
||||||
<ul>
|
{% with exams=object.sbas_exams.all app_name="sbas" %}
|
||||||
{% for exam in object.sbas_exams.all %}
|
{% include "exam_list.html#exam-list" %}
|
||||||
<li><a href="{% url 'sbas:exam_overview' exam.pk %}">{{ exam }}</a> - <a href="{% url 'sbas:exam_update' exam.pk %}">(Edit)</a></li>
|
{% endwith %}
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<a href="{% url 'sbas:exam_list_collection' object.pk %}">View exam list</a>
|
<a href="{% url 'sbas:exam_list_collection' object.pk %}">View exam list</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
{% include 'exam_overview_js.html' %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# serializers.py
|
|
||||||
from rest_framework import serializers, permissions
|
|
||||||
|
|
||||||
|
|
||||||
from .models import Exam
|
|
||||||
|
|
||||||
class ExamSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Exam
|
|
||||||
fields = ('name', 'id', 'active', "publish_results")
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
@@ -94,10 +94,6 @@ from reversion.views import RevisionMixin
|
|||||||
import reversion
|
import reversion
|
||||||
|
|
||||||
|
|
||||||
from rest_framework import viewsets
|
|
||||||
|
|
||||||
from .serializers import ExamSerializer
|
|
||||||
|
|
||||||
from zipview.views import BaseZipView
|
from zipview.views import BaseZipView
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@@ -1005,12 +1001,6 @@ class ExamGroupsUpdate(ExamGroupsUpdateBase):
|
|||||||
model = Exam
|
model = Exam
|
||||||
form_class = ExamGroupsForm
|
form_class = ExamGroupsForm
|
||||||
|
|
||||||
|
|
||||||
# class ExamViewSet(RevisionMixin, viewsets.ModelViewSet):
|
|
||||||
# queryset = Exam.objects.all().order_by("name")
|
|
||||||
# serializer_class = ExamSerializer
|
|
||||||
|
|
||||||
|
|
||||||
def question_json_unbased(request, pk):
|
def question_json_unbased(request, pk):
|
||||||
"""
|
"""
|
||||||
No (file based) caching is enabled for unbased quesitons
|
No (file based) caching is enabled for unbased quesitons
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ from generic.views import (
|
|||||||
exam_inactive,
|
exam_inactive,
|
||||||
)
|
)
|
||||||
|
|
||||||
from rest_framework import viewsets, permissions
|
|
||||||
from rest_framework.pagination import PageNumberPagination
|
|
||||||
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
from .forms import ExamGroupsForm, ExamMarkerForm, UserAnswerForm, ExamAuthorForm, ExamForm
|
from .forms import ExamGroupsForm, ExamMarkerForm, UserAnswerForm, ExamAuthorForm, ExamForm
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,6 @@ INSTALLED_APPS = [
|
|||||||
"django.contrib.staticfiles",
|
"django.contrib.staticfiles",
|
||||||
"django.contrib.postgres",
|
"django.contrib.postgres",
|
||||||
"dbbackup",
|
"dbbackup",
|
||||||
"rest_framework",
|
|
||||||
"tinymce",
|
"tinymce",
|
||||||
"django_unused_media",
|
"django_unused_media",
|
||||||
"django_htmx",
|
"django_htmx",
|
||||||
@@ -83,6 +82,7 @@ INSTALLED_APPS = [
|
|||||||
'django_jsonforms',
|
'django_jsonforms',
|
||||||
'django_svelte_jsoneditor',
|
'django_svelte_jsoneditor',
|
||||||
'django_psutil_dash',
|
'django_psutil_dash',
|
||||||
|
'template_partials',
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|||||||
+4
-2
@@ -34,7 +34,8 @@ from generic import views as generic_views
|
|||||||
from django.conf.urls import handler400, handler403, handler404, handler500
|
from django.conf.urls import handler400, handler403, handler404, handler500
|
||||||
|
|
||||||
from .api import api
|
from .api import api
|
||||||
from autocomplete import HTMXAutoComplete
|
from autocomplete import urls as autocomplete_urls
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -153,7 +154,8 @@ urlpatterns = [
|
|||||||
path("privacy/", views.privacy_view, name="privacy"),
|
path("privacy/", views.privacy_view, name="privacy"),
|
||||||
path("about/", views.about_view, name="about"),
|
path("about/", views.about_view, name="about"),
|
||||||
# path('select2/', include('select2.urls')),
|
# path('select2/', include('select2.urls')),
|
||||||
*HTMXAutoComplete.url_dispatcher('ac'),
|
|
||||||
|
path("ac/", autocomplete_urls),
|
||||||
path('psutil/', psutil_urlpatterns(), name='psutil'),
|
path('psutil/', psutil_urlpatterns(), name='psutil'),
|
||||||
path("cimar/", views.cimar, name="cimar"),
|
path("cimar/", views.cimar, name="cimar"),
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
# serializers.py
|
|
||||||
from rest_framework import serializers, permissions
|
|
||||||
|
|
||||||
|
|
||||||
from .models import Exam, Answer, Rapid, UserAnswer
|
|
||||||
|
|
||||||
class ExamSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Exam
|
|
||||||
fields = ('name', 'id', 'active', "publish_results")
|
|
||||||
|
|
||||||
class QuestionAnswerSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
#question = serializers.HyperlinkedRelatedField(view_name='rapid-detail',
|
|
||||||
# read_only=True
|
|
||||||
# )
|
|
||||||
class Meta:
|
|
||||||
model = Answer
|
|
||||||
fields = ('id', 'question', 'answer', "answer_compare", "status")
|
|
||||||
view_name = "rapid-exam"
|
|
||||||
|
|
||||||
class UserAnswerSerializer(serializers.HyperlinkedModelSerializer):
|
|
||||||
exam = serializers.HyperlinkedRelatedField(view_name='rapid-exam-detail',
|
|
||||||
read_only=True
|
|
||||||
)
|
|
||||||
class Meta:
|
|
||||||
model = UserAnswer
|
|
||||||
fields = ('id', 'question', 'normal', "answer", "answer_compare", "cid", "user", "exam", "created", "updated")
|
|
||||||
|
|
||||||
class RapidSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Rapid
|
|
||||||
fields = ('id', 'question', 'normal', "abnormality", "region", "laterality", "examination", "exams", "author", "open_access")
|
|
||||||
view_name = "rapid-detail"
|
|
||||||
|
|
||||||
class RapidLateralitySerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Rapid
|
|
||||||
fields = ('id', "laterality")
|
|
||||||
view_name = "rapid-laterality"
|
|
||||||
@@ -83,18 +83,6 @@ from django.forms.models import model_to_dict
|
|||||||
from rapids.forms import RapidCreationDefaultForm
|
from rapids.forms import RapidCreationDefaultForm
|
||||||
from rapids.models import RapidCreationDefault
|
from rapids.models import RapidCreationDefault
|
||||||
|
|
||||||
|
|
||||||
from rest_framework import viewsets, permissions, mixins
|
|
||||||
from rest_framework.pagination import PageNumberPagination
|
|
||||||
|
|
||||||
from .serializers import (
|
|
||||||
ExamSerializer,
|
|
||||||
QuestionAnswerSerializer,
|
|
||||||
RapidLateralitySerializer,
|
|
||||||
RapidSerializer,
|
|
||||||
UserAnswerSerializer,
|
|
||||||
)
|
|
||||||
|
|
||||||
from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin
|
from generic.mixins import CheckCanEditMixin, SuperuserRequiredMixin
|
||||||
|
|
||||||
from dal import autocomplete
|
from dal import autocomplete
|
||||||
@@ -797,92 +785,6 @@ class UserAnswerDelete(SuperuserRequiredMixin, DeleteView):
|
|||||||
success_url = reverse_lazy("rapids:user_answer_table_view")
|
success_url = reverse_lazy("rapids:user_answer_table_view")
|
||||||
|
|
||||||
|
|
||||||
class LargeResultsSetPagination(PageNumberPagination):
|
|
||||||
page_size = 1000
|
|
||||||
page_size_query_param = "page_size"
|
|
||||||
max_page_size = 10000
|
|
||||||
|
|
||||||
|
|
||||||
class StandardResultsSetPagination(PageNumberPagination):
|
|
||||||
page_size = 100
|
|
||||||
page_size_query_param = "page_size"
|
|
||||||
max_page_size = 1000
|
|
||||||
|
|
||||||
|
|
||||||
class ExamViewSet(RevisionMixin, viewsets.ModelViewSet):
|
|
||||||
# queryset = Exam.objects.all().order_by('name')
|
|
||||||
serializer_class = ExamSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
"""
|
|
||||||
This view should return a list exams available to a user.
|
|
||||||
"""
|
|
||||||
user = self.request.user
|
|
||||||
if user.groups.filter(name="rapid_checker").exists():
|
|
||||||
return Exam.objects.filter(archive=False).order_by("name")
|
|
||||||
|
|
||||||
return Exam.objects.filter(author__id=user.id, archive=False).order_by("name")
|
|
||||||
|
|
||||||
|
|
||||||
# class QuestionAnswerViewSet(viewsets.ModelViewSet):
|
|
||||||
# queryset = Answer.objects.all() # .order_by('name')
|
|
||||||
# serializer_class = QuestionAnswerSerializer
|
|
||||||
# permission_classes = [permissions.IsAuthenticated]
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class UserAnswerViewSet(viewsets.ModelViewSet):
|
|
||||||
# queryset = UserAnswer.objects.all() # .order_by('name')
|
|
||||||
# serializer_class = UserAnswerSerializer
|
|
||||||
# permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
|
|
||||||
# class RapidViewSet(
|
|
||||||
# RevisionMixin,
|
|
||||||
# mixins.CreateModelMixin,
|
|
||||||
# mixins.RetrieveModelMixin,
|
|
||||||
# mixins.UpdateModelMixin,
|
|
||||||
# mixins.ListModelMixin,
|
|
||||||
# mixins.DestroyModelMixin,
|
|
||||||
# viewsets.GenericViewSet,
|
|
||||||
# ):
|
|
||||||
# queryset = Rapid.objects.all() # .order_by('name')
|
|
||||||
# serializer_class = RapidSerializer
|
|
||||||
# permission_classes = [permissions.IsAuthenticated]
|
|
||||||
# pagination_class = StandardResultsSetPagination
|
|
||||||
|
|
||||||
|
|
||||||
# class AddSuggestedAnswer(LoginRequiredMixin, CreateView):
|
|
||||||
# model = QuestionNote
|
|
||||||
# form_class = QuestionNoteForm
|
|
||||||
#
|
|
||||||
# #fields = ("author", "note_type", "note")
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# def get_form_kwargs(self):
|
|
||||||
# kwargs = super(AddQuestionNote, self).get_form_kwargs()
|
|
||||||
# # update the kwargs for the form init method with yours
|
|
||||||
# kwargs.update(self.kwargs) # self.kwargs contains all url conf params
|
|
||||||
# return kwargs
|
|
||||||
#
|
|
||||||
# def get_initial(self):
|
|
||||||
# pk = self.kwargs["pk"]
|
|
||||||
# question_type = self.kwargs["question_type"]
|
|
||||||
# if question_type == "rapid":
|
|
||||||
# question = Rapid
|
|
||||||
# content_type = ContentType.objects.get(model="rapid")
|
|
||||||
# elif question_type == "anatomy":
|
|
||||||
# question = AnatomyQuestion
|
|
||||||
# content_type = ContentType.objects.get(model="anatomyquestion")
|
|
||||||
# elif question_type == "long":
|
|
||||||
# question = Long
|
|
||||||
# content_type = ContentType.objects.get(model="long")
|
|
||||||
# else:
|
|
||||||
# raise PermissionError()
|
|
||||||
#
|
|
||||||
# get_object_or_404(question, pk=pk)
|
|
||||||
# return { "content_type" : content_type,
|
|
||||||
# "object_id" : pk }
|
|
||||||
|
|
||||||
GenericViews = GenericViewBase("rapids", Rapid, UserAnswer, Exam)
|
GenericViews = GenericViewBase("rapids", Rapid, UserAnswer, Exam)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -51,4 +51,5 @@ pylibjpeg-libjpeg
|
|||||||
git+https://github.com/xkjq/django-jsonforms.git@bump-json-editor-lib
|
git+https://github.com/xkjq/django-jsonforms.git@bump-json-editor-lib
|
||||||
django_svelte_jsoneditor
|
django_svelte_jsoneditor
|
||||||
psutil
|
psutil
|
||||||
django-psutil-dash
|
django-psutil-dash
|
||||||
|
django-template-partials
|
||||||
@@ -54,9 +54,6 @@ from generic.views import (
|
|||||||
exam_inactive,
|
exam_inactive,
|
||||||
)
|
)
|
||||||
|
|
||||||
from rest_framework import viewsets, permissions
|
|
||||||
from rest_framework.pagination import PageNumberPagination
|
|
||||||
|
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
from .tables import QuestionTable, UserAnswerTable
|
from .tables import QuestionTable, UserAnswerTable
|
||||||
@@ -411,22 +408,6 @@ class ExamDelete(AuthorOrCheckerRequiredMixin, ExamDeleteBase):
|
|||||||
model = Exam
|
model = Exam
|
||||||
|
|
||||||
|
|
||||||
# class ExamViewSet(RevisionMixin, viewsets.ModelViewSet):
|
|
||||||
# # queryset = Exam.objects.all().order_by('name')
|
|
||||||
# serializer_class = ExamSerializer
|
|
||||||
# permission_classes = [permissions.IsAuthenticated]
|
|
||||||
#
|
|
||||||
# def get_queryset(self):
|
|
||||||
# """
|
|
||||||
# This view should return a list exams available to a user.
|
|
||||||
# """
|
|
||||||
# user = self.request.user
|
|
||||||
# if user.groups.filter(name="sbas_checker").exists():
|
|
||||||
# return Exam.objects.all()
|
|
||||||
#
|
|
||||||
# return Exam.objects.filter(author__id=user.id)
|
|
||||||
|
|
||||||
|
|
||||||
class ExamAuthorUpdate(
|
class ExamAuthorUpdate(
|
||||||
RevisionMixin, CheckCanEditMixin, LoginRequiredMixin, AuthorRequiredMixin, UpdateView
|
RevisionMixin, CheckCanEditMixin, LoginRequiredMixin, AuthorRequiredMixin, UpdateView
|
||||||
):
|
):
|
||||||
|
|||||||
+102
-94
@@ -1,102 +1,31 @@
|
|||||||
{% extends app_name|add:'/base.html' %}
|
{% extends app_name|add:'/base.html' %}
|
||||||
|
|
||||||
{% block content %}
|
{% load partials %}
|
||||||
<h1>Examinations</h1>
|
|
||||||
|
|
||||||
{% if collection %}
|
{% partialdef exam-list %}
|
||||||
<h2>Collection: {{collection.name}}</h2>
|
<ul class="exam-list exam-list-active">
|
||||||
{% endif %}
|
{% for exam in exams %}
|
||||||
|
<li class="exam-item">
|
||||||
<details class="help-text">
|
<a href="{% url app_name|add:':exam_overview' pk=exam.pk %}" class="flex-col-2 exam-name">{{exam}}</a>
|
||||||
<summary><i class="bi bi-info-circle"></i> Help</summary>
|
{% if marking %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}" class="flex-col-half">Mark</a>{% endif %}
|
||||||
{% if collection %}
|
<span class="flex-col">
|
||||||
<p>This page shows all the examinations within the collection "{{collection.name}}".</p>
|
<a href="{% url app_name|add:':exam_cids' exam_id=exam.pk %}">Candidates</a> <span class="candidate-counts">[<span title="Number of active CID users">
|
||||||
{% else %}
|
{{exam.valid_cid_users.count}}
|
||||||
<p>This page shows the currently active examinations (that you have access to manage).</p>
|
</span> / <span title="Number of active User users">{{exam.valid_user_users.count}}]</span></span>
|
||||||
{% endif %}
|
</span>
|
||||||
|
<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}" class="flex-col-half">Scores</a>
|
||||||
|
<input type="checkbox" id="active-{{exam.pk}}" class="exam-active-switch" data-posturl="{% url app_name|add:':exam_toggle_active' pk=exam.pk %}" {% if exam.active %}checked{% endif %}>
|
||||||
|
<label for="active-{{exam.pk}}" class="flex-col icon-container active-icon" title="Click to toggle active state">Exam Active</label>
|
||||||
|
<input type="checkbox" id="published-{{exam.pk}}" class="exam-publish-results-switch" data-posturl="{% url app_name|add:':exam_toggle_results_published' pk=exam.pk %}" {% if exam.publish_results %}checked{% endif %}>
|
||||||
|
<label for="published-{{exam.pk}}" class="flex-col icon-container published-icon" title="Click to toggle published state">Results Published</label>
|
||||||
|
<a href="{% url app_name|add:':exam_update' pk=exam.pk %}" class="flex-shrink exam-list-edit-button"><i class="bi bi-pencil-square"></i></a>
|
||||||
|
<input type="checkbox" id="archived-{{exam.pk}}" class="exam-archived-switch" data-posturl="{% url app_name|add:':exam_toggle_archived' pk=exam.pk %}" {% if exam.archive %}checked{% endif %}>
|
||||||
|
<label for="archived-{{exam.pk}}" class="flex-shrink icon-archive archived-icon" title="Click to toggle archived state"><i class="bi bi-archive"></i></label>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
<p>Exams that are active will be available for candidates to take.</p>
|
|
||||||
|
|
||||||
<p>Once candidates have completed the exam (or submitted some answers) they will immediately be able to view their answers on the platoform. They will not be able to see the correct answers (or their scores) until the exams results have been published.</p>
|
|
||||||
|
|
||||||
<p>A users submitted answers will remain available to the user until the exam is archived. Once an exam is archived the user will no longer be able to view their submitted answers.</p>
|
|
||||||
|
|
||||||
<p>Supervisors will have access to all exam results (including archived exams) for which they have access (when "results supervisor visible" is set to true or the user has shared their results).</p>
|
|
||||||
</details>
|
|
||||||
<div class="{{app_name}}">
|
|
||||||
Exams:<br/>
|
|
||||||
<ul class="exam-list exam-list-active">
|
|
||||||
{% for exam in exams %}
|
|
||||||
<li class="exam-item">
|
|
||||||
<a href="{% url app_name|add:':exam_overview' pk=exam.pk %}" class="flex-col-2 exam-name">{{exam}}</a>
|
|
||||||
{% if marking %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}" class="flex-col-half">Mark</a>{% endif %}
|
|
||||||
<span class="flex-col">
|
|
||||||
<a href="{% url app_name|add:':exam_cids' exam_id=exam.pk %}">Candidates</a> <span class="candidate-counts">[<span title="Number of active CID users">
|
|
||||||
{{exam.valid_cid_users.count}}
|
|
||||||
</span> / <span title="Number of active User users">{{exam.valid_user_users.count}}]</span></span>
|
|
||||||
</span>
|
|
||||||
<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}" class="flex-col-half">Scores</a>
|
|
||||||
<input type="checkbox" id="active-{{exam.pk}}" class="exam-active-switch" data-posturl="{% url app_name|add:':exam_toggle_active' pk=exam.pk %}" {% if exam.active %}checked{% endif %}>
|
|
||||||
<label for="active-{{exam.pk}}" class="flex-col icon-container active-icon" title="Click to toggle active state">Exam Active</label>
|
|
||||||
<input type="checkbox" id="published-{{exam.pk}}" class="exam-publish-results-switch" data-posturl="{% url app_name|add:':exam_toggle_results_published' pk=exam.pk %}" {% if exam.publish_results %}checked{% endif %}>
|
|
||||||
<label for="published-{{exam.pk}}" class="flex-col icon-container published-icon" title="Click to toggle published state">Results Published</label>
|
|
||||||
<a href="{% url app_name|add:':exam_update' pk=exam.pk %}" class="flex-shrink exam-list-edit-button"><i class="bi bi-pencil-square"></i></a>
|
|
||||||
<input type="checkbox" id="archived-{{exam.pk}}" class="exam-archived-switch" data-posturl="{% url app_name|add:':exam_toggle_archived' pk=exam.pk %}" {% if exam.archive %}checked{% endif %}>
|
|
||||||
<label for="archived-{{exam.pk}}" class="flex-shrink icon-archive archived-icon" title="Click to toggle archived state"><i class="bi bi-archive"></i></label>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% comment %} Inactive exams:<br/>
|
|
||||||
<ul class="exam-list exam-list-inactive">
|
|
||||||
{% for exam in exams %}
|
|
||||||
{% if not exam.active %}
|
|
||||||
<li class="exam-item">
|
|
||||||
<span class="flex-col-2">
|
|
||||||
<a href="{% url app_name|add:':exam_overview' pk=exam.pk %}" class="exam-name">{{exam}}</a>
|
|
||||||
{% if exam.examcollection %}
|
|
||||||
<a href='{% url "generic:examcollection_detail" exam.examcollection_id %}' title="This exam is part of the collection {{exam.examcollection.name}}"><i class="bi bi-collection"></i></a>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
|
|
||||||
{% if marking %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}" class="flex-col-half" title="Click to mark exam">Mark</a>{% endif %}
|
|
||||||
<span class="flex-col">
|
|
||||||
<a href="{% url app_name|add:':exam_cids' exam_id=exam.pk %}" title="Click to manage candidates">Candidates</a>
|
|
||||||
<span class="candidate-counts">
|
|
||||||
[<span title="Number of active CID users">{{exam.valid_cid_users.count}}</span>
|
|
||||||
/
|
|
||||||
<span title="Number of active User users">{{exam.valid_user_users.count}}]
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}" class="flex-col-half">Scores</a>
|
|
||||||
<input type="checkbox" id="active-{{exam.pk}}" class="exam-active-switch" data-posturl="{% url app_name|add:':exam_toggle_active' pk=exam.pk %}" {% if exam.active %}checked{% endif %}>
|
|
||||||
<label for="active-{{exam.pk}}" class="flex-col icon-container active-icon" title="Click to toggle active state">Exam Active</label>
|
|
||||||
<input type="checkbox" id="{{exam.pk}}-pub" class="exam-publish-results-switch" data-posturl="{% url app_name|add:':exam_toggle_results_published' pk=exam.pk %}" {% if exam.publish_results %}checked{% endif %}>
|
|
||||||
<label for="{{exam.pk}}-pub" class="flex-col icon-container published-icon">Results Published</label>
|
|
||||||
<a href="{% url app_name|add:':exam_update' pk=exam.pk %}" class="flex-shrink exam-list-edit-button" title="Click to edit exam"><i class="bi bi-pencil-square"></i></a>
|
|
||||||
<input type="checkbox" id="archived-{{exam.pk}}" class="exam-archived-switch" data-posturl="{% url app_name|add:':exam_toggle_archived' pk=exam.pk %}" {% if exam.archive %}checked{% endif %}>
|
|
||||||
<label for="archived-{{exam.pk}}" class="flex-shrink icon-archive archived-icon" title="Click to toggle archived state"><i class="bi bi-archive"></i></label>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</ul> {% endcomment %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if collection %}
|
|
||||||
|
|
||||||
{% else %}
|
|
||||||
{% if view_all %}
|
|
||||||
<a href="{% url app_name|add:':exam_list' %}" >Hide archived</a>
|
|
||||||
{% else %}
|
|
||||||
<a href="{% url app_name|add:':exam_list_all' %}" title="Show all exams (including archived)">View all</a>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% include 'exam_overview_js.html' %}
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.candidate-counts {
|
.candidate-counts {
|
||||||
@@ -170,6 +99,85 @@
|
|||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
{% endpartialdef %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>Examinations</h1>
|
||||||
|
|
||||||
|
{% if collection %}
|
||||||
|
<h2>Collection: {{collection.name}}</h2>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<details class="help-text">
|
||||||
|
<summary><i class="bi bi-info-circle"></i> Help</summary>
|
||||||
|
{% if collection %}
|
||||||
|
<p>This page shows all the examinations within the collection "{{collection.name}}".</p>
|
||||||
|
{% else %}
|
||||||
|
<p>This page shows the currently active examinations (that you have access to manage).</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
<p>Exams that are active will be available for candidates to take.</p>
|
||||||
|
|
||||||
|
<p>Once candidates have completed the exam (or submitted some answers) they will immediately be able to view their answers on the platoform. They will not be able to see the correct answers (or their scores) until the exams results have been published.</p>
|
||||||
|
|
||||||
|
<p>A users submitted answers will remain available to the user until the exam is archived. Once an exam is archived the user will no longer be able to view their submitted answers.</p>
|
||||||
|
|
||||||
|
<p>Supervisors will have access to all exam results (including archived exams) for which they have access (when "results supervisor visible" is set to true or the user has shared their results).</p>
|
||||||
|
</details>
|
||||||
|
<div class="{{app_name}}">
|
||||||
|
Exams:<br/>
|
||||||
|
{% partial exam-list %}
|
||||||
|
|
||||||
|
{% comment %} Inactive exams:<br/>
|
||||||
|
<ul class="exam-list exam-list-inactive">
|
||||||
|
{% for exam in exams %}
|
||||||
|
{% if not exam.active %}
|
||||||
|
<li class="exam-item">
|
||||||
|
<span class="flex-col-2">
|
||||||
|
<a href="{% url app_name|add:':exam_overview' pk=exam.pk %}" class="exam-name">{{exam}}</a>
|
||||||
|
{% if exam.examcollection %}
|
||||||
|
<a href='{% url "generic:examcollection_detail" exam.examcollection_id %}' title="This exam is part of the collection {{exam.examcollection.name}}"><i class="bi bi-collection"></i></a>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{% if marking %}<a href="{% url app_name|add:':mark_overview' pk=exam.pk %}" class="flex-col-half" title="Click to mark exam">Mark</a>{% endif %}
|
||||||
|
<span class="flex-col">
|
||||||
|
<a href="{% url app_name|add:':exam_cids' exam_id=exam.pk %}" title="Click to manage candidates">Candidates</a>
|
||||||
|
<span class="candidate-counts">
|
||||||
|
[<span title="Number of active CID users">{{exam.valid_cid_users.count}}</span>
|
||||||
|
/
|
||||||
|
<span title="Number of active User users">{{exam.valid_user_users.count}}]
|
||||||
|
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<a href="{% url app_name|add:':exam_scores_all' pk=exam.pk %}" class="flex-col-half">Scores</a>
|
||||||
|
<input type="checkbox" id="active-{{exam.pk}}" class="exam-active-switch" data-posturl="{% url app_name|add:':exam_toggle_active' pk=exam.pk %}" {% if exam.active %}checked{% endif %}>
|
||||||
|
<label for="active-{{exam.pk}}" class="flex-col icon-container active-icon" title="Click to toggle active state">Exam Active</label>
|
||||||
|
<input type="checkbox" id="{{exam.pk}}-pub" class="exam-publish-results-switch" data-posturl="{% url app_name|add:':exam_toggle_results_published' pk=exam.pk %}" {% if exam.publish_results %}checked{% endif %}>
|
||||||
|
<label for="{{exam.pk}}-pub" class="flex-col icon-container published-icon">Results Published</label>
|
||||||
|
<a href="{% url app_name|add:':exam_update' pk=exam.pk %}" class="flex-shrink exam-list-edit-button" title="Click to edit exam"><i class="bi bi-pencil-square"></i></a>
|
||||||
|
<input type="checkbox" id="archived-{{exam.pk}}" class="exam-archived-switch" data-posturl="{% url app_name|add:':exam_toggle_archived' pk=exam.pk %}" {% if exam.archive %}checked{% endif %}>
|
||||||
|
<label for="archived-{{exam.pk}}" class="flex-shrink icon-archive archived-icon" title="Click to toggle archived state"><i class="bi bi-archive"></i></label>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul> {% endcomment %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% if collection %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{% if view_all %}
|
||||||
|
<a href="{% url app_name|add:':exam_list' %}" >Hide archived</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url app_name|add:':exam_list_all' %}" title="Show all exams (including archived)">View all</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% include 'exam_overview_js.html' %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user