PURPOSE
This commit globally improves the backend survey module usability, notably by
renaming labels, moving menu items around and cleaning unused features.
SPECIFICATIONS
These changes include (non-exhaustive list):
On questions
- Changing labels, action helpers and modules description to be clearer;
- Re-organizing the survey.question form view, notably to clearly distinguish
fields related to answers and validation options;
- Removing the "Clean test answers" server action as it can be done through
a search + unlink;
- Removing the allow_value_image field as we now always display the
image field. Users simply choose to let it blank;
On surveys
- Re-organizing the survey.survey form view fields to get a clear view of
the various options;
- automatically update scoring type when checking certification: if not one
linked to scoring, update to scoring without answers;
- set create as create_multi to speedup batch creation;
- Changes ACL rights for user_input_line. Now, only Survey Managers can
change answers. Survey users keep only a read access on answers, meaning
changing what customers / people answered is now limited to managers;
Globally
- Moving menu items and make them visible outside debug mode;
- Answer recap on print frontend page is now visible whenever a scoring is
applied, not only for certification, as if scoring is activated seeing
answers is probably wanted;
Task-2600241
closes odoo/odoo#79813
Related: odoo/upgrade#3033
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
362 lines
17 KiB
Python
362 lines
17 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import datetime
|
|
|
|
from odoo.addons.survey.tests import common
|
|
from odoo.exceptions import AccessError, UserError
|
|
from odoo.tests import tagged
|
|
from odoo.tests.common import users, HttpCase
|
|
from odoo.tools import mute_logger
|
|
|
|
|
|
@tagged('security')
|
|
class TestAccess(common.TestSurveyCommon):
|
|
|
|
def setUp(self):
|
|
super(TestAccess, self).setUp()
|
|
|
|
self.answer_0 = self._add_answer(self.survey, self.customer)
|
|
self.answer_0_0 = self._add_answer_line(self.question_ft, self.answer_0, 'Test Answer')
|
|
self.answer_0_1 = self._add_answer_line(self.question_num, self.answer_0, 5)
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_emp')
|
|
def test_access_survey_employee(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].create({'title': 'Test Survey 2'})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Page', 'sequence': 0, 'is_page': True, 'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Question', 'sequence': 1, 'page_id': self.page_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].search([('title', 'ilike', 'Test')])
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).read(['title'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).write({'question': 'New Title'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_portal')
|
|
def test_access_survey_portal(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].create({'title': 'Test Survey 2'})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Page', 'sequence': 0, 'is_page': True, 'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Question', 'sequence': 1, 'page_id': self.page_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].search([('title', 'ilike', 'Test')])
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).read(['title'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).write({'question': 'New Title'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_public')
|
|
def test_access_survey_public(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].create({'title': 'Test Survey 2'})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Page', 'sequence': 0, 'is_page': True, 'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.question'].create({'title': 'My Question', 'sequence': 1, 'page_id': self.page_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.survey'].search([('title', 'ilike', 'Test')])
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).read(['title'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).write({'question': 'New Title'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.page_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.question_ft.with_user(self.env.user).unlink()
|
|
|
|
@users('survey_manager')
|
|
def test_access_survey_survey_manager(self):
|
|
# Create: all
|
|
survey = self.env['survey.survey'].create({'title': 'Test Survey 2'})
|
|
self.env['survey.question'].create({'title': 'My Page', 'sequence': 0, 'is_page': True, 'survey_id': survey.id})
|
|
self.env['survey.question'].create({'title': 'My Question', 'sequence': 1, 'survey_id': survey.id})
|
|
|
|
# Read: all
|
|
surveys = self.env['survey.survey'].search([('title', 'ilike', 'Test')])
|
|
self.assertEqual(surveys, self.survey | survey)
|
|
surveys.read(['title'])
|
|
|
|
# Write: all
|
|
(self.survey | survey).write({'title': 'New Title'})
|
|
|
|
# Unlink: all
|
|
(self.survey | survey).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('survey_user')
|
|
def test_access_survey_survey_user(self):
|
|
# Create: own only
|
|
survey = self.env['survey.survey'].create({'title': 'Test Survey 2'})
|
|
self.env['survey.question'].create({'title': 'My Page', 'sequence': 0, 'is_page': True, 'survey_id': survey.id})
|
|
self.env['survey.question'].create({'title': 'My Question', 'sequence': 1, 'survey_id': survey.id})
|
|
|
|
# Read: all
|
|
surveys = self.env['survey.survey'].search([('title', 'ilike', 'Test')])
|
|
self.assertEqual(surveys, self.survey | survey)
|
|
surveys.read(['title'])
|
|
|
|
# Write: own only
|
|
survey.write({'title': 'New Title'})
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).write({'title': 'New Title'})
|
|
|
|
# Unlink: own only
|
|
survey.unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.survey.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_emp')
|
|
def test_access_answers_employee(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].create({'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].create({'question_id': self.question_num.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': self.answer_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].browse(self.answer_0.ids).read(['state'])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].browse(self.answer_0_0.ids).read(['value_numerical_box'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).write({'state': 'done'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0_0.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_portal')
|
|
def test_access_answers_portal(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].create({'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].create({'question_id': self.question_num.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': self.answer_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].browse(self.answer_0.ids).read(['state'])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].browse(self.answer_0_0.ids).read(['value_numerical_box'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).write({'state': 'done'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0_0.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('user_public')
|
|
def test_access_answers_public(self):
|
|
# Create: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].create({'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].create({'question_id': self.question_num.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': self.answer_0.id})
|
|
|
|
# Read: nope
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].search([('survey_id', 'in', [self.survey.id])])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input'].browse(self.answer_0.ids).read(['state'])
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].browse(self.answer_0_0.ids).read(['value_numerical_box'])
|
|
|
|
# Write: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).write({'state': 'done'})
|
|
|
|
# Unlink: nope
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0_0.with_user(self.env.user).unlink()
|
|
|
|
@mute_logger('odoo.addons.base.models.ir_model')
|
|
@users('survey_user')
|
|
def test_access_answers_survey_user(self):
|
|
survey_own = self.env['survey.survey'].create({'title': 'Other'})
|
|
self.env['survey.question'].create({'title': 'Other', 'sequence': 0, 'is_page': True, 'survey_id': survey_own.id})
|
|
question_own = self.env['survey.question'].create({'title': 'Other Question', 'sequence': 1, 'survey_id': survey_own.id})
|
|
|
|
# Create: own survey only
|
|
answer_own = self.env['survey.user_input'].create({'survey_id': survey_own.id})
|
|
with self.assertRaises(AccessError):
|
|
self.env['survey.user_input.line'].create({'question_id': question_own.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': answer_own.id})
|
|
|
|
# Read: always
|
|
answers = self.env['survey.user_input'].search([('survey_id', 'in', [survey_own.id, self.survey.id])])
|
|
self.assertEqual(answers, answer_own | self.answer_0)
|
|
|
|
answer_lines = self.env['survey.user_input.line'].search([('survey_id', 'in', [survey_own.id, self.survey.id])])
|
|
self.assertEqual(answer_lines, self.answer_0_0 | self.answer_0_1)
|
|
|
|
self.env['survey.user_input'].browse(answer_own.ids).read(['state'])
|
|
self.env['survey.user_input'].browse(self.answer_0.ids).read(['state'])
|
|
|
|
self.env['survey.user_input.line'].browse(self.answer_0_0.ids).read(['value_numerical_box'])
|
|
|
|
# Create: own survey only (moved after read because DB not correctly rollbacked with assertRaises)
|
|
with self.assertRaises(AccessError):
|
|
answer_other = self.env['survey.user_input'].create({'survey_id': self.survey.id})
|
|
with self.assertRaises(AccessError):
|
|
answer_line_other = self.env['survey.user_input.line'].create({'question_id': self.question_num.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': self.answer_0.id})
|
|
|
|
# Write: own survey only
|
|
answer_own.write({'state': 'done'})
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).write({'state': 'done'})
|
|
|
|
# Unlink: own survey only
|
|
answer_own.unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0.with_user(self.env.user).unlink()
|
|
with self.assertRaises(AccessError):
|
|
self.answer_0_0.with_user(self.env.user).unlink()
|
|
|
|
@users('survey_manager')
|
|
def test_access_answers_survey_manager(self):
|
|
admin = self.env.ref('base.user_admin')
|
|
with self.with_user(admin.login):
|
|
survey_other = self.env['survey.survey'].create({'title': 'Other'})
|
|
self.env['survey.question'].create({'title': 'Other', 'sequence': 0, 'is_page': True, 'survey_id': survey_other.id})
|
|
question_other = self.env['survey.question'].create({'title': 'Other Question', 'sequence': 1, 'survey_id': survey_other.id})
|
|
self.assertEqual(survey_other.create_uid, admin)
|
|
self.assertEqual(question_other.create_uid, admin)
|
|
|
|
# Create: always
|
|
answer_own = self.env['survey.user_input'].create({'survey_id': self.survey.id})
|
|
answer_other = self.env['survey.user_input'].create({'survey_id': survey_other.id})
|
|
answer_line_own = self.env['survey.user_input.line'].create({'question_id': self.question_num.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': answer_own.id})
|
|
answer_line_other = self.env['survey.user_input.line'].create({'question_id': question_other.id, 'answer_type': 'numerical_box', 'value_numerical_box': 3, 'user_input_id': answer_other.id})
|
|
|
|
# Read: always
|
|
answers = self.env['survey.user_input'].search([('survey_id', 'in', [survey_other.id, self.survey.id])])
|
|
self.assertEqual(answers, answer_own | answer_other | self.answer_0)
|
|
|
|
answer_lines = self.env['survey.user_input.line'].search([('survey_id', 'in', [survey_other.id, self.survey.id])])
|
|
self.assertEqual(answer_lines, answer_line_own | answer_line_other | self.answer_0_0 | self.answer_0_1)
|
|
|
|
self.env['survey.user_input'].browse(answer_own.ids).read(['state'])
|
|
self.env['survey.user_input'].browse(self.answer_0.ids).read(['state'])
|
|
|
|
self.env['survey.user_input.line'].browse(answer_line_own.ids).read(['value_numerical_box'])
|
|
self.env['survey.user_input.line'].browse(self.answer_0_0.ids).read(['value_numerical_box'])
|
|
|
|
# Write: always
|
|
answer_own.write({'state': 'done'})
|
|
answer_other.write({'partner_id': self.env.user.partner_id.id})
|
|
|
|
# Unlink: always
|
|
(answer_own | answer_other | self.answer_0).unlink()
|
|
|
|
|
|
@tagged('post_install')
|
|
class TestSurveySecurityControllers(common.TestSurveyCommon, HttpCase):
|
|
def test_survey_start_short(self):
|
|
# avoid name clash with existing data
|
|
surveys = self.env['survey.survey'].search([
|
|
('session_state', 'in', ['ready', 'in_progress'])
|
|
])
|
|
self.survey.write({
|
|
'session_state': 'ready',
|
|
'session_code': '123456',
|
|
'session_start_time': datetime.datetime.now(),
|
|
'access_mode': 'public',
|
|
'users_login_required': False,
|
|
})
|
|
|
|
# right short access token
|
|
response = self.url_open(f'/s/123456')
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn('The session will begin automatically when the host starts', response.text)
|
|
|
|
# `like` operator injection
|
|
response = self.url_open(f'/s/______')
|
|
self.assertFalse(self.survey.title in response.text)
|
|
|
|
# right short token, but closed survey
|
|
self.survey.action_archive()
|
|
response = self.url_open(f'/s/123456')
|
|
self.assertFalse(self.survey.title in response.text)
|
|
|
|
# right short token, but wrong `session_state`
|
|
self.survey.write({'session_state': False, 'active': True})
|
|
response = self.url_open(f'/s/123456')
|
|
self.assertFalse(self.survey.title in response.text)
|