unify generic exam views naming

This commit is contained in:
Ross
2021-12-19 10:08:07 +00:00
parent b823e0a897
commit 889db68a08
12 changed files with 194 additions and 133 deletions
+18 -18
View File
@@ -8,7 +8,7 @@ app_name = "anatomy"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.AnatomyExamViews.index, name="index"), path("", views.GenericExamViews.index, name="index"),
path( path(
"question/", "question/",
views.AnatomyQuestionView.as_view(), views.AnatomyQuestionView.as_view(),
@@ -62,29 +62,29 @@ urlpatterns = [
"exam/<int:exam_pk>/<int:sk>/mark/review", views.mark_review, name="mark_review" "exam/<int:exam_pk>/<int:sk>/mark/review", views.mark_review, name="mark_review"
), ),
path( path(
"exam/<int:pk>/mark", views.AnatomyExamViews.mark_overview, name="mark_overview" "exam/<int:pk>/mark", views.GenericExamViews.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"),
path( path(
"exam/<int:pk>/question/<int:sk>/", "exam/<int:pk>/question/<int:sk>/",
views.AnatomyExamViews.exam_question_detail, views.GenericExamViews.exam_question_detail,
name="exam_question_detail", name="exam_question_detail",
), ),
path("exam/<int:pk>/", views.AnatomyExamViews.exam_overview, name="exam_overview"), path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
path( path(
"exam/<int:pk>/json_edit", "exam/<int:pk>/json_edit",
views.AnatomyExamViews.exam_json_edit, views.GenericExamViews.exam_json_edit,
name="exam_json_edit", name="exam_json_edit",
), ),
path( path(
"exam/<int:pk>/scores", "exam/<int:pk>/scores",
views.AnatomyExamViews.exam_scores_cid, views.GenericExamViews.exam_scores_cid,
# cache_page(60 * 1)(views.exam_scores_cid), # cache_page(60 * 1)(views.exam_scores_cid),
name="exam_scores_cid", name="exam_scores_cid",
), ),
path( path(
"exam/<int:pk>/scores/refresh", "exam/<int:pk>/scores/refresh",
views.AnatomyExamViews.exam_scores_refresh, views.GenericExamViews.exam_scores_refresh,
# cache_page(60 * 1)(views.exam_scores_cid), # cache_page(60 * 1)(views.exam_scores_cid),
name="exam_scores_refresh", name="exam_scores_refresh",
), ),
@@ -95,41 +95,41 @@ urlpatterns = [
), ),
path( path(
"exam/<int:pk>/toggle_active", "exam/<int:pk>/toggle_active",
views.AnatomyExamViews.exam_toggle_active, views.GenericExamViews.exam_toggle_active,
name="exam_toggle_active", name="exam_toggle_active",
), ),
path( path(
"exam/<int:pk>/toggle_results_published", "exam/<int:pk>/toggle_results_published",
views.AnatomyExamViews.exam_toggle_results_published, views.GenericExamViews.exam_toggle_results_published,
name="exam_toggle_results_published", name="exam_toggle_results_published",
), ),
path( path(
"exam/submit", "exam/submit",
views.AnatomyExamViews.postExamAnswers, views.GenericExamViews.postExamAnswers,
name="exam_answers_submit", name="exam_answers_submit",
), ),
path("exam/", views.AnatomyExamViews.exam_list, name="exam_list"), path("exam/", views.GenericExamViews.exam_list, name="exam_list"),
path("exam/all", views.AnatomyExamViews.exam_list_all, name="exam_list_all"), path("exam/all", views.GenericExamViews.exam_list_all, name="exam_list_all"),
path("exam/create", views.ExamCreate.as_view(), name="exam_create"), path("exam/create", views.ExamCreate.as_view(), name="exam_create"),
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"), path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
path("exam/<int:exam_id>/cids", views.AnatomyExamViews.exam_cids, name="exam_cids"), path("exam/<int:exam_id>/cids", views.GenericExamViews.exam_cids, name="exam_cids"),
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"), path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"), path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
path("exam/json/", views.AnatomyExamViews.active_exams, name="active_exams"), path("exam/json/", views.GenericExamViews.active_exams, name="active_exams"),
path("exam/json/<int:pk>", views.AnatomyExamViews.exam_json, name="exam_json"), path("exam/json/<int:pk>", views.GenericExamViews.exam_json, name="exam_json"),
path( path(
"exam/json/<int:pk>/unbased", "exam/json/<int:pk>/unbased",
views.AnatomyExamViews.exam_json_unbased, views.GenericExamViews.exam_json_unbased,
name="exam_json_unbased", name="exam_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/<int:sk>/unbased", "exam/json/<int:pk>/<int:sk>/unbased",
views.AnatomyExamViews.exam_question_json_unbased, views.GenericExamViews.exam_question_json_unbased,
name="exam_question_json_unbased", name="exam_question_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/recreate", "exam/json/<int:pk>/recreate",
views.AnatomyExamViews.exam_json_recreate, views.GenericExamViews.exam_json_recreate,
name="exam_json_recreate", name="exam_json_recreate",
), ),
# path("cid/", views.cid_selector, name="cid_selector"), # path("cid/", views.cid_selector, name="cid_selector"),
+12 -10
View File
@@ -136,8 +136,8 @@ def answer_question(request, pk):
) )
#@login_required # @login_required
#def exam_take(request, pk, sk): # def exam_take(request, pk, sk):
# """ # """
# Allows taking of the exam on the django server (when logged in) # Allows taking of the exam on the django server (when logged in)
# #
@@ -212,7 +212,7 @@ def answer_question(request, pk):
# ) # )
#def flag_question(request): # def flag_question(request):
# pk = request.GET.get("pk", None) # pk = request.GET.get("pk", None)
# ans = UserAnswer.objects.filter(user=request.user, question__pk=pk).first() # ans = UserAnswer.objects.filter(user=request.user, question__pk=pk).first()
# ans.flagged = not ans.flagged # ans.flagged = not ans.flagged
@@ -244,7 +244,9 @@ def loadJsonAnswer(answer):
exam = get_object_or_404(Exam, pk=eid) exam = get_object_or_404(Exam, pk=eid)
if not exam.check_cid_user(answer["cid"], answer["passcode"]): if not exam.check_cid_user(answer["cid"], answer["passcode"]):
return False, JsonResponse({"success": False, "error": "invalid cid / passcode"}) return False, JsonResponse(
{"success": False, "error": "invalid cid / passcode"}
)
# if not exam.active: # if not exam.active:
# return False, JsonResponse( # return False, JsonResponse(
@@ -452,6 +454,7 @@ def mark(request, exam_pk, sk, unmarked_exam_answers_only=True, review=False):
}, },
) )
@login_required @login_required
def exam_scores_refresh(request, pk): def exam_scores_refresh(request, pk):
exam = get_object_or_404(Exam, pk=pk) exam = get_object_or_404(Exam, pk=pk)
@@ -461,9 +464,7 @@ def exam_scores_refresh(request, pk):
questions = exam.exam_questions.all() questions = exam.exam_questions.all()
cids = ( cids = CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
)
# Force a score update # Force a score update
for c in cids: for c in cids:
@@ -477,8 +478,9 @@ def exam_scores_refresh(request, pk):
}, },
) )
#@login_required
#def exam_scores_cid(request, pk): # @login_required
# def exam_scores_cid(request, pk):
# exam = get_object_or_404(Exam, pk=pk) # exam = get_object_or_404(Exam, pk=pk)
# #
# if not exam.exam_mode: # if not exam.exam_mode:
@@ -1001,7 +1003,7 @@ def question_save_annotation(request, pk):
return JsonResponse(data, status=400) return JsonResponse(data, status=400)
AnatomyExamViews = ExamViews( GenericExamViews = ExamViews(
Exam, AnatomyQuestion, CidUserAnswer, "anatomy", "anatomy", loadJsonAnswer Exam, AnatomyQuestion, CidUserAnswer, "anatomy", "anatomy", loadJsonAnswer
) )
+1
View File
@@ -856,6 +856,7 @@ class ExamViews(View, LoginRequiredMixin):
cache.set("{}_question_json_{}".format(self.app_name, sk), question_json, 3600) cache.set("{}_question_json_{}".format(self.app_name, sk), question_json, 3600)
return JsonResponse(question_json) return JsonResponse(question_json)
def exam_scores_cid(self, request, pk): def exam_scores_cid(self, request, pk):
exam = get_object_or_404(self.Exam, pk=pk) exam = get_object_or_404(self.Exam, pk=pk)
+20 -16
View File
@@ -5,7 +5,7 @@ app_name = "longs"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.LongExamViews.index, name="index"), path("", views.GenericExamViews.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.LongView.as_view(), name="long_view"), path("question/", views.LongView.as_view(), name="long_view"),
@@ -81,17 +81,19 @@ urlpatterns = [
views.mark_question_overview, views.mark_question_overview,
name="mark_question_overview", name="mark_question_overview",
), ),
path("exam/<int:pk>/mark", views.LongExamViews.mark_overview, name="mark_overview"), path(
"exam/<int:pk>/mark", views.GenericExamViews.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"),
path( path(
"exam/<int:pk>/question/<int:sk>/", "exam/<int:pk>/question/<int:sk>/",
views.LongExamViews.exam_question_detail, views.GenericExamViews.exam_question_detail,
name="exam_question_detail", name="exam_question_detail",
), ),
path("exam/<int:pk>/", views.LongExamViews.exam_overview, name="exam_overview"), path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
path( path(
"exam/<int:pk>/json_edit", "exam/<int:pk>/json_edit",
views.LongExamViews.exam_json_edit, views.GenericExamViews.exam_json_edit,
name="exam_json_edit", name="exam_json_edit",
), ),
path( path(
@@ -107,43 +109,45 @@ urlpatterns = [
), ),
path( path(
"exam/<int:pk>/toggle_active", "exam/<int:pk>/toggle_active",
views.LongExamViews.exam_toggle_active, views.GenericExamViews.exam_toggle_active,
name="exam_toggle_active", name="exam_toggle_active",
), ),
path( path(
"exam/<int:pk>/toggle_results_published", "exam/<int:pk>/toggle_results_published",
views.LongExamViews.exam_toggle_results_published, views.GenericExamViews.exam_toggle_results_published,
name="exam_toggle_results_published", name="exam_toggle_results_published",
), ),
path( path(
"exam/submit", views.LongExamViews.postExamAnswers, name="exam_answers_submit" "exam/submit",
views.GenericExamViews.postExamAnswers,
name="exam_answers_submit",
), ),
path("exam/", views.LongExamViews.exam_list, name="exam_list"), path("exam/", views.GenericExamViews.exam_list, name="exam_list"),
path("exam/all", views.LongExamViews.exam_list_all, name="exam_list_all"), path("exam/all", views.GenericExamViews.exam_list_all, name="exam_list_all"),
path("exam/create", views.ExamCreate.as_view(), name="exam_create"), path("exam/create", views.ExamCreate.as_view(), name="exam_create"),
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"), path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"), path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"), path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
path("exam/json/", views.LongExamViews.active_exams, name="active_exams"), path("exam/json/", views.GenericExamViews.active_exams, name="active_exams"),
path("exam/json/<int:pk>", views.LongExamViews.exam_json, name="exam_json"), path("exam/json/<int:pk>", views.GenericExamViews.exam_json, name="exam_json"),
path( path(
"exam/json/<int:pk>/unbased", "exam/json/<int:pk>/unbased",
views.LongExamViews.exam_json_unbased, views.GenericExamViews.exam_json_unbased,
name="exam_json_unbased", name="exam_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/<int:sk>", "exam/json/<int:pk>/<int:sk>",
views.LongExamViews.exam_question_json, views.GenericExamViews.exam_question_json,
name="exam_question_json", name="exam_question_json",
), ),
path( path(
"exam/json/<int:pk>/unbased/<int:sk>", "exam/json/<int:pk>/unbased/<int:sk>",
views.LongExamViews.exam_question_json_unbased, views.GenericExamViews.exam_question_json_unbased,
name="exam_question_json_unbased", name="exam_question_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/recreate", "exam/json/<int:pk>/recreate",
views.LongExamViews.exam_json_recreate, views.GenericExamViews.exam_json_recreate,
name="exam_json_recreate", name="exam_json_recreate",
), ),
path("create/", views.LongCreate.as_view(), name="long_create"), path("create/", views.LongCreate.as_view(), name="long_create"),
+5 -4
View File
@@ -315,7 +315,6 @@ class LongSeriesCreate(RevisionMixin, LoginRequiredMixin, CreateView):
kwargs.update({"user": self.request.user}) kwargs.update({"user": self.request.user})
return kwargs return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(LongSeriesCreate, self).get_context_data(**kwargs) context = super(LongSeriesCreate, self).get_context_data(**kwargs)
@@ -635,7 +634,9 @@ def loadJsonAnswer(answer):
exam = get_object_or_404(Exam, pk=eid) exam = get_object_or_404(Exam, pk=eid)
if not exam.check_cid_user(answer["cid"], answer["passcode"]): if not exam.check_cid_user(answer["cid"], answer["passcode"]):
return False, JsonResponse({"success": False, "error": "invalid cid / passcode"}) return False, JsonResponse(
{"success": False, "error": "invalid cid / passcode"}
)
# if not exam.active: # if not exam.active:
# return False, JsonResponse( # return False, JsonResponse(
@@ -1107,7 +1108,7 @@ def exam_scores_cid_user(request, pk, sk, passcode):
{ {
"exam": exam, "exam": exam,
"cid": cid, "cid": cid,
"passcode" : passcode, "passcode": passcode,
"questions": questions, "questions": questions,
# "answers": answers, # "answers": answers,
"answers_marks": answers_marks, "answers_marks": answers_marks,
@@ -1169,7 +1170,7 @@ def long_series_order_upload_filename(request, pk):
return redirect("longs:long_series_detail", pk=pk) return redirect("longs:long_series_detail", pk=pk)
LongExamViews = ExamViews(Exam, Long, CidUserAnswer, "longs", "long", loadJsonAnswer) GenericExamViews = ExamViews(Exam, Long, CidUserAnswer, "longs", "long", loadJsonAnswer)
class ExamCreate(RevisionMixin, LoginRequiredMixin, CreateView): class ExamCreate(RevisionMixin, LoginRequiredMixin, CreateView):
+46 -20
View File
@@ -5,34 +5,60 @@ app_name = "physics"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.PhysicsExamViews.index, name="index"), path("", views.GenericExamViews.index, name="index"),
#path("question/", views.QuestionView.as_view(), name="question_view"), # path("question/", views.QuestionView.as_view(), name="question_view"),
path("question/", views.QuestionView.as_view(), name="question_view"), path("question/", views.QuestionView.as_view(), name="question_view"),
path("question/<int:pk>/", views.question_detail, name="question_detail"), path("question/<int:pk>/", views.question_detail, name="question_detail"),
#path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"), # path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"),
#path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"), # path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"),
#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>/take_old", views.exam_take_old, name="exam_take_old"), path("exam/<int:pk>/take_old", views.exam_take_old, name="exam_take_old"),
path("exam/<int:pk>/<int:sk>/<str:cid>/<str:passcode>/take", views.exam_take, name="exam_take"), path(
"exam/<int:pk>/<int:sk>/<str:cid>/<str:passcode>/take",
views.exam_take,
name="exam_take",
),
path("exam/<int:pk>/start", views.exam_start, name="exam_start"), path("exam/<int:pk>/start", views.exam_start, name="exam_start"),
path("exam/<int:pk>/<str:cid>/<str:passcode>/finish", views.exam_finish, name="exam_finish"), path(
path("exam/<int:pk>/", views.PhysicsExamViews.exam_overview, name="exam_overview"), "exam/<int:pk>/<str:cid>/<str:passcode>/finish",
path("exam/<int:pk>/scores", views.exam_scores_cid, views.exam_finish,
name="exam_scores_cid"), name="exam_finish",
path("exam/<int:pk>/scores/<int:cid>/<str:passcode>/", views.exam_scores_cid_user, ),
name="exam_scores_cid_user"), path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
path("exam/<int:pk>/toggle_active", views.PhysicsExamViews.exam_toggle_active, name="exam_toggle_active"), path("exam/<int:pk>/scores", views.exam_scores_cid, name="exam_scores_cid"),
path("exam/<int:pk>/toggle_results_published", views.PhysicsExamViews.exam_toggle_results_published, name="exam_toggle_results_published"), path(
"exam/<int:pk>/scores/<int:cid>/<str:passcode>/",
views.exam_scores_cid_user,
name="exam_scores_cid_user",
),
path(
"exam/<int:pk>/toggle_active",
views.GenericExamViews.exam_toggle_active,
name="exam_toggle_active",
),
path(
"exam/<int:pk>/toggle_results_published",
views.GenericExamViews.exam_toggle_results_published,
name="exam_toggle_results_published",
),
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"), path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"), path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"), path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
path("exam/submit", views.PhysicsExamViews.postExamAnswers, name="exam_answers_submit"), path(
path("exam/", views.PhysicsExamViews.exam_list, name="exam_list"), "exam/submit",
views.GenericExamViews.postExamAnswers,
name="exam_answers_submit",
),
path("exam/", views.GenericExamViews.exam_list, name="exam_list"),
path("exam/available", views.active_exams, name="active_exams"), path("exam/available", 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("user_answers/", views.UserAnswerTableView.as_view(), name="user_answer_table_view"), path(
"user_answers/",
views.UserAnswerTableView.as_view(),
name="user_answer_table_view",
),
path( path(
"user_answers/<int:pk>", views.UserAnswerView.as_view(), name="user_answer_view" "user_answers/<int:pk>", views.UserAnswerView.as_view(), name="user_answer_view"
), ),
+1 -1
View File
@@ -463,7 +463,7 @@ def loadJsonAnswer(answer):
return True, None return True, None
PhysicsExamViews = ExamViews( GenericExamViews = ExamViews(
Exam, Question, CidUserAnswer, "physics", "physics", loadJsonAnswer Exam, Question, CidUserAnswer, "physics", "physics", loadJsonAnswer
) )
+26 -23
View File
@@ -47,9 +47,9 @@ from sbas.models import CidUserAnswer as SbasCidUserAnswer
from sbas.models import Exam as SbasExam from sbas.models import Exam as SbasExam
from sbas.models import Question as SbasQuestion from sbas.models import Question as SbasQuestion
from anatomy.views import AnatomyExamViews from anatomy.views import GenericExamViews
from rapids.views import RapidExamViews from rapids.views import GenericExamViews
from longs.views import LongExamViews from longs.views import GenericExamViews
from generic.forms import QuestionNoteForm from generic.forms import QuestionNoteForm
from generic.models import CidUser, QuestionNote from generic.models import CidUser, QuestionNote
@@ -75,6 +75,7 @@ def cid_selector(request):
"cid_selector.html", "cid_selector.html",
) )
@login_required @login_required
@user_passes_test(lambda u: u.is_superuser) @user_passes_test(lambda u: u.is_superuser)
def cid_scores_admin(request, cid): def cid_scores_admin(request, cid):
@@ -82,6 +83,7 @@ def cid_scores_admin(request, cid):
return cid_scores(request, cid_user.cid, cid_user.passcode) return cid_scores(request, cid_user.cid, cid_user.passcode)
def cid_scores(request, pk, passcode): def cid_scores(request, pk, passcode):
# exam = get_object_or_404(Exam, pk=pk) # exam = get_object_or_404(Exam, pk=pk)
@@ -95,11 +97,11 @@ def cid_scores(request, pk, passcode):
# questions = exam.exam_questions.all() # questions = exam.exam_questions.all()
EXAM_ANSWER_MAP = { EXAM_ANSWER_MAP = {
"physics" : (PhysicsCidUserAnswer, PhysicsExam), "physics": (PhysicsCidUserAnswer, PhysicsExam),
"anatomy" : (AnatomyCidUserAnswer, AnatomyExam), "anatomy": (AnatomyCidUserAnswer, AnatomyExam),
"rapids" : (RapidsCidUserAnswer, RapidsExam), "rapids": (RapidsCidUserAnswer, RapidsExam),
"longs" : (LongsCidUserAnswer, LongsExam), "longs": (LongsCidUserAnswer, LongsExam),
"sbas" : (SbasCidUserAnswer, SbasExam), "sbas": (SbasCidUserAnswer, SbasExam),
} }
kwargs = {"exam_mode": True} kwargs = {"exam_mode": True}
@@ -110,18 +112,17 @@ def cid_scores(request, pk, passcode):
exam_ids = exam_answers.values_list("exam").distinct() exam_ids = exam_answers.values_list("exam").distinct()
exams.append((exam_type, Exam.objects.filter(id__in=exam_ids, **kwargs))) exams.append((exam_type, Exam.objects.filter(id__in=exam_ids, **kwargs)))
available_exams = cid_user.get_cid_exams() available_exams = cid_user.get_cid_exams()
return render( return render(
request, request,
"cid_scores.html", "cid_scores.html",
{ {
#"physics_exams": physics_exams, # "physics_exams": physics_exams,
#"anatomy_exams": anatomy_exams, # "anatomy_exams": anatomy_exams,
#"rapid_exams": rapid_exams, # "rapid_exams": rapid_exams,
#"longs_exams": longs_exams, # "longs_exams": longs_exams,
#"sba_exams": sba_exams, # "sba_exams": sba_exams,
"all_exams": exams, "all_exams": exams,
"cid": cid, "cid": cid,
"passcode": passcode, "passcode": passcode,
@@ -140,13 +141,15 @@ def active_exams(request, cid=None, passcode=None):
if not cid_user or cid_user.passcode != passcode: if not cid_user or cid_user.passcode != passcode:
return JsonResponse({"status": "invalid"}, status=401) return JsonResponse({"status": "invalid"}, status=401)
anatomy_exams = AnatomyExamViews.active_exams( anatomy_exams = GenericExamViews.active_exams(
request, False, cid=cid, passcode=passcode request, False, cid=cid, passcode=passcode
) )
rapid_exams = RapidExamViews.active_exams( rapid_exams = GenericExamViews.active_exams(
request, False, cid=cid, passcode=passcode
)
long_exams = GenericExamViews.active_exams(
request, False, cid=cid, passcode=passcode request, False, cid=cid, passcode=passcode
) )
long_exams = LongExamViews.active_exams(request, False, cid=cid, passcode=passcode)
exams = [] exams = []
exams.extend(anatomy_exams) exams.extend(anatomy_exams)
@@ -164,9 +167,9 @@ def active_exams(request, cid=None, passcode=None):
def active_exams_unbased(request): def active_exams_unbased(request):
anatomy_exams = AnatomyExamViews.active_exams(request, False, False) anatomy_exams = GenericExamViews.active_exams(request, False, False)
rapid_exams = RapidExamViews.active_exams(request, False, False) rapid_exams = GenericExamViews.active_exams(request, False, False)
long_exams = LongExamViews.active_exams(request, False, False) long_exams = GenericExamViews.active_exams(request, False, False)
exams = [] exams = []
exams.extend(anatomy_exams) exams.extend(anatomy_exams)
@@ -189,11 +192,11 @@ def exam_submit(request):
exam_type, exam_id = request.POST.get("eid").split("/") exam_type, exam_id = request.POST.get("eid").split("/")
if exam_type == "anatomy": if exam_type == "anatomy":
return AnatomyExamViews.postExamAnswers(request) return GenericExamViews.postExamAnswers(request)
elif exam_type == "rapid": elif exam_type == "rapid":
return RapidExamViews.postExamAnswers(request) return GenericExamViews.postExamAnswers(request)
elif exam_type == "long": elif exam_type == "long":
return LongExamViews.postExamAnswers(request) return GenericExamViews.postExamAnswers(request)
return JsonResponse({"success": False, "error": "Invalid exam type"}) return JsonResponse({"success": False, "error": "Invalid exam type"})
# postExamAnswers # postExamAnswers
+19 -17
View File
@@ -8,7 +8,7 @@ app_name = "rapids"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.RapidExamViews.index, name="index"), path("", views.GenericExamViews.index, name="index"),
path("author/<int:pk>/", views.GenericViews.author_detail, name="author_detail"), path("author/<int:pk>/", views.GenericViews.author_detail, name="author_detail"),
path("author/", views.GenericViews.author_list, name="author_list"), path("author/", views.GenericViews.author_list, name="author_list"),
path("question_viewer", views.question_viewer, name="question_viewer"), path("question_viewer", views.question_viewer, name="question_viewer"),
@@ -56,28 +56,28 @@ urlpatterns = [
"exam/<int:exam_pk>/<int:sk>/mark/review", views.mark_review, name="mark_review" "exam/<int:exam_pk>/<int:sk>/mark/review", views.mark_review, name="mark_review"
), ),
path( path(
"exam/<int:pk>/mark", views.RapidExamViews.mark_overview, name="mark_overview" "exam/<int:pk>/mark", views.GenericExamViews.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"),
path( path(
"exam/<int:pk>/question/<int:sk>/", "exam/<int:pk>/question/<int:sk>/",
views.RapidExamViews.exam_question_detail, views.GenericExamViews.exam_question_detail,
name="exam_question_detail", name="exam_question_detail",
), ),
path("exam/<int:pk>/", views.RapidExamViews.exam_overview, name="exam_overview"), path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
path( path(
"exam/<int:pk>/json_edit", "exam/<int:pk>/json_edit",
views.RapidExamViews.exam_json_edit, views.GenericExamViews.exam_json_edit,
name="exam_json_edit", name="exam_json_edit",
), ),
path( path(
"exam/<int:pk>/scores", "exam/<int:pk>/scores",
views.RapidExamViews.exam_scores_cid, views.GenericExamViews.exam_scores_cid,
name="exam_scores_cid", name="exam_scores_cid",
), ),
path( path(
"exam/<int:pk>/scores/refresh", "exam/<int:pk>/scores/refresh",
views.RapidExamViews.exam_scores_refresh, views.GenericExamViews.exam_scores_refresh,
# cache_page(60 * 1)(views.exam_scores_cid), # cache_page(60 * 1)(views.exam_scores_cid),
name="exam_scores_refresh", name="exam_scores_refresh",
), ),
@@ -88,38 +88,40 @@ urlpatterns = [
), ),
path( path(
"exam/<int:pk>/toggle_active", "exam/<int:pk>/toggle_active",
views.RapidExamViews.exam_toggle_active, views.GenericExamViews.exam_toggle_active,
name="exam_toggle_active", name="exam_toggle_active",
), ),
path( path(
"exam/<int:pk>/toggle_results_published", "exam/<int:pk>/toggle_results_published",
views.RapidExamViews.exam_toggle_results_published, views.GenericExamViews.exam_toggle_results_published,
name="exam_toggle_results_published", name="exam_toggle_results_published",
), ),
path( path(
"exam/submit", views.RapidExamViews.postExamAnswers, name="exam_answers_submit" "exam/submit",
views.GenericExamViews.postExamAnswers,
name="exam_answers_submit",
), ),
path("exam/", views.RapidExamViews.exam_list, name="exam_list"), path("exam/", views.GenericExamViews.exam_list, name="exam_list"),
path("exam/all", views.RapidExamViews.exam_list_all, name="exam_list_all"), path("exam/all", views.GenericExamViews.exam_list_all, name="exam_list_all"),
path("exam/create", views.ExamCreate.as_view(), name="exam_create"), path("exam/create", views.ExamCreate.as_view(), name="exam_create"),
path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"), path("exam/<int:exam_id>/clone", views.ExamClone.as_view(), name="exam_clone"),
path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"), path("exam/<int:pk>/update", views.ExamUpdate.as_view(), name="exam_update"),
path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"), path("exam/<int:pk>/delete", views.ExamDelete.as_view(), name="exam_delete"),
path("exam/json/", views.RapidExamViews.active_exams, name="active_exams"), path("exam/json/", views.GenericExamViews.active_exams, name="active_exams"),
path("exam/json/<int:pk>", views.RapidExamViews.exam_json, name="exam_json"), path("exam/json/<int:pk>", views.GenericExamViews.exam_json, name="exam_json"),
path( path(
"exam/json/<int:pk>/unbased", "exam/json/<int:pk>/unbased",
views.RapidExamViews.exam_json_unbased, views.GenericExamViews.exam_json_unbased,
name="exam_json_unbased", name="exam_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/<int:sk>/unbased", "exam/json/<int:pk>/<int:sk>/unbased",
views.RapidExamViews.exam_question_json_unbased, views.GenericExamViews.exam_question_json_unbased,
name="exam_question_json_unbased", name="exam_question_json_unbased",
), ),
path( path(
"exam/json/<int:pk>/recreate", "exam/json/<int:pk>/recreate",
views.RapidExamViews.exam_json_recreate, views.GenericExamViews.exam_json_recreate,
name="exam_json_recreate", name="exam_json_recreate",
), ),
path("create/", views.RapidCreate.as_view(), name="rapid_create"), path("create/", views.RapidCreate.as_view(), name="rapid_create"),
+1 -1
View File
@@ -1047,7 +1047,7 @@ class QuestionDelete(AuthorOrCheckerRequiredMixin, DeleteView):
success_url = reverse_lazy("rapids:rapid_view") success_url = reverse_lazy("rapids:rapid_view")
RapidExamViews = ExamViews( GenericExamViews = ExamViews(
Exam, Rapid, CidUserAnswer, "rapids", "rapid", loadJsonAnswer Exam, Rapid, CidUserAnswer, "rapids", "rapid", loadJsonAnswer
) )
+16 -8
View File
@@ -7,17 +7,25 @@ app_name = "sbas"
urlpatterns = [ urlpatterns = [
# path('', views.question_list, name='question_list'), # path('', views.question_list, name='question_list'),
path("", views.SbasExamViews.index, name="index"), path("", views.GenericExamViews.index, name="index"),
path("question/", views.QuestionView.as_view(), name="question_view"), path("question/", views.QuestionView.as_view(), name="question_view"),
path("question/<int:pk>/", views.question_detail, name="question_detail"), path("question/<int:pk>/", views.question_detail, name="question_detail"),
# path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"), # path("question/create/", views.QuestionCreate.as_view(), name="anatomy_question_create"),
# path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"), # path("question/<int:pk>/update", views.QuestionUpdate.as_view(), name="anatomy_question_update"),
# 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>/<str:cid>/<str:passcode>/take", views.exam_take, name="exam_take"), path(
"exam/<int:pk>/<int:sk>/<str:cid>/<str:passcode>/take",
views.exam_take,
name="exam_take",
),
path("exam/<int:pk>/start", views.exam_start, name="exam_start"), path("exam/<int:pk>/start", views.exam_start, name="exam_start"),
path("exam/<int:pk>/<str:cid>/<str:passcode>/finish", views.exam_finish, name="exam_finish"), path(
path("exam/<int:pk>/", views.SbasExamViews.exam_overview, name="exam_overview"), "exam/<int:pk>/<str:cid>/<str:passcode>/finish",
views.exam_finish,
name="exam_finish",
),
path("exam/<int:pk>/", views.GenericExamViews.exam_overview, name="exam_overview"),
path( path(
"exam/<int:pk>/scores", "exam/<int:pk>/scores",
cache_page(60 * 1)(views.exam_scores_cid), cache_page(60 * 1)(views.exam_scores_cid),
@@ -30,16 +38,16 @@ urlpatterns = [
), ),
path( path(
"exam/<int:pk>/toggle_active", "exam/<int:pk>/toggle_active",
views.SbasExamViews.exam_toggle_active, views.GenericExamViews.exam_toggle_active,
name="exam_toggle_active", name="exam_toggle_active",
), ),
path( path(
"exam/<int:pk>/toggle_results_published", "exam/<int:pk>/toggle_results_published",
views.SbasExamViews.exam_toggle_results_published, views.GenericExamViews.exam_toggle_results_published,
name="exam_toggle_results_published", name="exam_toggle_results_published",
), ),
# path("exam/submit", views.PhysicsExamViews.postExamAnswers, name="exam_answers_submit"), # path("exam/submit", views.GenericExamViews.postExamAnswers, name="exam_answers_submit"),
path("exam/", views.SbasExamViews.exam_list, name="exam_list"), path("exam/", views.GenericExamViews.exam_list, name="exam_list"),
path("exam/available", views.active_exams, name="active_exams"), path("exam/available", 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"),
+29 -15
View File
@@ -47,6 +47,7 @@ from django.core.exceptions import PermissionDenied
from .tables import QuestionTable, UserAnswerTable from .tables import QuestionTable, UserAnswerTable
from .filters import QuestionFilter, UserAnswerFilter from .filters import QuestionFilter, UserAnswerFilter
class AuthorOrCheckerRequiredMixin(object): class AuthorOrCheckerRequiredMixin(object):
def get_object(self, *args, **kwargs): def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs) obj = super().get_object(*args, **kwargs)
@@ -56,6 +57,7 @@ class AuthorOrCheckerRequiredMixin(object):
raise PermissionDenied() # or Http404 raise PermissionDenied() # or Http404
return obj return obj
def question_list(request): def question_list(request):
questions = Question.objects.all() questions = Question.objects.all()
return render(request, "sbas/question_list.html", {"questions": questions}) return render(request, "sbas/question_list.html", {"questions": questions})
@@ -109,9 +111,17 @@ def exam_scores_cid(request, pk):
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first() s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
if not s: if not s:
# skip if no answer # skip if no answer
user_answers_marks[cid].append((0,0,0,0,0)) user_answers_marks[cid].append((0, 0, 0, 0, 0))
user_answers[cid].append(("", "", "", "", "")) user_answers[cid].append(("", "", "", "", ""))
by_question[q].append((("", 0),("", 0),("", 0),("", 0),("", 0),)) by_question[q].append(
(
("", 0),
("", 0),
("", 0),
("", 0),
("", 0),
)
)
continue continue
ans = s.get_answer() ans = s.get_answer()
@@ -191,7 +201,6 @@ def exam_scores_cid_user(request, pk, sk, passcode):
answers_marks = [] answers_marks = []
answers = [] answers = []
view_all_results = False view_all_results = False
if request.user.groups.filter(name="view_all_results").exists(): if request.user.groups.filter(name="view_all_results").exists():
view_all_results = True view_all_results = True
@@ -200,7 +209,6 @@ def exam_scores_cid_user(request, pk, sk, passcode):
# Get user answer # Get user answer
user_answer = q.cid_user_answers.filter(cid=cid).first() user_answer = q.cid_user_answers.filter(cid=cid).first()
if user_answer is None: if user_answer is None:
answer_score = 0 answer_score = 0
ans = "" ans = ""
@@ -229,7 +237,7 @@ def exam_scores_cid_user(request, pk, sk, passcode):
{ {
"exam": exam, "exam": exam,
"cid": cid, "cid": cid,
"passcode" : passcode, "passcode": passcode,
"questions": questions, "questions": questions,
"answers": answers, "answers": answers,
"answers_marks": answers_marks, "answers_marks": answers_marks,
@@ -254,6 +262,7 @@ def exam_start(request, pk):
}, },
) )
def exam_finish(request, pk, cid, passcode): def exam_finish(request, pk, cid, passcode):
exam = get_object_or_404(Exam, pk=pk) exam = get_object_or_404(Exam, pk=pk)
@@ -262,8 +271,7 @@ def exam_finish(request, pk, cid, passcode):
questions = exam.exam_questions.all() questions = exam.exam_questions.all()
answers = CidUserAnswer.objects.filter( answers = CidUserAnswer.objects.filter(cid=cid, exam=exam)
cid=cid, exam=exam)
answer_question_map = {} answer_question_map = {}
for ans in answers: for ans in answers:
@@ -311,8 +319,7 @@ def exam_take(request, pk, sk, cid, passcode):
pos = exam.get_question_index(question) pos = exam.get_question_index(question)
answer = question.cid_user_answers.filter( answer = question.cid_user_answers.filter(cid=cid, exam=exam).first()
cid=cid, exam=exam).first()
if request.method == "POST": if request.method == "POST":
if answer: if answer:
@@ -336,7 +343,9 @@ def exam_take(request, pk, sk, cid, passcode):
elif "finish" in request.POST: elif "finish" in request.POST:
return redirect("sbas:exam_finish", **kwargs) return redirect("sbas:exam_finish", **kwargs)
elif "goto" in request.POST: elif "goto" in request.POST:
return redirect("sbas:exam_take", sk=int(request.POST.get("goto")), **kwargs) return redirect(
"sbas:exam_take", sk=int(request.POST.get("goto")), **kwargs
)
else: else:
form = CidUserAnswerForm(instance=answer) form = CidUserAnswerForm(instance=answer)
@@ -351,7 +360,6 @@ def exam_take(request, pk, sk, cid, passcode):
if answer is not None: if answer is not None:
saved_answer = answer.answer saved_answer = answer.answer
return render( return render(
request, request,
"sbas/exam_take.html", "sbas/exam_take.html",
@@ -373,7 +381,11 @@ def exam_take(request, pk, sk, cid, passcode):
def loadJsonAnswer(answer): def loadJsonAnswer(answer):
pass pass
SbasExamViews = ExamViews(Exam, Question, CidUserAnswer, "sbas", "sbas", loadJsonAnswer)
GenericExamViews = ExamViews(
Exam, Question, CidUserAnswer, "sbas", "sbas", loadJsonAnswer
)
class QuestionView(LoginRequiredMixin, SingleTableMixin, FilterView): class QuestionView(LoginRequiredMixin, SingleTableMixin, FilterView):
model = Question model = Question
@@ -382,6 +394,7 @@ class QuestionView(LoginRequiredMixin, SingleTableMixin, FilterView):
filterset_class = QuestionFilter filterset_class = QuestionFilter
class UserAnswerView(LoginRequiredMixin, DetailView): class UserAnswerView(LoginRequiredMixin, DetailView):
model = CidUserAnswer model = CidUserAnswer
@@ -399,8 +412,9 @@ class UserAnswerDelete(SuperuserRequiredMixin, DeleteView):
template_name = "user_answer_delete.html" template_name = "user_answer_delete.html"
success_url = reverse_lazy("sbas:user_answer_table_view") success_url = reverse_lazy("sbas:user_answer_table_view")
#@user_passes_test(lambda u: u.is_superuser)
#def user_answer_delete_multiple(request): # @user_passes_test(lambda u: u.is_superuser)
# def user_answer_delete_multiple(request):
# if request.is_ajax(): # if request.is_ajax():
# print(request.POST["answer_ids"]) # print(request.POST["answer_ids"])
# answer_ids = json.loads(request.POST["answer_ids"]) # answer_ids = json.loads(request.POST["answer_ids"])
@@ -412,4 +426,4 @@ class UserAnswerDelete(SuperuserRequiredMixin, DeleteView):
# return JsonResponse({"status": "error"}) # return JsonResponse({"status": "error"})
GenericViews = GenericViewBase("sbas", Question, CidUserAnswer, Exam) GenericViews = GenericViewBase("sbas", Question, CidUserAnswer, Exam)