429 lines
14 KiB
Python
429 lines
14 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect
|
|
|
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
|
from django.views.decorators.csrf import csrf_exempt
|
|
|
|
from django.http import Http404, JsonResponse
|
|
from django.http import HttpResponseRedirect, HttpResponse
|
|
|
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
|
|
|
|
from django.utils.decorators import method_decorator
|
|
|
|
|
|
from django.core.cache import cache
|
|
|
|
import json
|
|
|
|
from django.views import View
|
|
|
|
from .forms import (
|
|
ExaminationForm,
|
|
)
|
|
|
|
from .models import Examination
|
|
|
|
from rapids.models import Rapid as RapidQuestion
|
|
from rapids.models import Exam as RapidExam
|
|
from longs.models import Long as LongQuestion
|
|
from longs.models import Exam as LongExam
|
|
from anatomy.models import AnatomyQuestion as AnatomyQuestion
|
|
from anatomy.models import Exam as AnatomyExam
|
|
|
|
from django.db.models import Case, When
|
|
from django.conf import settings
|
|
|
|
from datetime import datetime
|
|
import os
|
|
|
|
|
|
# Create your views here.
|
|
@login_required
|
|
def create_examination(request):
|
|
form = ExaminationForm(request.POST or None)
|
|
if form.is_valid():
|
|
instance = form.save()
|
|
return HttpResponse(
|
|
'<script>opener.closePopup(window, "%s", "%s", "#id_examination");</script>'
|
|
% (instance.pk, instance)
|
|
)
|
|
return render(
|
|
request, "rapids/create_simple.html", {"form": form, "name": "Examination"}
|
|
)
|
|
|
|
@csrf_exempt
|
|
def get_examination_id(request):
|
|
if request.is_ajax():
|
|
examination_name = request.GET["examination_name"]
|
|
examination_id = Examination.objects.get(name=examination_name).id
|
|
data = {
|
|
"examination_id": examination_id,
|
|
}
|
|
return HttpResponse(json.dumps(data), content_type="application/json")
|
|
return HttpResponse("/")
|
|
|
|
# Generic view to dispatch to indivuals app views
|
|
@login_required
|
|
def generic_exam_json_edit(request):
|
|
if request.is_ajax() and request.method == "POST":
|
|
question_type = request.POST.get("type")
|
|
|
|
if question_type == "rapid":
|
|
Exam = RapidExam
|
|
Question = RapidQuestion
|
|
elif question_type == "long":
|
|
Exam = LongExam
|
|
Question = LongQuestion
|
|
elif question_type == "anatomy":
|
|
Exam = AnatomyExam
|
|
Question = AnatomyQuestion
|
|
else:
|
|
data = {"status": "error"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
|
exam = get_object_or_404(Exam, pk=request.POST.get("exam_id"))
|
|
|
|
if "add_exam_questions" in request.POST:
|
|
question_ids = json.loads(request.POST.get("add_exam_questions"))
|
|
question_objects = Question.objects.filter(pk__in=question_ids)
|
|
|
|
for i in question_ids:
|
|
exam.exam_questions.add(i)
|
|
#exam.exam_questions.add(question_objects)
|
|
exam.save()
|
|
data = {"status": "success"}
|
|
return JsonResponse(data, status=200)
|
|
|
|
if "set_open_access" in request.POST:
|
|
if request.POST.get("set_open_access") == "true":
|
|
state = True
|
|
else:
|
|
state = False
|
|
|
|
questions_changed = []
|
|
for q in exam.exam_questions.all():
|
|
q.open_access = state
|
|
q.save()
|
|
questions_changed.append(q.pk)
|
|
|
|
data = {"status": "success", "questions": questions_changed, "state": state}
|
|
return JsonResponse(data, status=200)
|
|
|
|
if "set_exam_order" in request.POST:
|
|
new_order = json.loads(request.POST.get("set_exam_order"))
|
|
|
|
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(new_order)])
|
|
objects = Question.objects.filter(pk__in=new_order).order_by(preserved)
|
|
|
|
if len(objects) != exam.exam_questions.count():
|
|
data = {"status": "error, count does not match"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
exam.exam_questions.set(objects)
|
|
exam.save()
|
|
data = {"status": "success"}
|
|
return JsonResponse(data, status=200)
|
|
|
|
|
|
data = {"status": "error, unknown request"}
|
|
return JsonResponse(data, status=400)
|
|
else:
|
|
data = {"status": "error"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
|
|
|
class ExamViews(View, LoginRequiredMixin):
|
|
def __init__(self, exam, question, app, question_type, loadJsonAnswer):
|
|
self.Exam = exam
|
|
self.Question = question
|
|
self.app_name = app
|
|
self.question_type = question_type
|
|
self.loadJsonAnswer = loadJsonAnswer
|
|
|
|
@method_decorator(login_required)
|
|
def exam_toggle_results_published(self, request, pk):
|
|
if request.is_ajax() and request.method == "POST":
|
|
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
exam.publish_results = (
|
|
True if request.POST.get("publish_results") == "true" else False
|
|
)
|
|
exam.save()
|
|
data = {"status": "success", "publish_results": exam.publish_results}
|
|
return JsonResponse(data, status=200)
|
|
else:
|
|
data = {"status": "error"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
|
|
@method_decorator(login_required)
|
|
def exam_toggle_active(self, request, pk):
|
|
if request.is_ajax() and request.method == "POST":
|
|
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
exam.active = True if request.POST.get("active") == "true" else False
|
|
exam.save()
|
|
data = {"status": "success", "active": exam.active}
|
|
return JsonResponse(data, status=200)
|
|
else:
|
|
data = {"status": "error"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
@method_decorator(login_required)
|
|
def exam_json_recreate(self, request, pk):
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
exam.recreate_json = True
|
|
exam.save()
|
|
|
|
return redirect("{}:exam_overview".format(self.app_name), pk=pk)
|
|
|
|
@method_decorator(login_required)
|
|
def question_json_recreate(self, request, pk):
|
|
question = get_object_or_404(self.Question, pk=pk)
|
|
|
|
question.recreate_json = True
|
|
question.save()
|
|
|
|
return redirect("{}:question_detail".format(self.app_name), pk=pk)
|
|
|
|
@method_decorator(login_required)
|
|
def exam_list(self, request):
|
|
exams = self.Exam.objects.all()
|
|
return render(request, "{}/exam_list.html".format(self.app_name), {"exams": exams})
|
|
|
|
|
|
@method_decorator(login_required)
|
|
def exam_overview(self, request, pk):
|
|
#print(Exam.objects.all())
|
|
#exams = Exam.objects.all()
|
|
#print("test", Exam.objects.all().get(id=pk))
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
questions = exam.exam_questions.all()
|
|
|
|
question_number = len(questions)
|
|
|
|
return render(
|
|
request,
|
|
"{}/exam_overview.html".format(self.app_name),
|
|
{"exam": exam, "questions": questions, "question_number": question_number},
|
|
)
|
|
|
|
@method_decorator(login_required)
|
|
def exam_json_edit(self, request, pk):
|
|
if request.is_ajax() and request.method == "POST":
|
|
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
if "add_exam_questions" in request.POST:
|
|
question_ids = json.loads(request.POST.get("add_exam_questions"))
|
|
question_objects = self.Question.objects.filter(pk__in=question_ids)
|
|
|
|
exam.exam_questions.add(question_objects)
|
|
exam.save()
|
|
data = {"status": "success"}
|
|
return JsonResponse(data, status=200)
|
|
|
|
if "set_open_access" in request.POST:
|
|
if request.POST.get("set_open_access") == "true":
|
|
state = True
|
|
else:
|
|
state = False
|
|
|
|
questions_changed = []
|
|
for q in exam.exam_questions.all():
|
|
q.open_access = state
|
|
q.save()
|
|
questions_changed.append(q.pk)
|
|
|
|
data = {"status": "success", "questions": questions_changed, "state": state}
|
|
return JsonResponse(data, status=200)
|
|
|
|
if "set_exam_order" in request.POST:
|
|
new_order = json.loads(request.POST.get("set_exam_order"))
|
|
|
|
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(new_order)])
|
|
objects = self.Question.objects.filter(pk__in=new_order).order_by(preserved)
|
|
|
|
if len(objects) != exam.exam_questions.count():
|
|
data = {"status": "error, count does not match"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
exam.exam_questions.set(objects)
|
|
exam.save()
|
|
data = {"status": "success"}
|
|
return JsonResponse(data, status=200)
|
|
|
|
|
|
data = {"status": "error, unknown request"}
|
|
return JsonResponse(data, status=400)
|
|
else:
|
|
data = {"status": "error"}
|
|
return JsonResponse(data, status=400)
|
|
|
|
@method_decorator(login_required)
|
|
def mark_overview(self, request, pk):
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
questions = exam.exam_questions.all()
|
|
|
|
return render(
|
|
request, "{}/mark_overview.html".format(self.app_name), {"exam": exam, "questions": questions}
|
|
)
|
|
|
|
@method_decorator(login_required)
|
|
def index(self, request):
|
|
exams = self.Exam.objects.all()
|
|
return render(request, "{}/index.html".format(self.app_name), {"exams": exams})
|
|
|
|
@method_decorator(login_required)
|
|
def exam_question_detail(self, request, pk, sk):
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
question = exam.exam_questions.all()[sk]
|
|
|
|
exam_length = len(exam.exam_questions.all())
|
|
|
|
pos = exam.get_question_index(question) + 1
|
|
|
|
previous = -1
|
|
if sk > 0:
|
|
previous = sk - 1
|
|
next = sk + 1
|
|
if sk == exam_length - 1:
|
|
next = False
|
|
|
|
return render(
|
|
request,
|
|
"{}/question_detail.html".format(self.app_name),
|
|
{
|
|
"question": question,
|
|
"exam": exam,
|
|
"next": next,
|
|
"previous": previous,
|
|
"exam_length": exam_length,
|
|
"pos": pos,
|
|
},
|
|
)
|
|
|
|
def active_exams(self, request, json=True):
|
|
exams = self.Exam.objects.all()
|
|
|
|
active_exams = {"exams": []}
|
|
|
|
for exam in exams:
|
|
if exam.active:
|
|
if exam.json_creation_time:
|
|
creation_time = exam.json_creation_time.isoformat()
|
|
else:
|
|
creation_time = "None"
|
|
|
|
obj = {
|
|
"name": exam.get_exam_name(),
|
|
"url": request.build_absolute_uri(exam.get_json_url()),
|
|
"type": self.question_type,
|
|
"eid": "{}/{}".format(self.question_type, exam.pk),
|
|
"json_creation_time": creation_time
|
|
}
|
|
|
|
if self.question_type == "long":
|
|
h = {}
|
|
for question in exam.exam_questions.all():
|
|
h[question.pk] = question.json_creation_time.isoformat()
|
|
obj["multi_question_json"] = h
|
|
active_exams["exams"].append( obj )
|
|
|
|
if json == False:
|
|
return active_exams["exams"]
|
|
|
|
return JsonResponse(active_exams)
|
|
|
|
@method_decorator(csrf_exempt)
|
|
def postExamAnswers(self, request):
|
|
if request.is_ajax and request.method == "POST":
|
|
|
|
n = 0
|
|
|
|
for answer in json.loads(request.POST.get("answers")):
|
|
ret = self.loadJsonAnswer(answer)
|
|
|
|
#if ret is not True:
|
|
# return ret
|
|
|
|
if ret:
|
|
n = n + 1
|
|
|
|
# print(UserAnswer.objects.filter(exam__id=q["eid"]))
|
|
# print(request.urlencode())
|
|
|
|
return JsonResponse({"success": True, "question_count": n})
|
|
return JsonResponse({"success": False, "error": "Invalid data"})
|
|
|
|
def exam_json(self, request, pk):
|
|
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
if not exam.active:
|
|
raise Http404("No available exam")
|
|
|
|
|
|
exam_json_cache = cache.get("{}_exam_json_{}".format(self.app_name, pk))
|
|
|
|
path= "{0}{1}/exam/{2}.json".format(settings.MEDIA_ROOT, self.app_name, pk)
|
|
url= "{0}{1}/exam/{2}.json".format(settings.MEDIA_URL, self.app_name, pk)
|
|
|
|
|
|
if os.path.isfile(path) and not exam.recreate_json:
|
|
#exam_json_cache["cached"] = True
|
|
return redirect(url)
|
|
return JsonResponse(exam_json_cache)
|
|
|
|
time = datetime.now()
|
|
|
|
with open(path, "w+") as f:
|
|
exam_json = exam.get_exam_json()
|
|
exam_json["generated"] = time.isoformat()
|
|
f.write(json.dumps(exam_json))
|
|
|
|
exam.recreate_json = False
|
|
|
|
exam.json_creation_time = time
|
|
exam.save()
|
|
|
|
# We also try to clear the cache of any associated questions (longs)
|
|
# see exam_question_json
|
|
#n = exam.exam_questions.count()
|
|
#question_keys = ["{}_exam_json_{}_{}".format(self.app_name, pk, i) for i in range(1, n)]
|
|
#cache.delete_many(question_keys)
|
|
|
|
#cache.set("{}_exam_json_{}".format(self.app_name, pk), exam_json, 3600)
|
|
|
|
return JsonResponse(exam_json)
|
|
|
|
def exam_question_json(self, request, pk, sk):
|
|
question = get_object_or_404(self.Question, pk=sk)
|
|
exam = get_object_or_404(self.Exam, pk=pk)
|
|
|
|
if not exam.active:
|
|
raise Http404("No available exam")
|
|
|
|
return redirect("{}:question_json".format(self.app_name), pk=sk)
|
|
redirect()
|
|
|
|
question_json_cache = cache.get("{}_question_json_{}".format(self.app_name, sk))
|
|
|
|
if question_json_cache is not None and not question.recreate_json:
|
|
question_json_cache["cached"] = True
|
|
return JsonResponse(question_json_cache)
|
|
|
|
question_json = exam.get_exam_question_json(sk)
|
|
|
|
cache.set("{}_question_json_{}".format(self.app_name, sk), question_json, 3600)
|
|
|
|
return JsonResponse(question_json) |