When the user submits a quiz, the user will not get much feedback. To improve the user experience, we will now indicate how many points the users earned per question. With that information, the users could detect errors and report them to the administrators. We will also add some minor layout improvements to make things clearer. When the administrator creates a quiz, the administrator might not want to set a limit on the number of attempts that a user can have on a quiz. To allow that, we added an option in the quiz settings called 'Unlimited Tries'. When the administrator checks that option, a button will appear below the quiz and will let the users reset the quiz at will. Sometimes, the administrator might also want to (1) give points for an answer that is not wrong or (2) give no point for a correct answer. This is not currently possible as we considered that the correct answer is the answer that rewards points. To allow that, we will add a new boolean field on each answer to mark the correct answer. task-2504216 COM PR: odoo/odoo#69585 UPG PR: odoo/upgrade#2408
68 lines
3.0 KiB
Python
68 lines
3.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class Quiz(models.Model):
|
|
_name = "event.quiz"
|
|
_description = "Quiz"
|
|
|
|
name = fields.Char('Name', required=True, translate=True)
|
|
question_ids = fields.One2many('event.quiz.question', 'quiz_id', string="Questions")
|
|
event_track_id = fields.Many2one('event.track', readonly=True)
|
|
event_id = fields.Many2one(
|
|
'event.event', related='event_track_id.event_id',
|
|
readonly=True, store=True)
|
|
repeatable = fields.Boolean('Unlimited Tries',
|
|
help='Let attendees reset the quiz and try again.')
|
|
|
|
|
|
class QuizQuestion(models.Model):
|
|
_name = "event.quiz.question"
|
|
_description = "Content Quiz Question"
|
|
_order = "quiz_id, sequence, id"
|
|
|
|
name = fields.Char("Question", required=True, translate=True)
|
|
sequence = fields.Integer("Sequence")
|
|
quiz_id = fields.Many2one("event.quiz", "Quiz", required=True, ondelete='cascade')
|
|
correct_answer_id = fields.One2many('event.quiz.answer', compute='_compute_correct_answer_id')
|
|
awarded_points = fields.Integer("Number of Points", compute='_compute_awarded_points')
|
|
answer_ids = fields.One2many('event.quiz.answer', 'question_id', string="Answer")
|
|
|
|
@api.depends('answer_ids.awarded_points')
|
|
def _compute_awarded_points(self):
|
|
for question in self:
|
|
question.awarded_points = sum(question.answer_ids.mapped('awarded_points'))
|
|
|
|
@api.depends('answer_ids.is_correct')
|
|
def _compute_correct_answer_id(self):
|
|
for question in self:
|
|
question.correct_answer_id = question.answer_ids.filtered(lambda e: e.is_correct)
|
|
|
|
@api.constrains('answer_ids')
|
|
def _check_answers_integrity(self):
|
|
for question in self:
|
|
if len(question.correct_answer_id) != 1:
|
|
raise ValidationError(_('Question "%s" must have 1 correct answer to be valid.', question.name))
|
|
if len(question.answer_ids) < 2:
|
|
raise ValidationError(_('Question "%s" must have 1 correct answer and at least 1 incorrect answer to be valid.', question.name))
|
|
|
|
|
|
class QuizAnswer(models.Model):
|
|
_name = "event.quiz.answer"
|
|
_rec_name = "text_value"
|
|
_description = "Question's Answer"
|
|
_order = 'question_id, sequence, id'
|
|
|
|
sequence = fields.Integer("Sequence")
|
|
question_id = fields.Many2one('event.quiz.question', string="Question", required=True, ondelete='cascade')
|
|
text_value = fields.Char("Answer", required=True, translate=True)
|
|
is_correct = fields.Boolean('Correct', default=False)
|
|
comment = fields.Text(
|
|
'Extra Comment', translate=True,
|
|
help='''This comment will be displayed to the user if he selects this answer, after submitting the quiz.
|
|
It is used as a small informational text helping to understand why this answer is correct / incorrect.''')
|
|
awarded_points = fields.Integer('Points', default=0)
|