Skip to content

Commit

Permalink
Merge pull request #36 from robotveradev/VJB-15
Browse files Browse the repository at this point in the history
VJB-15 Quiz application code refactoring.
  • Loading branch information
Klyaus authored Jul 2, 2018
2 parents ee99674 + 15e8f16 commit 02060c5
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 54 deletions.
54 changes: 35 additions & 19 deletions quiz/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.db.models import Max, Sum
from django.urls import reverse
from jsonfield import JSONField

from jobboard.helpers import BaseAction


class Category(models.Model):
title = models.CharField(max_length=255)
Expand Down Expand Up @@ -57,17 +60,20 @@ def __str__(self):

@property
def max_points(self):
if self.kind.one_right_answer:
max_points = self.answers.all().aggregate(max=Max('weight'))['max'] * self.weight
else:
max_points = self.answers.filter(weight__gt=0).aggregate(sum=Sum('weight'))['sum'] * self.weight
return max_points
if self.kind:
if self.kind.one_right_answer:
max_points = self.answers.all().aggregate(max=Max('weight'))['max'] * self.weight
else:
max_points = self.answers.filter(weight__gt=0).aggregate(sum=Sum('weight'))['sum'] * self.weight
return max_points
return 0


class Answer(models.Model):
text = models.TextField(verbose_name=u'Answer\'s text')
weight = models.SmallIntegerField(default=1,
help_text=u'Value from -100 to 100')
help_text=u'Value from -100 to 100',
validators=[MinValueValidator(-100), MaxValueValidator(100)])
question = models.ForeignKey(Question,
related_name='answers',
on_delete=models.CASCADE)
Expand All @@ -79,11 +85,11 @@ class Meta:
ordering = ('?',)


class ActionExam(models.Model):
class ActionExam(BaseAction, models.Model):
action = models.OneToOneField('pipeline.Action',
on_delete=models.SET_NULL,
null=True,
related_name='exam')
on_delete=models.CASCADE,
null=False,
related_name='exam')
questions = models.ManyToManyField(Question)
max_attempts = models.PositiveIntegerField(default=3)
passing_grade = models.PositiveIntegerField(default=0)
Expand All @@ -92,15 +98,28 @@ class ActionExam(models.Model):
def __str__(self):
return 'Exam for "{}"'.format(self.action)

def get_absolute_url(self):
def get_candidate_url(self):
return reverse('candidate_examining', kwargs={'pk': self.pk})

def get_result_url(self, **kwargs):
return reverse('exam_result', kwargs={'exam_id': self.id, 'candidate_id': kwargs.get('candidate_id')})

def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if self.id:
if self.questions.count() == 0:
return self.delete()
super().save(force_insert, force_update, using, update_fields)

class Meta:
abstract = False


class ExamPassed(models.Model):
profile = models.ForeignKey('candidateprofile.CandidateProfile',
on_delete=models.SET_NULL,
null=True,
related_name='exams')
candidate = models.ForeignKey('jobboard.Candidate',
on_delete=models.SET_NULL,
null=True,
related_name='exams')
exam = models.ForeignKey(ActionExam,
on_delete=models.SET_NULL,
null=True)
Expand All @@ -111,10 +130,7 @@ class ExamPassed(models.Model):
updated_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return '{}'.format(self.profile.candidate.contract_address)

def get_absolute_url(self):
return reverse('exam_results', kwargs={'pk': self.id})
return '{} exam result'.format(self.candidate.contract_address)


class AnswerForVerification(models.Model):
Expand Down
14 changes: 8 additions & 6 deletions quiz/signals/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@
from django.dispatch import receiver

from jobboard.handlers.oracle import OracleHandler
from jobboard.tasks import save_txn_to_history
from quiz.models import ExamPassed, AnswerForVerification, ActionExam
from quiz.tasks import ProcessExam, VerifyAnswer
from pipeline.tasks import candidate_level_up


@receiver(post_save, sender=ExamPassed)
def candidate_pass_exam(sender, instance, created, **kwargs):
if created:
if created or not instance.processed:
pr = ProcessExam()
pr.delay(instance.id)
else:
if instance.processed and instance.points >= instance.exam.passing_grade:
oracle = OracleHandler()
print(oracle.current_cv_action_on_vacancy(instance.exam.action.pipeline.vacancy.uuid, instance.cv.uuid))
txn_hash = oracle.level_up(instance.exam.action.pipeline.vacancy.uuid, instance.cv.uuid)
save_txn_to_history.delay(instance.cv.candidate.user.id, txn_hash.hex(),
'Level up on vacancy {}'.format(instance.exam.action.pipeline.vacancy.title))
cci = oracle.get_candidate_current_action_index(instance.exam.action.pipeline.vacancy.uuid,
instance.candidate.contract_address)
if cci == instance.exam.action.index:
action_bch = oracle.get_action(instance.exam.action.pipeline.vacancy.uuid, cci)
if not action_bch['approvable']:
candidate_level_up.delay(instance.exam.action.pipeline.vacancy.id, instance.candidate.id)


@receiver(pre_save, sender=AnswerForVerification)
Expand Down
84 changes: 55 additions & 29 deletions quiz/views.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from django.contrib import messages
from django.http import HttpResponseRedirect, HttpResponse
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse_lazy, reverse
from django.views import View
from django.views.generic import TemplateView, CreateView, DetailView, ListView, UpdateView
from django.views.generic.edit import BaseUpdateView

from candidateprofile.models import CandidateProfile
from jobboard.handlers.oracle import OracleHandler
from jobboard.mixins import OnlyEmployerMixin, OnlyCandidateMixin
from jobboard.models import Candidate
from pipeline.models import Action
from quiz.forms import CategoryForm
from quiz.models import ActionExam, Category, Question, Answer, QuestionKind, ExamPassed, AnswerForVerification
Expand All @@ -27,7 +27,7 @@ def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)

def get_queryset(self):
return self.action.exam.first()
return hasattr(self.action, 'exam') and self.action.exam or None

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
Expand All @@ -41,6 +41,7 @@ class ActionAddQuestionsView(ListView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.action = None
self.request = None

def dispatch(self, request, *args, **kwargs):
self.action = get_object_or_404(Action, id=kwargs.get('pk'))
Expand All @@ -52,26 +53,23 @@ def get_queryset(self):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['action'] = self.action
context['selected'] = self.get_seleted_exam_questions()
if hasattr(self.action, 'exam'):
context['selected'] = self.get_seleted_exam_questions()
return context

def get_seleted_exam_questions(self):
exam = self.action.exam.first()
if exam is not None:
return [qe.id for qe in exam.questions.all()]
return []
return [qe.id for qe in self.action.exam.questions.all()]

def post(self, request, *args, **kwargs):
action = get_object_or_404(Action, pipeline__vacancy__company__employer=request.role_object,
action = get_object_or_404(Action,
id=request.POST.get('action'))
if not action.owner == request.user:
raise Http404
question_ids = request.POST.getlist('questions')
if question_ids:
action_exam, _ = ActionExam.objects.get_or_create(action=action)
action_exam.questions.set(Question.objects.filter(id__in=question_ids))
action_exam.save()
else:
messages.error(request, 'You cannot delete all questions from exam.')
return redirect('action_exam', pk=action.id)
action_exam, _ = ActionExam.objects.get_or_create(action=action)
action_exam.questions.set(Question.objects.filter(id__in=question_ids))
action_exam.save()
return redirect('action_details', pk=action.id)


class CandidateExaminingView(OnlyCandidateMixin, TemplateView):
Expand All @@ -87,22 +85,21 @@ def __init__(self, **kwargs):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.already_pass_exam:
context['exam_passed'] = ExamPassed.objects.filter(profile=self.profile,
context['exam_passed'] = ExamPassed.objects.filter(candidate=self.request.role_object,
exam=self.action_exam).first()
else:
context['profile'] = self.profile
context['candidate'] = self.request.role_object
context['exam'] = self.action_exam
context['action'] = self.action_exam.action
return context

def get(self, request, *args, **kwargs):
self.profile = get_object_or_404(CandidateProfile, pk=self.request.role_object.profile.id)
self.action_exam = get_object_or_404(ActionExam, pk=kwargs.get('pk'))
self.check_candidate()
return super().get(self, request, *args, **kwargs)

def check_candidate(self):
self.already_pass_exam = ExamPassed.objects.filter(profile=self.profile,
self.already_pass_exam = ExamPassed.objects.filter(candidate=self.request.role_object,
exam=self.action_exam).exists()

def post(self, request, *args, **kwargs):
Expand All @@ -112,10 +109,9 @@ def post(self, request, *args, **kwargs):

def process_request(self, request):
self.action_exam = get_object_or_404(ActionExam, pk=request.POST.get('exam_id', None))
self.profile = get_object_or_404(CandidateProfile, pk=request.POST.get('profile_id', None))
answers = {key: value[0] if len(value) == 1 else value for key, value in dict(request.POST).items() if
key.startswith('question_') and value[0] != ''}
ExamPassed.objects.create(profile=self.profile, exam=self.action_exam, answers=answers)
ExamPassed.objects.create(candidate=request.role_object, exam=self.action_exam, answers=answers)


class QuizIndexPage(TemplateView):
Expand All @@ -136,15 +132,16 @@ class NewCategoryView(CreateView):
form_class = CategoryForm
success_url = reverse_lazy('quiz_index')

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.request = None
self.object = None

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['employer'] = self.request.role_object
return kwargs

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.object = None

def form_valid(self, form):
self.object = form.save(commit=False)
self.object.employer = self.request.role_object
Expand Down Expand Up @@ -265,7 +262,7 @@ def form_valid(self, form):
return HttpResponse(True, status=200)

def form_invalid(self, form):
return HttpResponse(False, status=403)
return HttpResponse(False, status=400)


class ProcessAnswerView(View):
Expand All @@ -282,5 +279,34 @@ def post(self, request, *args, **kwargs):
return HttpResponse('ok', status=200)


class ExamResultsView(DetailView):
class ExamPassedView(OnlyEmployerMixin, DetailView):
model = ExamPassed

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.action_exam = None
self.candidate = None

def dispatch(self, request, *args, **kwargs):
self.action_exam = get_object_or_404(ActionExam, pk=kwargs.get('exam_id'))
if self.action_exam.action.owner != request.user:
raise Http404
self.candidate = get_object_or_404(Candidate, pk=kwargs.get('candidate_id'))
return super().dispatch(request, *args, **kwargs)

def get_object(self, queryset=None):
try:
results = ExamPassed.objects.get(exam=self.action_exam, candidate=self.candidate)
except ExamPassed.DoesNotExist:
results = {}
return results

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['action'] = self.action_exam.action
context['candidate'] = self.candidate
oracle = OracleHandler()
cci = oracle.get_candidate_current_action_index(self.action_exam.action.pipeline.vacancy.uuid,
self.candidate.contract_address)
cci == self.action_exam.action.index and context.update({'not_yet': True})
return context
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
amqp==2.2.2
appnope==0.1.0
attrdict==2.0.0
authy==2.1.5
billiard==3.5.0.3
celery==4.1.0
certifi==2018.1.18
Expand Down Expand Up @@ -63,6 +64,7 @@ scikit-learn==0.19.1
scipy==1.0.0
semantic-version==2.6.0
simplegeneric==0.8.1
simplejson==3.16.0
six==1.11.0
sklearn==0.0
toolz==0.9.0
Expand Down

0 comments on commit 02060c5

Please sign in to comment.