[REF] survey: improve access mode options and survey form view

In this commit we extend access option on survey model. Access mode is now
defined as

 * public: everyone can access this survey. People having a link to the survey
   can create answers and fill survey. Those are used for example as
   satisfaction surveys;
 * login required: only users can access this survey. Depending on auth
   signup configuration this either limits survey access or forces people
   to create an account;
 * employees only: only users belonging to base.group_user can access this
   survey. Those are used for example for internal polls;
 * on invitation only: only people receiving a token can access this survey.
   They do not need to be an user, having a token is sufficient. Those are
   used for example for appraisals;

Note that survey officers and managers can always create and update answers
according to their ACLs.

In this commit we also improve a bit survey form view while changing the
access field. Surveys users now have access to all buttons and some labels
have been updated to better fit current Odoo style. Archive button is now
always displayed as it is considered as a standard way of managing surveys.

This commit is linked to task ID 1911586 and PR #28986.
This commit is contained in:
Thibault Delavallée
2019-01-14 15:22:18 +00:00
parent 66e00f642a
commit 7c50807bec
9 changed files with 57 additions and 42 deletions
@@ -3,7 +3,7 @@
<record id="survey_recruitment_form" model="survey.survey">
<field name="title">Recruitment Form</field>
<field name="stage_id" ref="survey.stage_permanent"/>
<field name="auth_required" eval="True"/>
<field name="access_mode">token</field>
<field name="users_can_go_back" eval="True"/>
<field name="description" type="html">
<p>
+5 -2
View File
@@ -59,8 +59,11 @@ class Survey(http.Controller):
if not answer_sudo and ensure_token:
return 'token_required'
if not answer_sudo and survey_sudo.access_mode == 'token':
return 'token_required'
if survey_sudo.auth_required and request.env.user._is_public():
# Public -> no auth required; Token -> token check hereabove
if survey_sudo.access_mode not in ['public', 'token'] and request.env.user._is_public():
return 'survey_auth'
if survey_sudo.is_closed or not survey_sudo.active:
@@ -99,7 +102,7 @@ class Survey(http.Controller):
has_survey_access = True
can_answer = bool(answer_sudo)
if not can_answer:
can_answer = survey_sudo.auth_required is False
can_answer = survey_sudo.access_mode == 'public'
return {
'survey_sudo': survey_sudo,
+2 -2
View File
@@ -4,7 +4,7 @@
<record model="survey.survey" id="survey_feedback">
<field name="title">User Feedback Form</field>
<field name="stage_id" ref="survey.stage_in_progress" />
<field name="auth_required" eval="False" />
<field name="access_mode">public</field>
<field name="users_can_go_back" eval="True" />
<field name="description" type="html">
<p>This survey allows you to give a feedback about your experience with our eCommerce solution.
@@ -229,4 +229,4 @@
<field name="state">skip</field>
</record>
</data></odoo>
</data></odoo>
+22 -3
View File
@@ -35,14 +35,26 @@ class Survey(models.Model):
page_ids = fields.One2many('survey.page', 'survey_id', string='Pages', copy=True)
user_input_ids = fields.One2many('survey.user_input', 'survey_id', string='User responses', readonly=True, groups='survey.group_survey_user')
# security / access
auth_required = fields.Boolean('Login required', help="Users with a public link will be requested to login before taking part to the survey")
access_mode = fields.Selection([
('public', 'Everyone'),
('authentication', 'Login Required'),
('internal', 'Employees Only'),
('token', 'Invitation only')], string='Access Mode',
default='authentication', required=True)
users_can_go_back = fields.Boolean('Users can go back', help="If checked, users can go back to previous pages.")
users_can_signup = fields.Boolean('Users can signup', compute='_compute_users_can_signup')
public_url = fields.Char("Public link", compute="_compute_survey_url")
# statistics
tot_sent_survey = fields.Integer("Number of sent surveys", compute="_compute_survey_statistic")
tot_start_survey = fields.Integer("Number of started surveys", compute="_compute_survey_statistic")
tot_comp_survey = fields.Integer("Number of completed surveys", compute="_compute_survey_statistic")
@api.multi
def _compute_users_can_signup(self):
signup_allowed = self.env['res.users'].sudo()._get_signup_invitation_scope() == 'b2c'
for survey in self:
survey.users_can_signup = signup_allowed
@api.multi
def _compute_survey_statistic(self):
UserInput = self.env['survey.user_input']
@@ -125,8 +137,15 @@ class Survey(models.Model):
raise UserError(_('Creating token for archived surveys is not allowed.'))
elif self.is_closed:
raise UserError(_('Creating token for closed surveys is not allowed.'))
if self.auth_required and (not user or user._is_public()):
raise UserError(_('Creating token for external users is not allowed for surveys requesting authentication.'))
if self.access_mode == 'authentication':
# signup possible -> should have at least a partner to create an account
if self.users_can_signup and not user and not partner:
raise UserError(_('Creating token for external people is not allowed for surveys requesting authentication.'))
# no signup possible -> should be a not public user (employee or portal users)
if not self.users_can_signup and (not user or user._is_public()):
raise UserError(_('Creating token for external people is not allowed for surveys requesting authentication.'))
if self.access_mode == 'internal' and (not user or not user.has_group('base.group_user')):
raise UserError(_('Creating token for anybody else than employees is not allowed for internal surveys.'))
@api.model
def next_page(self, user_input, page_id, go_back=False):
+1 -1
View File
@@ -64,7 +64,7 @@ class SurveyCase(common.SavepointCase):
self.survey = self.env['survey.survey'].sudo(self.survey_manager).create({
'title': 'Test Survey',
'auth_required': True,
'access_mode': 'authentication',
'users_can_go_back': False,
})
self.page_0 = self.env['survey.page'].sudo(self.survey_manager).create({
+1 -1
View File
@@ -47,7 +47,7 @@ class TestSurveyFlow(common.SurveyCase, HttpCase):
with self.sudo(self.survey_manager):
survey = self.env['survey.survey'].create({
'title': 'Public Survey for Tarte Al Djotte',
'auth_required': False,
'access_mode': 'public',
})
# First page is about customer data
+23 -30
View File
@@ -9,12 +9,11 @@
<field name="id" invisible="1"/>
<field name="tot_start_survey" invisible="1"/>
<field name="is_closed" invisible="1"/>
<header groups="survey.group_survey_manager">
<button name="action_test_survey" string="Test Survey" type="object" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_print_survey" string="Print Survey" type="object" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_send_survey" string="Share and invite by email" type="object" class="oe_highlight" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_result_survey" string="View results" type="object" attrs="{'invisible': ['|',('id', '=', False), ('tot_start_survey', '!=', 0)]}"/>
<button name="action_result_survey" string="View results" type="object" class="oe_highlight" attrs="{'invisible': [('tot_start_survey', '=', 0)]}"/>
<header>
<button name="action_test_survey" string="Test" type="object" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_print_survey" string="Print" type="object" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_send_survey" string="Share and invite" type="object" class="oe_highlight" attrs="{'invisible': [('id', '=', False)]}"/>
<button name="action_result_survey" string="View results" type="object" class="oe_highlight" attrs="{'invisible': [('id', '=', False)]}"/>
<field name="stage_id" widget="statusbar" options="{'clickable': '1'}"/>
</header>
<sheet>
@@ -25,7 +24,7 @@
icon="fa-pencil-square-o">
<field string="Answers" name="tot_comp_survey" widget="statinfo"/>
</button>
<button name="toggle_active" type="object" class="oe_stat_button" icon="fa-archive" attrs="{'invisible': [('is_closed', '=', False)]}">
<button name="toggle_active" type="object" class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
</button>
</div>
@@ -33,24 +32,20 @@
<label for="title" class="oe_edit_only"/>
<h1><field name="title" placeholder="Survey Title"/></h1>
</div>
<notebook>
<page string="Edit Pages and Questions">
<field name="page_ids" mode="tree" context="{'default_survey_id': active_id}" nolabel="1">
<tree>
<field name="sequence" widget="handle"/>
<field name="title"/>
<field name="question_ids"/>
</tree>
</field>
</page>
<page string="Options">
<group class="o_label_nowrap">
<field name="users_can_go_back" string="User can come back in the previous page"/>
<field name="auth_required"/>
<field name="quizz_mode" groups="base.group_no_one"/>
</group>
</page>
</notebook>
<group>
<field name="access_mode"/>
<field name="quizz_mode"/>
<field name="users_can_go_back"/>
</group>
<group string="Edit Pages and Questions">
<field name="page_ids" mode="tree" context="{'default_survey_id': active_id}" nolabel="1">
<tree>
<field name="sequence" widget="handle"/>
<field name="title"/>
<field name="question_ids"/>
</tree>
</field>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
@@ -85,7 +80,7 @@
<field name="tot_start_survey" />
<field name="tot_comp_survey" />
<field name="color" />
<field name="auth_required" />
<field name="access_mode"/>
<field name="activity_ids" />
<field name="activity_state" />
<templates>
@@ -108,7 +103,7 @@
</div>
<div class="o_kanban_record_bottom">
<ul class="list-unstyled">
<li id="survey_test">
<li>
<a type="object" name="action_test_survey">Test</a>
</li>
<li>
@@ -165,12 +160,10 @@
</p><p>
You can create surveys for different purposes: customer opinion, services feedback, recruitment interviews, employee's periodical evaluations, marketing campaigns, etc.
</p><p>
Design easily your survey, send invitations to answer by email and analyse answers.
Design easily your survey, send invitations to answer by email and analyze answers.
</p>
</field>
</record>
<act_window context="{'search_default_survey_id': [active_id], 'default_survey_id': active_id}" id="act_survey_pages" name="Pages" res_model="survey.page" src_model="survey.survey"/>
<act_window context="{'search_default_survey_id': [active_id], 'default_survey_id': active_id}" id="act_survey_question" name="Questions" res_model="survey.question" src_model="survey.survey"/>
<menuitem name="Surveys" id="menu_survey_form" action="action_survey_form" parent="menu_surveys" sequence="1"/>
+1 -1
View File
@@ -55,7 +55,7 @@
<div class="jumbotron mt32">
<h1>Login required</h1>
<p>This survey is open only to registered people. Please
<a t-att-href="'/web/login?redirect=%s' % ('/survey/start/%s?token=%s' % (survey, token))">log in</a>.
<a t-att-href="'/web/login?redirect=%s' % ('/survey/start/%s?token=%s' % (survey.id, token))">log in</a>.
</p>
</div>
</div>
+1 -1
View File
@@ -30,7 +30,7 @@
<form string="Survey User inputs" create="false">
<header>
<button name="action_survey_resend" string="Send Invitation Again" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('input_type','=','manually'), ('state', '=', 'done')]}"/>
<button name="action_print_answers" states="done" string="Print These Answers" type="object" class="oe_highlight" />
<button name="action_print_answers" states="done" string="Print" type="object" class="oe_highlight" />
<field name="state" widget="statusbar"/>
</header>
<sheet>