From 8fbb50ee9ff689e2a2c9eb3aab484e51d3c7bc26 Mon Sep 17 00:00:00 2001 From: Ross Date: Sun, 7 Feb 2021 22:43:17 +0000 Subject: [PATCH] continue unifying views --- anatomy/models.py | 35 ++++ anatomy/urls.py | 12 +- anatomy/views.py | 230 +++-------------------- generic/views.py | 181 +++++++++++++++--- longs/urls.py | 106 +++++++---- longs/views.py | 182 +----------------- physics/templates/physics/exam_take.html | 9 +- physics/urls.py | 12 +- physics/views.py | 86 +-------- rad/views.py | 15 +- rapids/urls.py | 22 +-- rapids/views.py | 192 +------------------ 12 files changed, 330 insertions(+), 752 deletions(-) diff --git a/anatomy/models.py b/anatomy/models.py index 42141e77..cc3f74c0 100644 --- a/anatomy/models.py +++ b/anatomy/models.py @@ -15,6 +15,9 @@ import string from generic.models import Examination, ExamBase +from collections import defaultdict +from helpers.images import image_as_base64 + image_storage = FileSystemStorage( # Physical file location ROOT location=u"{0}/anatomy/".format(settings.MEDIA_ROOT), @@ -273,6 +276,38 @@ class Exam(ExamBase): help_text="Exam time limit (in seconds)", default=5400 ) + def get_exam_json(self): + questions = self.exam_questions.all() + + exam_questions = defaultdict(dict) + + exam_order = [] + + for q in questions: + exam_order.append(q.id) + + exam_questions[q.id] = { + "title": "{}".format(q.description), + "question": str(q.question_type), + "images": [image_as_base64(q.image)], + "annotations": [str(q.image_annotations)], + "type": "anatomy", + } + + exam_json = { + "eid": "anatomy/{}".format(self.id), + "cached": False, + "exam_type": "anatomy", + "exam_name": self.name, + "exam_mode": True, + "exam_order": exam_order, + "questions": exam_questions, + } + + if self.time_limit: + exam_json["exam_time"] = self.time_limit + + return exam_json # class UserAnswer(models.Model): diff --git a/anatomy/urls.py b/anatomy/urls.py index 0016d27c..0c4202fc 100644 --- a/anatomy/urls.py +++ b/anatomy/urls.py @@ -5,7 +5,7 @@ app_name = "anatomy" urlpatterns = [ # path('', views.question_list, name='question_list'), - path("", views.index, name="index"), + path("", views.AnatomyExamViews.index, name="index"), path("question/", views.AnatomyQuestionView.as_view(), name="anatomy_question_view"), path("question//", views.question_detail, name="question_detail"), path("question/create/", views.AnatomyQuestionCreate.as_view(), name="anatomy_question_create"), @@ -16,21 +16,21 @@ urlpatterns = [ name="answer_question"), path("question//clone", views.QuestionClone.as_view(), name="question_clone"), path("exam///mark", views.mark, name="mark"), - path("exam//mark", views.mark_overview, name="mark_overview"), + path("exam//mark", views.AnatomyExamViews.mark_overview, name="mark_overview"), path("exam///", views.exam_take, name="exam_take"), - path("exam//question//", views.exam_question_detail, name="exam_question_detail"), + path("exam//question//", views.AnatomyExamViews.exam_question_detail, name="exam_question_detail"), path("exam//", views.AnatomyExamViews.exam_overview, name="exam_overview"), - path("exam//json_edit", views.exam_json_edit, name="exam_json_edit"), + path("exam//json_edit", views.AnatomyExamViews.exam_json_edit, name="exam_json_edit"), path("exam//scores", views.exam_scores_cid, name="exam_scores_cid"), path("exam//scores//", views.exam_scores_cid_user, name="exam_scores_cid_user"), path("exam//toggle_active", views.AnatomyExamViews.exam_toggle_active, name="exam_toggle_active"), path("exam//toggle_results_published", views.AnatomyExamViews.exam_toggle_results_published, name="exam_toggle_results_published"), - path("exam/submit", views.postExamAnswers, name="exam_answers_submit"), + path("exam/submit", views.AnatomyExamViews.postExamAnswers, name="exam_answers_submit"), path("exam/", views.AnatomyExamViews.exam_list, name="exam_list"), path("exam/json/", views.AnatomyExamViews.active_exams, name="active_exams"), - path("exam/json/", views.exam_json, name="exam_json"), + path("exam/json/", views.AnatomyExamViews.exam_json, name="exam_json"), path("exam/json//recreate", views.AnatomyExamViews.exam_json_recreate, name="exam_json_recreate"), #path("cid/", views.cid_scores, name="cid_scores"), #path("cid/", views.cid_selector, name="cid_selector"), diff --git a/anatomy/views.py b/anatomy/views.py index c7439c16..f83dbfc9 100644 --- a/anatomy/views.py +++ b/anatomy/views.py @@ -75,17 +75,12 @@ def user_is_admin(user): return False + def question_list(request): questions = AnatomyQuestion.objects.all() return render(request, "anatomy/question_list.html", {"questions": questions}) -@login_required -def index(request): - exams = Exam.objects.all() - return render(request, "anatomy/index.html", {"exams": exams}) - - @login_required def question_detail(request, pk): question = get_object_or_404(AnatomyQuestion, pk=pk) @@ -93,38 +88,6 @@ def question_detail(request, pk): return render(request, "anatomy/question_detail.html", {"question": question}) -@login_required -def exam_question_detail(request, pk, sk): - exam = get_object_or_404(Exam, pk=pk) - - question = exam.exam_questions.all()[sk] - - exam_length = len(exam.exam_questions.all()) - - pos = exam.get_question_index(question) + 1 - - print(question.exams.through.sort_value) - - previous = -1 - if sk > 0: - previous = sk - 1 - next = sk + 1 - if sk == exam_length - 1: - next = False - - return render( - request, - "anatomy/question_detail.html", - { - "question": question, - "exam": exam, - "next": next, - "previous": previous, - "exam_length": exam_length, - "pos": pos, - }, - ) - @login_required def answer_question(request, pk): @@ -283,63 +246,28 @@ def loadJsonAnswer(answer): return True -def exam_json_edit(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(Exam, pk=pk) - - 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) - else: - data = {"status": "error"} - return JsonResponse(data, status=400) - - -@csrf_exempt -def postExamAnswers(request): - if request.is_ajax and request.method == "POST": - - n = 0 - # horrible but it works - #for k in request.POST.dict(): - - for answer in json.loads(request.POST.get("answers")): - ret = loadJsonAnswer(answer) - - if ret is not True: - return 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"}) - - # return render(request, "anatomy/exam.html", {"exam" : exam, "question" : question}) - - -# @user_passes_test(user_is_admin, login_url="/accounts/login") -@login_required -def mark_overview(request, pk): - exam = get_object_or_404(Exam, pk=pk) - - questions = exam.exam_questions.all() - - return render( - request, "anatomy/mark_overview.html", {"exam": exam, "questions": questions} - ) +#@csrf_exempt +#def postExamAnswers(request): +# if request.is_ajax and request.method == "POST": +# +# n = 0 +# # horrible but it works +# #for k in request.POST.dict(): +# +# for answer in json.loads(request.POST.get("answers")): +# ret = loadJsonAnswer(answer) +# +# if ret is not True: +# return 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"}) +# +# # return render(request, "anatomy/exam.html", {"exam" : exam, "question" : question}) # @user_passes_test(user_is_admin, login_url="/accounts/login") @@ -487,116 +415,6 @@ def mark(request, pk, sk): }, ) -AnatomyExamViews = ExamViews(Exam, "anatomy", "anatomy") - -# def exam_toggle_results_published(request, pk): -# if request.is_ajax() and request.method == "POST": -# -# exam = get_object_or_404(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) -# -# -# def exam_toggle_active(request, pk): -# if request.is_ajax() and request.method == "POST": -# -# exam = get_object_or_404(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) -# -# -# def active_exams(request, json=True): -# exams = Exam.objects.all() -# -# active_exams = {"exams": []} -# -# for exam in exams: -# if exam.active: -# active_exams["exams"].append( -# { -# "name": exam.get_exam_name(), -# "url": request.build_absolute_uri(exam.get_json_url()), -# "type": "anatomy", -# } -# ) -# -# if json == False: -# return active_exams["exams"] -# -# return JsonResponse(active_exams) -# -# @login_required -# def exam_json_recreate(request, pk): -# exam = get_object_or_404(Exam, pk=pk) -# -# exam.recreate_json = True -# exam.save() -# -# return redirect("anatomy:exam_overview", pk=pk) - -def exam_json(request, pk): - - exam = get_object_or_404(Exam, pk=pk) - - if not exam.active: - raise Http404("No available exam") - - exam_json_cache = cache.get("anatomy_exam_json_{}".format(pk)) - - if exam_json_cache is not None and not exam.recreate_json: - exam_json_cache["cached"] = True - return JsonResponse(exam_json_cache) - - questions = exam.exam_questions.all() - - exam_questions = defaultdict(dict) - - exam_order = [] - - for q in questions: - exam_order.append(q.id) - - exam_questions[q.id] = { - "title": "{}".format(q.description), - "question": str(q.question_type), - "images": [image_as_base64(q.image)], - "annotations": [str(q.image_annotations)], - "type": "anatomy", - } - - exam_json = { - "eid": "anatomy/{}".format(exam.id), - "cached": False, - "exam_type": "anatomy", - "exam_name": exam.name, - "exam_mode": True, - "exam_order": exam_order, - "questions": exam_questions, - } - - if exam.time_limit: - exam_json["exam_time"] = exam.time_limit - - exam.recreate_json = False - exam.save() - - cache.set("anatomy_exam_json_{}".format(pk), exam_json, 3600) - - return JsonResponse(exam_json) @login_required @@ -1116,3 +934,5 @@ def question_save_annotation(request, pk): data = {"status": "error"} return JsonResponse(data, status=400) + +AnatomyExamViews = ExamViews(Exam, "anatomy", "anatomy", loadJsonAnswer) \ No newline at end of file diff --git a/generic/views.py b/generic/views.py index e484df78..a72fe095 100644 --- a/generic/views.py +++ b/generic/views.py @@ -6,8 +6,18 @@ 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, ) @@ -40,12 +50,15 @@ def get_examination_id(request): return HttpResponse("/") -class ExamViews: - def __init__(self, exam, app, question_type): + +class ExamViews(View, LoginRequiredMixin): + def __init__(self, exam, app, question_type, loadJsonAnswer): self.Exam = exam 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": @@ -62,6 +75,7 @@ class ExamViews: return JsonResponse(data, status=400) + @method_decorator(login_required) def exam_toggle_active(self, request, pk): if request.is_ajax() and request.method == "POST": @@ -75,6 +89,105 @@ class ExamViews: 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 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 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) + 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() @@ -96,35 +209,45 @@ class ExamViews: return JsonResponse(active_exams) - @login_required - def exam_json_recreate(self, request, pk): + @method_decorator(csrf_exempt) + def postExamAnswers(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) - exam.recreate_json = True + if not exam.active: + raise Http404("No available exam") + + exam_json_cache = cache.get("{}_exam_json_{}".format(self.app_name, pk)) + + if exam_json_cache is not None and not exam.recreate_json: + exam_json_cache["cached"] = True + return JsonResponse(exam_json_cache) + + exam_json = exam.get_exam_json() + + exam.recreate_json = False exam.save() - return redirect("{}:exam_overview".format(self.app_name), pk=pk) - - @login_required - def exam_list(self, request): - exams = self.Exam.objects.all() - return render(request, "{}/exam_list.html".format(self.app_name), {"exams": exams}) - - - @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}, - ) + cache.set("{}_exam_json_{}".format(self.app_name, pk), exam_json, 3600) + return JsonResponse(exam_json) \ No newline at end of file diff --git a/longs/urls.py b/longs/urls.py index 86dd1a74..07aebd3d 100755 --- a/longs/urls.py +++ b/longs/urls.py @@ -5,64 +5,90 @@ app_name = "longs" urlpatterns = [ # path('', views.question_list, name='question_list'), - path("", views.index, name="index"), + path("", views.LongExamViews.index, name="index"), path("author//", views.author_detail, name="author_detail"), path("author/", views.author_list, name="author_list"), path("question/", views.LongView.as_view(), name="long_view"), path("series/", views.LongSeriesView.as_view(), name="long_series_view"), path("series/", views.long_series_detail, name="long_series_detail"), - #path("unchecked/", views.unchecked_list, name="unchecked_list"), - #path("verified//", views.verified_detail, name="verified_detail"), + # path("unchecked/", views.unchecked_list, name="unchecked_list"), + # path("verified//", views.verified_detail, name="verified_detail"), path("question//", views.long_detail, name="long_detail"), path("question//split", views.long_split, name="long_split"), path("question//clone", views.LongClone.as_view(), name="long_clone"), - #path("verified/", views.verified, name="verified"), - #path("all_questions/", views.all_questions, name="all_questions"), + # path("verified/", views.verified, name="verified"), + # path("all_questions/", views.all_questions, name="all_questions"), path("question//scrap", views.long_scrap, name="long_scrap"), path("exam///mark", views.mark, name="mark"), - path("exam//mark", views.mark_overview, name="mark_overview"), -# path("exam///", views.exam_take, name="exam_take"), - path("exam//question//", views.exam_question_detail, name="exam_question_detail"), - path("exam//", views.exam_overview, name="exam_overview"), - path("exam//json_edit", views.exam_json_edit, name="exam_json_edit"), - path("exam//scores", views.exam_scores_cid, - name="exam_scores_cid"), - path("exam//scores//", views.exam_scores_cid_user, - name="exam_scores_cid_user"), - path("exam//toggle_active", views.exam_toggle_active, name="exam_toggle_active"), - path("exam//toggle_results_published", views.exam_toggle_results_published, name="exam_toggle_results_published"), - path("exam/submit", views.postExamAnswers, name="exam_answers_submit"), - path("exam/", views.exam_list, name="exam_list"), - path("exam/json/", views.active_exams, name="active_exams"), + path("exam//mark", views.LongExamViews.mark_overview, name="mark_overview"), + # path("exam///", views.exam_take, name="exam_take"), + path( + "exam//question//", + views.LongExamViews.exam_question_detail, + name="exam_question_detail", + ), + path("exam//", views.LongExamViews.exam_overview, name="exam_overview"), + path("exam//json_edit", views.LongExamViews.exam_json_edit, name="exam_json_edit"), + path("exam//scores", views.exam_scores_cid, name="exam_scores_cid"), + path( + "exam//scores//", + views.exam_scores_cid_user, + name="exam_scores_cid_user", + ), + path( + "exam//toggle_active", + views.LongExamViews.exam_toggle_active, + name="exam_toggle_active", + ), + path( + "exam//toggle_results_published", + views.LongExamViews.exam_toggle_results_published, + name="exam_toggle_results_published", + ), + path("exam/submit", views.LongExamViews.postExamAnswers, name="exam_answers_submit"), + path("exam/", views.LongExamViews.exam_list, name="exam_list"), + path("exam/json/", views.LongExamViews.active_exams, name="active_exams"), path("exam/json/", views.exam_json, name="exam_json"), - path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), + path( + "exam/json//recreate", + views.LongExamViews.exam_json_recreate, + name="exam_json_recreate", + ), path("create/", views.LongCreate.as_view(), name="long_create"), path("create/series", views.LongSeriesCreate.as_view(), name="long_series_create"), - path("create/series/", views.LongSeriesCreate.as_view(), name="long_series_id_create"), - path("create/defaults", - views.LongCreationDefaultView.as_view(), - name="long_create_defaults"), + path( + "create/series/", + views.LongSeriesCreate.as_view(), + name="long_series_id_create", + ), + path( + "create/defaults", + views.LongCreationDefaultView.as_view(), + name="long_create_defaults", + ), path("region/create/", views.create_region, name="create_region"), - path("region/ajax/get_region_id", - views.get_region_id, - name="get_region_id"), - path("abnormality/create/", - views.create_abnormality, - name="create_abnormality"), - path("abnormality/ajax/get_abnormality_id", - views.get_abnormality_id, - name="get_abnormality_id"), - path("examination/create/", - views.create_examination, - name="create_examination"), - path("examination/ajax/get_examination_id", - views.get_examination_id, - name="get_examination_id"), + path("region/ajax/get_region_id", views.get_region_id, name="get_region_id"), + path("abnormality/create/", views.create_abnormality, name="create_abnormality"), + path( + "abnormality/ajax/get_abnormality_id", + views.get_abnormality_id, + name="get_abnormality_id", + ), + path("examination/create/", views.create_examination, name="create_examination"), + path( + "examination/ajax/get_examination_id", + views.get_examination_id, + name="get_examination_id", + ), path( "question//update", views.LongUpdate.as_view(), name="long_update", ), - path("series//update", views.LongSeriesUpdate.as_view(), name="long_series_update"), + path( + "series//update", + views.LongSeriesUpdate.as_view(), + name="long_series_update", + ), path("/add_note", views.AddNote.as_view(), name="long_add_note"), ] diff --git a/longs/views.py b/longs/views.py index 574138f4..500c7c5f 100755 --- a/longs/views.py +++ b/longs/views.py @@ -56,6 +56,8 @@ from django.forms.models import model_to_dict from longs.forms import LongCreationDefaultForm from longs.models import LongCreationDefault +from generic.views import ExamViews + logger = logging.getLogger(__name__) @@ -69,11 +71,6 @@ class AuthorOrCheckerRequiredMixin(object): return obj -@login_required -def index(request): - exams = Exam.objects.all() - return render(request, "longs/index.html", {"exams": exams}) - # def index(request): # other_longs = Long.objects.exclude(author=request.user.pk) @@ -652,62 +649,6 @@ def loadJsonAnswer(answer): return True -def exam_json_edit(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(Exam, pk=pk) - - 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) - else: - data = {"status": "error"} - return JsonResponse(data, status=400) - - -@csrf_exempt -def postExamAnswers(request): - if request.is_ajax and request.method == "POST": - - n = 0 - - for answer in json.loads(request.POST.get("answers")): - ret = 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"}) - - -# @user_passes_test(user_is_admin, login_url="/accounts/login") -@login_required -def mark_overview(request, pk): - exam = get_object_or_404(Exam, pk=pk) - - questions = exam.exam_questions.all() - - return render( - request, "longs/mark_overview.html", {"exam": exam, "questions": questions} - ) - # @user_passes_test(user_is_admin, login_url="/accounts/login") @login_required @@ -855,56 +796,6 @@ def mark(request, pk, sk): ) -def exam_toggle_results_published(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - -def exam_toggle_active(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - -def active_exams(request, json=True): - exams = Exam.objects.all() - - active_exams = {"exams": []} - - for exam in exams: - if exam.active: - active_exams["exams"].append( - { - "name": exam.get_exam_name(), - "url": request.build_absolute_uri(exam.get_json_url()), - "type": "long", - } - ) - - if json == False: - return active_exams["exams"] - - return JsonResponse(active_exams) - def exam_json(request, pk): @@ -962,6 +853,7 @@ def exam_json(request, pk): "questions": exam_questions, } + if exam.time_limit: exam_json["exam_time"] = exam.time_limit @@ -973,16 +865,6 @@ def exam_json(request, pk): return JsonResponse(exam_json) -@login_required -def exam_json_recreate(request, pk): - exam = get_object_or_404(Exam, pk=pk) - - exam.recreate_json = True - exam.save() - - return redirect("longs:exam_overview", pk=pk) - - @login_required def exam_scores_cid(request, pk): exam = get_object_or_404(Exam, pk=pk) @@ -1155,60 +1037,4 @@ def exam_scores_cid_user(request, pk, sk): ) -@login_required -def exam_question_detail(request, pk, sk): - exam = get_object_or_404(Exam, pk=pk) - - question = exam.exam_questions.all()[sk] - - exam_length = len(exam.exam_questions.all()) - - pos = exam.get_question_index(question) + 1 - - print(question.exams.through.sort_value) - - previous = -1 - if sk > 0: - previous = sk - 1 - next = sk + 1 - if sk == exam_length - 1: - next = False - - return render( - request, - "longs/long_detail.html", - { - "question": question, - "exam": exam, - "next": next, - "previous": previous, - "exam_length": exam_length, - "pos": pos, - }, - ) - - -@login_required -def exam_list(request): - exams = Exam.objects.all() - return render(request, "longs/exam_list.html", {"exams": exams}) - - -@login_required -def exam_overview(request, pk): - print(type(pk)) - #print(Exam.objects.all()) - #exams = Exam.objects.all() - #print("test", Exam.objects.all().get(id=pk)) - exam = get_object_or_404(Exam, pk=pk) - print("exam", exam) - - questions = exam.exam_questions.all() - - question_number = len(questions) - - return render( - request, - "longs/exam_overview.html", - {"exam": exam, "questions": questions, "question_number": question_number}, - ) \ No newline at end of file +LongExamViews = ExamViews(Exam, "longs", "long", loadJsonAnswer) \ No newline at end of file diff --git a/physics/templates/physics/exam_take.html b/physics/templates/physics/exam_take.html index f8ab241b..51f4b991 100644 --- a/physics/templates/physics/exam_take.html +++ b/physics/templates/physics/exam_take.html @@ -110,7 +110,12 @@ ans: answers } - postAnswers(ans); + let json = { + eid: {{exam.pk}}, + answers: JSON.stringify([ans]), + }; + + postAnswers(json); }) }); @@ -125,7 +130,7 @@ function postAnswers(ans) { console.log(ans); - $.post("{% url 'physics:exam_answers_submit' %}", JSON.stringify(ans)).done((data) => { + $.post("{% url 'physics:exam_answers_submit' %}", ans, null, "json").done((data) => { console.log(data); if (data.success) { let ret = confirm( diff --git a/physics/urls.py b/physics/urls.py index 0a25884d..55108c4a 100644 --- a/physics/urls.py +++ b/physics/urls.py @@ -5,7 +5,7 @@ app_name = "physics" urlpatterns = [ # path('', views.question_list, name='question_list'), - path("", views.index, name="index"), + path("", views.PhysicsExamViews.index, name="index"), #path("question/", views.QuestionView.as_view(), name="question_view"), path("question//", views.question_detail, name="question_detail"), #path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"), @@ -13,15 +13,15 @@ urlpatterns = [ #path("exam///mark", views.mark, name="mark"), #path("exam//mark", views.mark_overview, name="mark_overview"), path("exam//take", views.exam_take, name="exam_take"), - path("exam//", views.exam_overview, name="exam_overview"), + path("exam//", views.PhysicsExamViews.exam_overview, name="exam_overview"), path("exam//scores", views.exam_scores_cid, name="exam_scores_cid"), path("exam//scores//", views.exam_scores_cid_user, name="exam_scores_cid_user"), - path("exam//toggle_active", views.exam_toggle_active, name="exam_toggle_active"), - path("exam//toggle_results_published", views.exam_toggle_results_published, name="exam_toggle_results_published"), - path("exam/submit", views.postExamAnswers, name="exam_answers_submit"), - path("exam/", views.exam_list, name="exam_list"), + path("exam//toggle_active", views.PhysicsExamViews.exam_toggle_active, name="exam_toggle_active"), + path("exam//toggle_results_published", views.PhysicsExamViews.exam_toggle_results_published, name="exam_toggle_results_published"), + path("exam/submit", views.PhysicsExamViews.postExamAnswers, name="exam_answers_submit"), + path("exam/", views.PhysicsExamViews.exam_list, name="exam_list"), path("exam/available", views.active_exams, name="active_exams"), #path("exam/json/", views.exam_json, name="exam_json"), #path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), diff --git a/physics/views.py b/physics/views.py index b0638a5b..049dbcef 100644 --- a/physics/views.py +++ b/physics/views.py @@ -31,80 +31,20 @@ import json import statistics import plotly.express as px +from generic.views import ExamViews + def question_list(request): questions = Question.objects.all() return render(request, "physics/question_list.html", {"questions": questions}) -@login_required -def index(request): - exams = Exam.objects.all() - return render(request, "physics/index.html", {"exams": exams}) - - @login_required def question_detail(request, pk): question = get_object_or_404(Question, pk=pk) return render(request, "physics/question_detail.html", {"question": question}) -@login_required -def exam_list(request): - exams = Exam.objects.all() - return render(request, "physics/exam_list.html", {"exams": exams}) - - -@login_required -def exam_overview(request, pk): - print(type(pk)) - print(Exam.objects.all()) - exams = Exam.objects.all() - print("test", Exam.objects.all().get(id=pk)) - exam = get_object_or_404(Exam, pk=pk) - print("exam", exam) - - questions = exam.exam_questions.all() - - question_number = len(questions) - - return render( - request, - "physics/exam_overview.html", - {"exam": exam, "questions": questions, "question_number": question_number}, - ) - - -def exam_toggle_results_published(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - -def exam_toggle_active(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - def active_exams(request): exams = Exam.objects.all() print(exams) @@ -289,26 +229,6 @@ def exam_take(request, pk): ) -@csrf_exempt -def postExamAnswers(request): - if request.is_ajax and request.method == "POST": - - n = 0 - # horrible but it works - for k in request.POST.dict(): - print(k) - ret = loadJsonAnswer(json.loads(k)) - - if ret is not True: - return ret - - # print(UserAnswer.objects.filter(exam__id=q["eid"])) - # print(request.urlencode()) - - return JsonResponse({"success": True}) - return JsonResponse({"success": False, "error": "Invalid data"}) - - def loadJsonAnswer(answer): # As access is not restricted make sure the data appears valid if (not isinstance(answer["cid"], int)) or (not isinstance(answer["eid"], int)): @@ -364,3 +284,5 @@ def loadJsonAnswer(answer): ans.save() return True + +PhysicsExamViews = ExamViews(Exam, "physics", "physics", loadJsonAnswer) \ No newline at end of file diff --git a/rad/views.py b/rad/views.py index 22efe790..4986e10a 100644 --- a/rad/views.py +++ b/rad/views.py @@ -30,8 +30,9 @@ from anatomy.models import Exam as AnatomyExam from rapids.models import CidUserAnswer as RapidsCidUserAnswer from rapids.models import Exam as RapidsExam -from anatomy.views import AnatomyExamViews as AnatomyExamViews, postExamAnswers as postAnatomyExamAnswers -from rapids.views import active_exams as active_rapid_exams, postExamAnswers as postRapidExamAnswers +from anatomy.views import AnatomyExamViews +from rapids.views import RapidExamViews +from longs.views import LongExamViews @@ -89,11 +90,13 @@ def cid_scores(request, pk): def active_exams(request): anatomy_exams = AnatomyExamViews.active_exams(request, False) - rapid_exams = active_rapid_exams(request, False) + rapid_exams = RapidExamViews.active_exams(request, False) + long_exams = LongExamViews.active_exams(request, False) exams = [] exams.extend(anatomy_exams) exams.extend(rapid_exams) + exams.extend(long_exams) active_exams = {"exams": exams} @@ -107,9 +110,11 @@ def exam_submit(request): exam_type, exam_id = request.POST.get("eid").split("/") if exam_type == "anatomy": - return postAnatomyExamAnswers(request) + return AnatomyExamViews.postExamAnswers(request) elif exam_type == "rapid": - return postRapidExamAnswers(request) + return RapidExamViews.postExamAnswers(request) + elif exam_type == "long": + return LongExamViews.postExamAnswers(request) return JsonResponse({"success": False, "error": "Invalid exam type"}) # postExamAnswers diff --git a/rapids/urls.py b/rapids/urls.py index 65c4cc51..a5df6aec 100755 --- a/rapids/urls.py +++ b/rapids/urls.py @@ -5,7 +5,7 @@ app_name = "rapids" urlpatterns = [ # path('', views.question_list, name='question_list'), - path("", views.index, name="index"), + path("", views.RapidExamViews.index, name="index"), path("author//", views.author_detail, name="author_detail"), path("author/", views.author_list, name="author_list"), path("question/", views.RapidView.as_view(), name="rapid_view"), @@ -18,22 +18,22 @@ urlpatterns = [ #path("all_questions/", views.all_questions, name="all_questions"), path("question//scrap", views.rapid_scrap, name="rapid_scrap"), path("exam///mark", views.mark, name="mark"), - path("exam//mark", views.mark_overview, name="mark_overview"), + path("exam//mark", views.RapidExamViews.mark_overview, name="mark_overview"), # path("exam///", views.exam_take, name="exam_take"), - path("exam//question//", views.exam_question_detail, name="exam_question_detail"), - path("exam//", views.exam_overview, name="exam_overview"), - path("exam//json_edit", views.exam_json_edit, name="exam_json_edit"), + path("exam//question//", views.RapidExamViews.exam_question_detail, name="exam_question_detail"), + path("exam//", views.RapidExamViews.exam_overview, name="exam_overview"), + path("exam//json_edit", views.RapidExamViews.exam_json_edit, name="exam_json_edit"), path("exam//scores", views.exam_scores_cid, name="exam_scores_cid"), path("exam//scores//", views.exam_scores_cid_user, name="exam_scores_cid_user"), - path("exam//toggle_active", views.exam_toggle_active, name="exam_toggle_active"), - path("exam//toggle_results_published", views.exam_toggle_results_published, name="exam_toggle_results_published"), - path("exam/submit", views.postExamAnswers, name="exam_answers_submit"), - path("exam/", views.exam_list, name="exam_list"), - path("exam/json/", views.active_exams, name="active_exams"), + path("exam//toggle_active", views.RapidExamViews.exam_toggle_active, name="exam_toggle_active"), + path("exam//toggle_results_published", views.RapidExamViews.exam_toggle_results_published, name="exam_toggle_results_published"), + path("exam/submit", views.RapidExamViews.postExamAnswers, name="exam_answers_submit"), + path("exam/", views.RapidExamViews.exam_list, name="exam_list"), + path("exam/json/", views.RapidExamViews.active_exams, name="active_exams"), path("exam/json/", views.exam_json, name="exam_json"), - path("exam/json//recreate", views.exam_json_recreate, name="exam_json_recreate"), + path("exam/json//recreate", views.RapidExamViews.exam_json_recreate, name="exam_json_recreate"), path("create/", views.RapidCreate.as_view(), name="rapid_create"), path("create/defaults", views.RapidCreationDefaultView.as_view(), diff --git a/rapids/views.py b/rapids/views.py index ce4b5c05..6e761d0c 100755 --- a/rapids/views.py +++ b/rapids/views.py @@ -39,6 +39,9 @@ from .models import ( Answer, CidUserAnswer, ) + +from generic.views import ExamViews + from .tables import RapidTable from .filters import RapidFilter @@ -75,20 +78,6 @@ class AuthorOrCheckerRequiredMixin(object): return obj -@login_required -def index(request): - exams = Exam.objects.all() - return render(request, "rapids/index.html", {"exams": exams}) - - -# def index(request): -# other_rapids = Rapid.objects.exclude(author=request.user.pk) -# user_rapids = Rapid.objects.filter(author=request.user.pk) -# return render( -# request, -# "rapids/index.html", -# {"other_rapids": other_rapids, "user_rapids": user_rapids}, -# ) @login_required @@ -564,63 +553,6 @@ def loadJsonAnswer(answer): return True -def exam_json_edit(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(Exam, pk=pk) - - 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) - else: - data = {"status": "error"} - return JsonResponse(data, status=400) - - -@csrf_exempt -def postExamAnswers(request): - if request.is_ajax and request.method == "POST": - - n = 0 - - for answer in json.loads(request.POST.get("answers")): - ret = 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"}) - - -# @user_passes_test(user_is_admin, login_url="/accounts/login") -@login_required -def mark_overview(request, pk): - exam = get_object_or_404(Exam, pk=pk) - - questions = exam.exam_questions.all() - - return render( - request, "rapids/mark_overview.html", {"exam": exam, "questions": questions} - ) - - # @user_passes_test(user_is_admin, login_url="/accounts/login") @login_required def mark(request, pk, sk): @@ -767,57 +699,6 @@ def mark(request, pk, sk): ) -def exam_toggle_results_published(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - -def exam_toggle_active(request, pk): - if request.is_ajax() and request.method == "POST": - - exam = get_object_or_404(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) - - -def active_exams(request, json=True): - exams = Exam.objects.all() - - active_exams = {"exams": []} - - for exam in exams: - if exam.active: - active_exams["exams"].append( - { - "name": exam.get_exam_name(), - "url": request.build_absolute_uri(exam.get_json_url()), - "type": "rapid", - } - ) - - if json == False: - return active_exams["exams"] - - return JsonResponse(active_exams) - - def exam_json(request, pk): exam = get_object_or_404(Exam, pk=pk) @@ -885,16 +766,6 @@ def exam_json(request, pk): return JsonResponse(exam_json) -@login_required -def exam_json_recreate(request, pk): - exam = get_object_or_404(Exam, pk=pk) - - exam.recreate_json = True - exam.save() - - return redirect("rapids:exam_overview", pk=pk) - - @login_required def exam_scores_cid(request, pk): exam = get_object_or_404(Exam, pk=pk) @@ -1067,60 +938,5 @@ def exam_scores_cid_user(request, pk, sk): ) -@login_required -def exam_question_detail(request, pk, sk): - exam = get_object_or_404(Exam, pk=pk) - question = exam.exam_questions.all()[sk] - - exam_length = len(exam.exam_questions.all()) - - pos = exam.get_question_index(question) + 1 - - print(question.exams.through.sort_value) - - previous = -1 - if sk > 0: - previous = sk - 1 - next = sk + 1 - if sk == exam_length - 1: - next = False - - return render( - request, - "rapids/rapid_detail.html", - { - "question": question, - "exam": exam, - "next": next, - "previous": previous, - "exam_length": exam_length, - "pos": pos, - }, - ) - - -@login_required -def exam_list(request): - exams = Exam.objects.all() - return render(request, "rapids/exam_list.html", {"exams": exams}) - - -@login_required -def exam_overview(request, pk): - print(type(pk)) - #print(Exam.objects.all()) - #exams = Exam.objects.all() - #print("test", Exam.objects.all().get(id=pk)) - exam = get_object_or_404(Exam, pk=pk) - print("exam", exam) - - questions = exam.exam_questions.all() - - question_number = len(questions) - - return render( - request, - "rapids/exam_overview.html", - {"exam": exam, "questions": questions, "question_number": question_number}, - ) \ No newline at end of file +RapidExamViews = ExamViews(Exam, "rapids", "rapid", loadJsonAnswer) \ No newline at end of file