diff options
| author | David Beguin <dbe@odoo.com> | 2019-12-02 12:50:25 +0000 |
|---|---|---|
| committer | Aurélien Warnon <awa@odoo.com> | 2020-01-10 11:01:04 +0000 |
| commit | 26147efeab9bd37679c0202950c48bdb1c8ec04a (patch) | |
| tree | 1efeff8e6bb7d5958c65d61f2ad673b9c369a630 /addons | |
| parent | 94fd0624afc508bb46b9444ac232d313a200c168 (diff) | |
[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
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/survey/controllers/main.py | 49 |
1 files changed, 22 insertions, 27 deletions
diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 11b2e287e04..db5b65a3ea9 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -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 {} - - 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} - - # 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'] + return {'error': 'unauthorized'} + + 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'} + + 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: |
