[IMP] survey: save questions on time limit reached
Purpose ======= If the timer goes to 00:00, the form is automatically submitted but the answers are not saved. The form should be submitted, validation should filter out invalid answers to avoid showing validation errors on the form, and save answers. If the answer is not in the correct format : skip the question If the answer is required but there is no answer : skip the question This way, we can still compute score. Specifications ============== This commit removes the invalid answers from the question to save, only if the timer is not over, to be able to compute score on not finished survey. In order to avoid being able to submit answers when the survey is marked as done, a check was added to return an error for that use case. Also, to avoid frontend timer hacking, an extra buffer of 10 seconds has been added. If the time limit is reached and the submit occurs 10 seconds after the maximum stop time (start time + time limit), no answer can be submitted. Task ID: 2152223 PR #41453
This commit is contained in:
committed by
Aurélien Warnon
parent
94fd0624af
commit
26147efeab
@@ -5,7 +5,7 @@ import json
|
||||
import logging
|
||||
import werkzeug
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from odoo import fields, http, _
|
||||
@@ -302,42 +302,37 @@ class Survey(http.Controller):
|
||||
# Survey Validation
|
||||
access_data = self._get_access_data(survey_token, answer_token, ensure_token=True)
|
||||
if access_data['validity_code'] is not True:
|
||||
return {
|
||||
'error': access_data['validity_code'],
|
||||
}
|
||||
return {'error': access_data['validity_code']}
|
||||
survey_sudo, answer_sudo = access_data['survey_sudo'], access_data['answer_sudo']
|
||||
|
||||
if answer_sudo.state == 'done':
|
||||
return {'error': 'unauthorized'}
|
||||
|
||||
questions, page_or_question_id = survey_sudo._get_survey_questions(answer=answer_sudo,
|
||||
page_id=post.get('page_id'),
|
||||
question_id=post.get('question_id'))
|
||||
|
||||
if not answer_sudo.test_entry and not survey_sudo._has_attempts_left(answer_sudo.partner_id, answer_sudo.email, answer_sudo.invite_token):
|
||||
# prevent cheating with users creating multiple 'user_input' before their last attempt
|
||||
return {}
|
||||
return {'error': 'unauthorized'}
|
||||
|
||||
if not answer_sudo.is_time_limit_reached:
|
||||
# Prepare answers and comment by question
|
||||
prepared_questions = {}
|
||||
for question in questions:
|
||||
answer_full = post.get(str(question.id))
|
||||
answer_without_comment, comment = self._extract_comment_from_answers(question, answer_full)
|
||||
prepared_questions[question.id] = {'answer': answer_without_comment, 'comment': comment}
|
||||
if answer_sudo.is_time_limit_reached:
|
||||
time_limit = answer_sudo.start_datetime + timedelta(minutes=survey_sudo.time_limit)
|
||||
if fields.Datetime.now() > (time_limit + timedelta(seconds=10)):
|
||||
# prevent cheating with users blocking the JS timer and taking all their time to answer
|
||||
return {'error': 'unauthorized'}
|
||||
|
||||
# Questions Validation
|
||||
errors = {}
|
||||
for question in questions:
|
||||
answer = prepared_questions[question.id]['answer']
|
||||
comment = prepared_questions[question.id]['comment']
|
||||
errors.update(question.validate_question(answer, comment))
|
||||
if errors:
|
||||
return {'error': 'validation', 'fields': errors}
|
||||
|
||||
# Submitting questions
|
||||
for question in questions:
|
||||
answer = prepared_questions[question.id]['answer']
|
||||
comment = prepared_questions[question.id]['comment']
|
||||
errors = {}
|
||||
# Prepare answers / comment by question, validate and save answers
|
||||
for question in questions:
|
||||
answer, comment = self._extract_comment_from_answers(question, post.get(str(question.id)))
|
||||
errors.update(question.validate_question(answer, comment))
|
||||
if not errors.get(question.id):
|
||||
answer_sudo.save_lines(question, answer, comment)
|
||||
|
||||
if errors and not answer_sudo.is_time_limit_reached:
|
||||
return {'error': 'validation', 'fields': errors}
|
||||
|
||||
if answer_sudo.is_time_limit_reached or survey_sudo.questions_layout == 'one_page':
|
||||
answer_sudo._mark_done()
|
||||
elif 'previous_page_id' in post:
|
||||
|
||||
Reference in New Issue
Block a user