SkyLearn-Test/quiz/views.py
2021-03-25 16:13:17 +03:00

322 lines
13 KiB
Python

import random
from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404, render, redirect
from django.utils.decorators import method_decorator
from django.views.generic import DetailView, ListView, TemplateView, FormView, CreateView, FormView, DeleteView, UpdateView
from django.contrib import messages
from django.urls import reverse_lazy
from django.db import transaction
from django.forms import inlineformset_factory
from django.http import HttpResponseRedirect
from accounts.decorators import student_required, lecturer_required
from .models import *
from .forms import *
@method_decorator([login_required, lecturer_required], name='dispatch')
class QuizCreateView(CreateView):
model = Quiz
form_class = QuizAddForm
def get_context_data(self, *args, **kwargs):
context = super(QuizCreateView, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
if self.request.POST:
context['form'] = QuizAddForm(self.request.POST)
# context['quiz'] = self.request.POST.get('quiz')
else:
context['form'] = QuizAddForm(initial={'course': Course.objects.get(slug=self.kwargs['slug'])})
return context
def form_valid(self, form, **kwargs):
context = self.get_context_data()
form = context['form']
with transaction.atomic():
self.object = form.save()
if form.is_valid():
form.instance = self.object
form.save()
return redirect('mc_create', slug=self.kwargs['slug'], quiz_id=form.instance.id)
return super(QuizCreateView, self).form_invalid(form)
@method_decorator([login_required, lecturer_required], name='dispatch')
class QuizUpdateView(UpdateView):
model = Quiz
form_class = QuizAddForm
def get_context_data(self, *args, **kwargs):
context = super(QuizUpdateView, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
quiz = Quiz.objects.get(pk=self.kwargs['pk'])
if self.request.POST:
context['form'] = QuizAddForm(self.request.POST, instance=quiz)
else:
context['form'] = QuizAddForm(instance=quiz)
return context
def form_valid(self, form, **kwargs):
context = self.get_context_data()
course = context['course']
form = context['form']
with transaction.atomic():
self.object = form.save()
if form.is_valid():
form.instance = self.object
form.save()
return redirect('quiz_index', course.slug)
return super(QuizUpdateView, self).form_invalid(form)
@login_required
@lecturer_required
def quiz_delete(request, slug, pk):
quiz = Quiz.objects.get(pk=pk)
course = Course.objects.get(slug=slug)
quiz.delete()
messages.success(request, f'successfuly deleted.')
return redirect('quiz_index', quiz.course.slug)
@method_decorator([login_required, lecturer_required], name='dispatch')
class MCQuestionCreate(CreateView):
model = MCQuestion
form_class = MCQuestionForm
def get_context_data(self, **kwargs):
context = super(MCQuestionCreate, self).get_context_data(**kwargs)
context['course'] = Course.objects.get(slug=self.kwargs['slug'])
context['quiz_obj'] = Quiz.objects.get(id=self.kwargs['quiz_id'])
context['quizQuestions'] = Question.objects.filter(quiz=self.kwargs['quiz_id']).count()
if self.request.POST:
context['form'] = MCQuestionForm(self.request.POST)
context['formset'] = MCQuestionFormSet(self.request.POST)
else:
context['form'] = MCQuestionForm(initial={'quiz': self.kwargs['quiz_id']})
context['formset'] = MCQuestionFormSet()
return context
def form_valid(self, form):
context = self.get_context_data()
formset = context['formset']
course = context['course']
with transaction.atomic():
form.instance.question = self.request.POST.get('content')
self.object = form.save()
if formset.is_valid():
formset.instance = self.object
formset.save()
if "another" in self.request.POST:
return redirect('mc_create', slug=self.kwargs['slug'], quiz_id=self.kwargs['quiz_id'])
return redirect('quiz_index', course.slug)
return super(MCQuestionCreate, self).form_invalid(form)
@login_required
def quiz_list(request, slug):
quizzes = Quiz.objects.filter(course__slug = slug).order_by('-timestamp')
course = Course.objects.get(slug = slug)
return render(request, 'quiz/quiz_list.html', {'quizzes': quizzes, 'course': course})
# return render(request, 'quiz/quiz_list.html', {'quizzes': quizzes})
@method_decorator([login_required, lecturer_required], name='dispatch')
class QuizMarkerMixin(object):
@method_decorator(login_required)
# @method_decorator(permission_required('quiz.view_sittings'))
def dispatch(self, *args, **kwargs):
return super(QuizMarkerMixin, self).dispatch(*args, **kwargs)
# @method_decorator([login_required, lecturer_required], name='get_queryset')
class SittingFilterTitleMixin(object):
def get_queryset(self):
queryset = super(SittingFilterTitleMixin, self).get_queryset()
quiz_filter = self.request.GET.get('quiz_filter')
if quiz_filter:
queryset = queryset.filter(quiz__title__icontains=quiz_filter)
return queryset
@method_decorator([login_required], name='dispatch')
class QuizUserProgressView(TemplateView):
template_name = 'progress.html'
def dispatch(self, request, *args, **kwargs):
return super(QuizUserProgressView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(QuizUserProgressView, self).get_context_data(**kwargs)
progress, c = Progress.objects.get_or_create(user=self.request.user)
context['cat_scores'] = progress.list_all_cat_scores
context['exams'] = progress.show_exams()
context['exams_counter'] = progress.show_exams().count()
return context
from result.models import TakenCourse
@method_decorator([login_required, lecturer_required], name='dispatch')
class QuizMarkingList(QuizMarkerMixin, SittingFilterTitleMixin, ListView):
model = Sitting
# def get_context_data(self, **kwargs):
# context = super(QuizMarkingList, self).get_context_data(**kwargs)
# context['queryset_counter'] = super(QuizMarkingList, self).get_queryset().filter(complete=True).filter(course__allocated_course__lecturer__pk=self.request.user.id).count()
# context['marking_list'] = super(QuizMarkingList, self).get_queryset().filter(complete=True).filter(course__allocated_course__lecturer__pk=self.request.user.id)
# return context
def get_queryset(self):
if self.request.user.is_superuser:
queryset = super(QuizMarkingList, self).get_queryset().filter(complete=True)
else:
queryset = super(QuizMarkingList, self).get_queryset().filter(quiz__course__allocated_course__lecturer__pk=self.request.user.id).filter(complete=True)
# search by user
user_filter = self.request.GET.get('user_filter')
if user_filter:
queryset = queryset.filter(user__username__icontains=user_filter)
return queryset
@method_decorator([login_required, lecturer_required], name='dispatch')
class QuizMarkingDetail(QuizMarkerMixin, DetailView):
model = Sitting
def post(self, request, *args, **kwargs):
sitting = self.get_object()
q_to_toggle = request.POST.get('qid', None)
if q_to_toggle:
q = Question.objects.get_subclass(id=int(q_to_toggle))
if int(q_to_toggle) in sitting.get_incorrect_questions:
sitting.remove_incorrect_question(q)
else:
sitting.add_incorrect_question(q)
return self.get(request)
def get_context_data(self, **kwargs):
context = super(QuizMarkingDetail, self).get_context_data(**kwargs)
context['questions'] = context['sitting'].get_questions(with_answers=True)
return context
# @method_decorator([login_required, student_required], name='dispatch')
@method_decorator([login_required], name='dispatch')
class QuizTake(FormView):
form_class = QuestionForm
template_name = 'question.html'
result_template_name = 'result.html'
# single_complete_template_name = 'single_complete.html'
def dispatch(self, request, *args, **kwargs):
self.quiz = get_object_or_404(Quiz, slug=self.kwargs['slug'])
self.course = get_object_or_404(Course, pk=self.kwargs['pk'])
quizQuestions = Question.objects.filter(quiz=self.quiz).count()
course = get_object_or_404(Course, pk=self.kwargs['pk'])
if quizQuestions <= 0:
messages.warning(request, f'Question set of the quiz is empty. try later!')
return redirect('quiz_index', self.course.slug)
if self.quiz.draft and not request.user.has_perm('quiz.change_quiz'):
raise PermissionDenied
self.sitting = Sitting.objects.user_sitting(request.user, self.quiz, self.course)
if self.sitting is False:
# return render(request, self.single_complete_template_name)
messages.info(request, f'You have already sat this exam and only one sitting is permitted')
return redirect('quiz_index', self.course.slug)
return super(QuizTake, self).dispatch(request, *args, **kwargs)
def get_form(self, *args, **kwargs):
self.question = self.sitting.get_first_question()
self.progress = self.sitting.progress()
if self.question.__class__ is Essay_Question:
form_class = EssayForm
else:
form_class = self.form_class
return form_class(**self.get_form_kwargs())
def get_form_kwargs(self):
kwargs = super(QuizTake, self).get_form_kwargs()
return dict(kwargs, question=self.question)
def form_valid(self, form):
self.form_valid_user(form)
if self.sitting.get_first_question() is False:
return self.final_result_user()
self.request.POST = {}
return super(QuizTake, self).get(self, self.request)
def get_context_data(self, **kwargs):
context = super(QuizTake, self).get_context_data(**kwargs)
context['question'] = self.question
context['quiz'] = self.quiz
context['course'] = get_object_or_404(Course, pk=self.kwargs['pk'])
if hasattr(self, 'previous'):
context['previous'] = self.previous
if hasattr(self, 'progress'):
context['progress'] = self.progress
return context
def form_valid_user(self, form):
progress, c = Progress.objects.get_or_create(user=self.request.user)
guess = form.cleaned_data['answers']
is_correct = self.question.check_if_correct(guess)
if is_correct is True:
self.sitting.add_to_score(1)
progress.update_score(self.question, 1, 1)
else:
self.sitting.add_incorrect_question(self.question)
progress.update_score(self.question, 0, 1)
if self.quiz.answers_at_end is not True:
self.previous = {
'previous_answer': guess,
'previous_outcome': is_correct,
'previous_question': self.question,
'answers': self.question.get_choices(),
'question_type': {self.question.__class__.__name__: True}
}
else:
self.previous = {}
self.sitting.add_user_answer(self.question, guess)
self.sitting.remove_first_question()
def final_result_user(self):
results = {
'course': get_object_or_404(Course, pk=self.kwargs['pk']),
'quiz': self.quiz,
'score': self.sitting.get_current_score,
'max_score': self.sitting.get_max_score,
'percent': self.sitting.get_percent_correct,
'sitting': self.sitting,
'previous': self.previous,
'course': get_object_or_404(Course, pk=self.kwargs['pk'])
}
self.sitting.mark_quiz_complete()
if self.quiz.answers_at_end:
results['questions'] = self.sitting.get_questions(with_answers=True)
results['incorrect_questions'] = self.sitting.get_incorrect_questions
if self.quiz.exam_paper is False or self.request.user.is_superuser or self.request.user.is_lecturer :
self.sitting.delete()
return render(self.request, self.result_template_name, results)