[submodule "lib/pdfannotator"]
path = lib/pdfannotator
url = https://git.pilotsystems.net/probarreau/pdfannotator.git
+[submodule "lib/Django-Quiz"]
+ path = lib/Django-Quiz
+ url = https://github.com/Parisson/Django-Quiz.git
--- /dev/null
+Subproject commit 414ffcec05588d41652cdd1799706abccad9b8b7
Django = ">=1.0"
six = "*"
-[[package]]
-name = "django-model-utils"
-version = "5.0.0"
-description = "Django model mixins and utilities"
-optional = false
-python-versions = ">=3.8"
-files = [
- {file = "django_model_utils-5.0.0-py3-none-any.whl", hash = "sha256:fec78e6c323d565a221f7c4edc703f4567d7bb1caeafe1acd16a80c5ff82056b"},
- {file = "django_model_utils-5.0.0.tar.gz", hash = "sha256:041cdd6230d2fbf6cd943e1969318bce762272077f4ecd333ab2263924b4e5eb"},
-]
-
-[package.dependencies]
-Django = ">=3.2"
-
[[package]]
name = "django-nvd3"
version = "0.9.7"
[package.dependencies]
Django = "*"
-[[package]]
-name = "django-quiz-app"
-version = "0.5.1"
-description = "A configurable quiz app for Django."
-optional = false
-python-versions = "*"
-files = []
-develop = false
-
-[package.dependencies]
-Django = ">=1.5.1"
-django-model-utils = ">=2.0.3"
-Pillow = ">=2.5.0"
-
-[package.source]
-type = "git"
-url = "https://github.com/pilot-systems/Django-Quiz.git"
-reference = "HEAD"
-resolved_reference = "414ffcec05588d41652cdd1799706abccad9b8b7"
-
[[package]]
name = "django-recaptcha"
version = "2.0.6"
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
-content-hash = "75063f62ed7197ea62b66b4106181196aeeeeb8c0513c3e3ae15173e4d52d6f5"
+content-hash = "b1c45f071661223d1e19bf13115bb28c4ac30c7053b314db769523a7a96702c3"
boto3 = "^1.34.89"
ipython = "^8.23.0"
reportlab = "^4.2.0"
-django-quiz-app = {git = "https://github.com/pilot-systems/Django-Quiz.git"}
[build-system]
--- /dev/null
+# Generated by Django 3.2.25 on 2025-09-11 16:12
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('quiz', '__first__'),
+ ('teleforma', '0032_alter_mediaread_duration'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='course',
+ name='quizzes',
+ field=models.ManyToManyField(blank=True, related_name='courses', to='quiz.Quiz', verbose_name='Quizzes'),
+ ),
+ ]
--- /dev/null
+# Generated by Django 3.2.25 on 2025-09-16 23:01
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ('quiz', '__first__'),
+ ('teleforma', '0033_course_quizzes'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='QuizValidation',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('validated', models.BooleanField(verbose_name='validated')),
+ ('date_validated', models.DateTimeField(auto_now_add=True, null=True, verbose_name='date validated')),
+ ('quiz', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='quiz_validation', to='quiz.quiz', verbose_name='quiz')),
+ ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quiz_validation', to=settings.AUTH_USER_MODEL, verbose_name='user')),
+ ],
+ options={
+ 'verbose_name': 'Quiz validation',
+ 'db_table': 'teleforma_quiz_validation',
+ 'ordering': ['-date_validated'],
+ },
+ ),
+ ]
from sorl.thumbnail import default as sorl_default
from pypdf import PdfWriter
import httpx
-
+from quiz.models import Quiz
from storages.backends.s3boto3 import S3Boto3Storage
corrections_shared = models.BooleanField("Corrections partagés",
help_text="A utiliser avec le champ relatif dans la période.",
default=False)
+ quizzes = models.ManyToManyField(Quiz, related_name="courses",
+ verbose_name=u'Quizzes',
+ blank=True)
def __str__(self):
return self.title
user = models.ForeignKey(User, related_name='read', verbose_name=_('user'),
blank=True, null=True, on_delete=models.SET_NULL)
duration = models.DurationField(_("duration"), blank=True, null=True)
+
+
from django.utils.translation import ugettext_lazy as _
from tinymce.models import HTMLField
from django.core.cache import cache
+from quiz.models import Quiz
from ..models.core import (Course, Media, MetaCore, payment_choices,
payment_schedule_choices)
+
app_label = 'teleforma'
months_choices = []
def can_delete(self, request):
return request.user.is_staff or request.user.id == self.creator.id
+
+
+class QuizValidation(models.Model):
+
+ user = models.ForeignKey(User, related_name="quiz_validation", verbose_name=_('user'), on_delete=models.CASCADE)
+ quiz = models.ForeignKey(Quiz, related_name="quiz_validation", verbose_name=_('quiz'),
+ blank=True, null=True, on_delete=models.SET_NULL)
+ validated = models.BooleanField(_('validated'))
+ date_validated = models.DateTimeField(_('date validated'), auto_now_add=True, null=True)
+
+ def __str__(self):
+ return ' - '.join([str(self.quiz), self.user.username, str(self.date_validated)])
+
+ def validate(self):
+ self.validated = True
+ self.save()
+
+ def reject(self):
+ self.validated = False
+ self.save()
+
+ class Meta(MetaCore):
+ db_table = app_label + '_' + 'quiz_validation'
+ verbose_name = _('Quiz validation')
+ ordering = ['-date_validated']
.icon_wait{
background-image: url('/static/teleforma/images/wait.gif');
}
+.icon_loading{
+ background-image: url('/static/teleforma/images/loading.png');
+}
.icon_rss,.icon_rss:hover{
background: url('/static/teleforma/images/feed-icon-14x14.png') no-repeat;
background-position: 0ex .8ex;
scroll-margin-block-end: 1em;
}
+.course_sub_title {
+ color: #355ea2;
+ -moz-border-radius: 8px 0px 0px 0px;
+ -webkit-border-radius: 8px 0px 0px 0px;
+ border-radius: 8px 0px 0px 0px;
+ padding: 1em 0em 0.5em 0em;
+ font-weight: bold;
+ font-size: 1.1em;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ scroll-margin-block-start: 1em;
+ scroll-margin-block-end: 1em;
+}
+
+
.create-bbb-conference {
font-size: 0.8em;
}
flex-direction: row-reverse;
justify-content: start;
font-weight: bold;
+}
+
+#flex-container {
+ display: flex;
+ flex-direction: row;
+}
+
+#flex-container > .flex-item {
+ flex: auto;
+}
+
+#flex-container > .raw-item {
+ width: 5rem;
}
\ No newline at end of file
{% if user_was_incorrect %}
<div class="alert alert-error">
- <strong>{% trans "You answered the above question incorrectly" %}</strong>
+ <strong>{% trans "You answered the above question incorrectly" %}</strong>
</div>
{% endif %}
- <table class="table table-striped table-bordered">
- <tbody>
- {% for answer in previous.answers %}
- {% if answer.correct %}
- <tr class="success">
- <td>{{ answer.content }}</td>
- <td><strong>{% trans "This is the correct answer" %}</strong></td>
- {% else %}
- <tr>
- <td>{{ answer.content }}</td>
- <td>
- {% if previous.question_type.MCQuestion %}
- {% if answer.id|add:"0" == previous.previous_answer|add:"0" %}
- {% trans "This was your answer." %}
- {% endif %}
- {% endif %}
- </td>
- {% endif %}
- </tr>
- {% endfor %}
- </tbody>
- </table>
+ <div style="padding: 1em">
+ <table class="table table-striped table-bordered">
+ <tbody>
+ {% for answer in previous.answers %}
+ {% if answer.correct %}
+ <tr class="success">
+ <td>{{ answer.content }}</td>
+ <td><strong>{% trans "This is the correct answer" %}</strong></td>
+ {% else %}
+ <tr
+ {% if previous.question_type.MCQuestion %}
+ {% if answer.id|add:"0" == previous.previous_answer|add:"0" %}
+ class="error"
+ {% endif %}
+ {% endif %}
+ >
+ <td>{{ answer.content }}</td>
+ <td>
+ {% if previous.question_type.MCQuestion %}
+ {% if answer.id|add:"0" == previous.previous_answer|add:"0" %}
+ {% trans "This was your answer." %}
+ {% endif %}
+ {% endif %}
+ </td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
{% endif %}
-{% extends "teleforma/base.html" %}
+{% extends "teleforma/course_detail.html" %}
{% load i18n%}
-
{% load quiz_tags %}
-{% block title %} {{ quiz.title }} {% endblock %}
-{% block description %} {{ quiz.title }} - {{ quiz.description }} {% endblock %}
+{% block course %}
-{% block content %}
+<div class="course_media">
-{% if previous.answers %}
+ <div class="course_main_title">
+ {{ course.title }}
+ </div>
- <p class="muted"><small>{% trans "The previous question" %}:</small></p>
- <p>{{ previous.previous_question }}</p>
+ <div class="course_title">
+ Quiz - {{ quiz.title }}
+ </div>
- {% if previous.previous_outcome %}
- <div class="alert alert-success">
- {% else %}
- <div class="alert alert-warning">
- {% endif %}
- <p><small>
- Votre réponse est </small>
- <strong>
- {{ previous.previous_outcome|yesno:"correct,incorrect" }}
- </strong>
- </p>
+ {% block description %} {{ quiz.description }} {% endblock %}
- </div>
+ {% if previous.answers %}
- {% include 'correct_answer.html' %}
+ <div class="course_sub_title">
+ {% trans "The previous question" %}:
+ </div>
- <p><strong>{% trans "Explanation" %}:</strong></p>
- <div class="well " style="background-color: #fcf8e3;">
- <p>{{ previous.previous_question.explanation }}</p>
- </div>
+ <div class="course_content">
+ <p class="lead">{{ previous.previous_question }}</p>
+ {% include 'quiz/correct_answer.html' %}
+ </div>
- <hr>
+ <p>Votre réponse est
+ <strong>
+ {{ previous.previous_outcome|yesno:"correct,incorrect" }}
+ </strong>
+ </p>
-{% endif %}
+ <div class="course_sub_title">{% trans "Explanation" %}:</div>
+ <div class="well course_content">
+ <p>{{ previous.previous_question.explanation }}</p>
+ </div>
-<br />
+ {% endif %}
-{% if question %}
+ <br />
-{% if progress %}
-<div style="float: right;">
-{% trans "Question" %} {{ progress.0|add:1 }} {% trans "of" %} {{ progress.1 }}
-</div>
-{% endif %}
+ {% if question %}
-{% if question.category %}<p>
- <small class="muted">{% trans "Question category" %}:</small>
- <strong>{{ question.category }}</strong>
-</p>{% endif %}
+ {% if progress %}
+ <div class="course_sub_title">
+ {% trans "Question" %} {{ progress.0|add:1 }} {% trans "of" %} {{ progress.1 }}
+ </div>
+ {% endif %}
-<p class="lead">{{ question.content }}</p>
+ {% if question.category %}<p>
+ <small class="muted">{% trans "Question category" %}:</small>
+ <strong>{{ question.category }}</strong>
+ </p>{% endif %}
-{% if question.figure %}
- <img src="{{ question.figure.url }}" alt="{{ question.content }}" />
-{% endif %}
+ <div class="course_content">
-<form action="" method="POST">{% csrf_token %}
- <input type=hidden name="question_id" value="{{ question.id }}">
+ <p class="lead">{{ question.content }}</p>
- <ul class="list-group">
+ {% if question.figure %}
+ <img src="{{ question.figure.url }}" alt="{{ question.content }}" />
+ {% endif %}
- {% for answer in form.answers %}
- <li class="list-group-item">
- {{ answer }}
- </li>
- {% endfor %}
+ <form action="" method="POST">{% csrf_token %}
+ <input type=hidden name="question_id" value="{{ question.id }}">
- </ul>
- <input type="submit" value={% trans "Check" %} class="btn btn-large btn-block btn-warning" >
-</form>
+ <ul class="list-group">
+ {% for answer in form.answers %}
+ <li class="list-group-item">
+ {{ answer }}
+ </li>
+ {% endfor %}
+ </ul>
-{% endif %}
+ <input style="padding: 5px; margin: 5px" type="submit" value={% trans "Check" %} class="btn btn-large btn-block btn-warning" >
-<hr>
+ </form>
+ </div>
+
+ {% endif %}
+
+
+</div>
{% endblock %}
-{% extends 'teleforma/base.html' %}
+{% extends 'teleforma/course_detail.html' %}
{% load i18n %}
{% block title %}
{{ quiz.title }}
{% endblock %}
-{% block content %}
+{% block course %}
<!--<h2>{{ quiz.title }}</h2>-->
<!--<h3>{% trans "Category" %}: {{ quiz.category }}</h3>-->
{% if quiz.single_attempt %}
<td>{{ quiz.exam_paper }}</td>
<td>{{ quiz.single_attempt }}</td>
<td>
- <a href="{% url 'quiz_start_page' slug=quiz.url %}">
+ <a href="{% url 'teleforma-quiz' period_id=period.id pk=course.pk quiz_name=quiz.name %}">
{% trans "View details" %}
</a>
</tr>
-{% extends "teleforma/base.html" %}
+{% extends "quiz/question.html" %}
{% load i18n %}
-
{% load quiz_tags %}
-{% block title %} {{ quiz.title}} {% endblock %}
-{% block description %} {% trans "Exam Results for" %} {{ quiz.title }} {% endblock %}
+{% block course %}
+
+<div class="course_media">
+
+<div class="course_main_title">
+ {{ course.title }}
+ </div>
+
+<div class="course_title">
+ Quiz - {{ quiz.title }}
+</div>
-{% block content %}
+{% block description %} {{ quiz.description }} {% endblock %}
{% if previous.answers %}
- <p class="muted"><small>{% trans "The previous question" %}:</small></p>
- <p>{{ previous.previous_question }}</p>
+ <div class="course_sub_title">
+ {% trans "The previous question" %}:
+ </div>
+
+ <div class="course_content">
+ <p class="lead">{{ previous.previous_question }}</p>
+ {% include 'quiz/correct_answer.html' %}
+ </div>
+
<p>Votre réponse est
- <strong>
- {{ previous.previous_outcome|yesno:"correct,incorrect" }}
- </strong>
+ <strong>
+ {{ previous.previous_outcome|yesno:"correct,incorrect" }}
+ </strong>
</p>
- {% include 'correct_answer.html' %}
- <p><strong>{% trans "Explanation" %}:</strong></p>
- <div class="well " style="background-color: #fcf8e3;">
+
+ <div class="course_sub_title">{% trans "Explanation" %}:</div>
+ <div class="well course_content">
<p>{{ previous.previous_question.explanation }}</p>
</div>
- <hr>
+
{% endif %}
{% if max_score %}
<div>
- <h2>{% trans "Exam results" %}</h2>
- <p>
- <small class="muted">{% trans "Exam title" %}: </small>
- <strong>{{ quiz.title }}</strong></p>
+ <div class="course_title">{% trans "Exam results" %}</div>
<p class="lead">
- {% trans "You answered" %} {{ score }} {% trans "questions correctly out of" %} {{ max_score }}, {% trans "giving you" %} {{ percent }} {% trans "percent correct" %}
+ {% if percent >= quiz.pass_mark %}
+ 🎉 💯
+ {% endif %}
+
+ {% trans "You answered" %} <b>{{ score }}</b> {% trans "questions correctly out of" %} <b>{{ max_score }}</b>, {% trans "giving you" %} <b>{{ percent }}</b> {% trans "percent correct" %}
</p>
{% if quiz.pass_mark %}
- <hr>
- <p class="lead">{{ sitting.result_message }}</p>
- <hr>
-
+ <p class="lead">{{ sitting.result_message }}</p>
{% endif %}
</div>
-
{% endif %}
-
- <hr>
-
{% if possible %}
<p class="lead">
{% trans "Your session score is" %} {{ session }} {% trans "out of a possible" %} {{ possible }}
</p>
- <hr>
-
{% endif %}
{% if questions %}
{% for question in questions %}
- <p class="lead">
- {{ question.content }}
+ <p class="lead">
+ {{ question.content }}
</p>
{% correct_answer_for_all question %}
<p>{{ question.explanation }}</p>
</div>
- <hr>
{% endfor %}
{% endif %}
+ <br><br>
+
+ <div id="flex-container">
+ <div class="flex-item" id="flex">
+ <a href="{% url 'teleforma-desk-period-course' period.id course.id %}" class="component_icon button icon_previous">Retour à la matière</a>
+ </div>
+ <div class="flex-item" id="flex">
+ <a href="{% url 'teleforma-quiz' period_id=period.id course_id=course.pk quiz_name=quiz.url %}" class="component_icon button icon_loading">Refaire le quiz</a>
+ </div>
+ <div class="flex-item" id="flex">
+ <a class="component_icon button icon_next">Quiz suivant</a>
+ </div>
+ </div>
+
+</div>
{% endblock %}
{{ course.description }}{% endif %}
</div>
- {% if type.name == 'Quiz' %}
- <div class="course_content">
- {% if course.quiz.all %}
- <table class="listing" width="100%">
- <tbody>
- {% for quiz in course.quiz.all %}
- <td class="border-top"><a href="{% url 'quiz_start_page' slug=quiz.url %}">{{quiz.title}}</a></td>
- <td class="border-top">{{quiz.description}}</td>
- {% endfor %}
- </tbody>
- </table>
- {% else %}
- <p>Aucun quiz</p>
- {% endif %}
- </div>
-
- {% else %}
{% if show_media %}
- {% block conference %}
- {% include "teleforma/inc/conference_list.html" %}
- {% endblock %}
+ {% block conference %}
+ {% include "teleforma/inc/conference_list.html" %}
+ {% endblock %}
- {% block media %}
- {% include "teleforma/inc/media_list.html" %}
- {% endblock %}
+ {% block media %}
+ {% include "teleforma/inc/media_list.html" %}
+ {% endblock %}
{% endif %}
{% block document %}
{% include "teleforma/inc/document_list.html" %}
{% endblock %}
- {% endif %}
</div>
{% endfor %}
+ <div class="course">
+ {% if course.quizzes.all %}
+ <div class="course_title" id="webclasses">
+ Quizes
+ </div>
+ <div class="course_content">
+ <table class="listing" width="100%">
+ <tbody>
+ {% for quiz in course.quizzes.all %}
+ <tr>
+ <td class="border-top"><a href="{% url 'teleforma-quiz' period_id=period.id course_id=course.id quiz_name=quiz.url %}">{{ quiz.title }}</a></td>
+ <td class="border-top">{{ quiz.description }}</td>
+ <td class="border-top" width="5%" align="center">
+ {% if quiz|quiz_validated:user %}
+ <img src="{{ STATIC_URL }}teleforma/images/ok.png" style="vertical-align:middle" alt="" title="{% trans "Validated" %}" />
+ {% else %}
+ <img src="{{ STATIC_URL }}teleforma/images/delete.png" style="vertical-align:middle" alt="" title="{% trans ' not viewed yet' %}" />
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+ {% else %}
+ <p>Aucun quiz</p>
+ {% endif %}
+ </div>
+
+
<div class="course">
<div class="course_title" id="webclasses">Webclasses{% if course.description %} -
{{ course.description }}{% endif %}
from ..exam.models import Quota, Script
from ..models.core import Document, Professor
-from ..models.crfpa import IEJ, Course, NewsItem, Training
+from ..models.crfpa import IEJ, Course, NewsItem, Training, QuizValidation
from ..views import get_courses
from ..utils import generate_hash
from collections import defaultdict
+
register = template.Library()
# more translations for template variables
# if not context['user'].is_staff or context.get('list_view', None):
# media = media.filter(is_published = True)
# return list(media)
+
+
+
+@register.filter
+def one_more(_1, _2):
+ # to pass more than one argument to filter
+ return _1, _2
+
+@register.filter
+def quiz_validated(quiz, user):
+ validations = QuizValidation.objects.filter(quiz=quiz, user=user, validated=True)
+ if validations:
+ return validations[0].date_validated
+ else:
+ return ''
RegistrationPDFViewDownload, RetractationView, UserAddView,
UserCompleteView, UserLoginView, UsersExportView,
UsersView, WriteView, update_training,
- UserAddUseYourLawOriginView)
+ UserAddUseYourLawOriginView, QuizQuestionView)
from .views.payment import (PaymentStartView, bank_auto, bank_cancel,
bank_fail, bank_success)
+
htdocs_forma = os.path.dirname(__file__) + '/static/teleforma/'
profile_view = CRFPAProfileView()
document = DocumentView()
# must be called on channels instance
path('live_conference_notify',
- LiveConferenceNotify.as_view(), name='teleforma-live-conference-notify')
+ LiveConferenceNotify.as_view(), name='teleforma-live-conference-notify'),
+
+ # QUIZZ
+ url(r'^desk/periods/(?P<period_id>.*)/courses/(?P<course_id>.*)/quiz/(?P<quiz_name>[\w-]+)/$', QuizQuestionView.as_view(), name="teleforma-quiz"),
]
from postman.views import WriteView as PostmanWriteView
from xlwt import Workbook
from django.conf import settings
+from quiz.views import QuizTake
+from quiz.models import Quiz
from ..decorators import access_required
from ..forms import (CorrectorForm, NewsItemForm, RetractationForm, UserForm, WriteForm,
get_unique_username, UserUseYourLawOriginForm)
from ..models.core import Course, CourseType, Document, NamePaginator, Period
from ..models.crfpa import (IEJ, Discount, NewsItem, Parameters, Payback,
- Payment, Profile, Student, Training, months_choices, payment_choices)
+ Payment, Profile, Student, Training, months_choices, payment_choices,
+ QuizValidation)
from ..views.core import (CourseAccessMixin, PDFTemplateResponseMixin, format_courses,
get_courses, get_periods)
from ..views.profile import ProfileView
+
def get_course_code(obj):
if obj:
return str(obj.code)
else:
return ''
+
def get_crfpa_courses(user, date_order=False, num_order=False, period=None):
courses = []
payment = payment[0]
return render(request, template, {'profile' : profile, 'usr': user, 'payment':payment})
+
+
+class QuizQuestionView(CourseAccessMixin, QuizTake):
+
+ template_name = 'quiz/question.html'
+
+ def _init(self):
+ self.user = self.get_user()
+ self.period = Period.objects.get(pk=self.kwargs['period_id'])
+ self.course = Course.objects.get(pk=self.kwargs['course_id'])
+ self.quiz = Quiz.objects.get(url=self.kwargs['quiz_name'])
+
+ def get_user(self):
+ user_id = self.request.user.id
+ return User.objects.get(id=user_id)
+
+ def get_context_data(self, **kwargs):
+ context = super(QuizQuestionView, self).get_context_data(**kwargs)
+ self._init()
+ context['period_id'] = self.kwargs['period_id']
+ context['period'] = self.period
+ context['course_id'] = self.kwargs['course_id']
+ context['course'] = self.course
+ context['quiz'] = self.quiz
+ return context
+
+ def final_result_user(self):
+ self._init()
+
+ results = {
+ '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,
+ 'period': self.period,
+ 'course': self.course,
+ 'quiz': self.quiz,
+ 'all_courses': get_courses(self.user, num_order=True, period=self.period),
+ }
+
+ 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:
+ self.sitting.delete()
+
+ if self.sitting.get_percent_correct >= self.quiz.pass_mark:
+ validation = QuizValidation(
+ user=self.user, quiz=self.quiz, validated=True)
+ validation.save()
+
+ return render(self.request, 'quiz/result.html', results)