[IMP] Mandatory questions validation
bzr revid: rim@openerp.com-20131108142406-pmqubepahqg2qyqx
This commit is contained in:
@@ -36,7 +36,7 @@ sent mails with user name and password for the invitation of the survey.
|
||||
'summary': 'Create surveys, collect answers and print statistics',
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'https://www.openerp.com/',
|
||||
'depends': ['email_template', 'mail'],
|
||||
'depends': ['email_template', 'mail', 'website'],
|
||||
'data': [
|
||||
'security/survey_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
||||
@@ -58,21 +58,41 @@ class WebsiteSurvey(http.Controller):
|
||||
if survey_obj.exists(cr, uid, survey.id, context=context) == []:
|
||||
return werkzeug.utils.redirect("/survey/")
|
||||
|
||||
_logger.debug('Post request data:\n %s', post)
|
||||
_logger.debug('Post request data: %s', post)
|
||||
|
||||
# Answer validation and storage
|
||||
problems = []
|
||||
if post:
|
||||
if post and int(post['current']) != -1:
|
||||
for question in survey.page_ids[int(post['current'])].question_ids:
|
||||
problems = problems + self.__check_constraints(survey.id,
|
||||
post['current'], question, post)
|
||||
problems = problems + self.__do_validation(survey.id,
|
||||
post['current'], question, post)
|
||||
|
||||
_logger.debug('Problems in the survey:\n %s', problems)
|
||||
# validation methods are dynamically loaded, if defined for the
|
||||
# question type
|
||||
#
|
||||
# eg: if question type is 'new_question_type', this will try to
|
||||
# load validate_new_question_type
|
||||
|
||||
# Pagination
|
||||
pagination = {'current': -1, 'next': 0}
|
||||
try:
|
||||
checker = getattr(self, 'validate_' + question.type)
|
||||
except AttributeError:
|
||||
_logger.warning(question.type + ": This type of question has no validation method")
|
||||
else:
|
||||
problems = problems + checker(survey.id, post['current'], question, post)
|
||||
|
||||
# Return the same survey page if problems occur
|
||||
if problems:
|
||||
_logger.debug('Problems in the survey: %s', problems)
|
||||
pagination = {'current': int(post['current']), 'next': int(post['next'])}
|
||||
return request.website.render('survey.survey',
|
||||
{'survey': survey,
|
||||
'pagination': pagination,
|
||||
'problems': problems})
|
||||
|
||||
# Display success message if totally succeeded
|
||||
if post and post['next'] == "finished":
|
||||
return request.website.render('survey.finished')
|
||||
|
||||
# Page selection
|
||||
pagination = {'current': -1, 'next': 0} # Default pagination if first opening
|
||||
if 'current' in post and 'next' in post and post['next'] != "finished":
|
||||
oldnext = int(post['next'])
|
||||
if oldnext not in range(0, len(survey.page_ids)):
|
||||
@@ -84,32 +104,103 @@ class WebsiteSurvey(http.Controller):
|
||||
else:
|
||||
pagination['next'] = oldnext + 1
|
||||
|
||||
# Display success message if totally succeeded
|
||||
if post and post['next'] == "finished":
|
||||
return request.website.render('survey.finished')
|
||||
|
||||
return request.website.render('survey.survey',
|
||||
{'survey': survey,
|
||||
'pagination': pagination,
|
||||
'problems': problems})
|
||||
'problems': None})
|
||||
|
||||
@website.route(["/survey/print/<int:survey_id>/"],
|
||||
@website.route(['/survey/print/<model("survey.survey"):survey>/'],
|
||||
type='http', auth='public', multilang=True)
|
||||
def print_empty_survey(self, survey_id=None, **post):
|
||||
def print_empty_survey(self, survey=None, **post):
|
||||
'''Display an empty survey in printable view'''
|
||||
cr, uid, context = request.cr, request.uid, request.context
|
||||
survey_obj = request.registry['survey.survey']
|
||||
survey = survey_obj.browse(cr, uid, survey_id, context=context)
|
||||
pagination = {'current': -1, 'next': 0}
|
||||
return request.website.render('survey.survey_print',
|
||||
{'survey': survey})
|
||||
{'survey': survey,
|
||||
'pagination': pagination})
|
||||
|
||||
def __check_constraints(self, survey_id, page_nr, question, post):
|
||||
print(survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__())
|
||||
def validate_free_text(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
if (survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()) not in post:
|
||||
return [{'qlabel': question.question,
|
||||
'errmsg': "This question is mandatory"}]
|
||||
return []
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
return problems
|
||||
|
||||
def __do_validation(self, survey_id, page_nr, question, post):
|
||||
return []
|
||||
def validate_textbox(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
return problems
|
||||
|
||||
def validate_numerical_box(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
# Check for an empty input
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
# Check for a non number input
|
||||
if answer_tag in post and post[answer_tag].strip() != "":
|
||||
try:
|
||||
float(post[answer_tag].strip())
|
||||
except ValueError:
|
||||
problems = problems + [{'qlabel': question.question,
|
||||
'errmsg': "This is not a number"}]
|
||||
|
||||
return problems
|
||||
|
||||
def validate_datetime(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
|
||||
# TODO CHECK, check if this is a date
|
||||
|
||||
return problems
|
||||
|
||||
def validate_simple_choice_scale(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
return problems
|
||||
|
||||
def validate_simple_choice_dropdown(self, survey_id, page_nr, question, post):
|
||||
answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
problems = []
|
||||
if question.constr_mandatory:
|
||||
problems = problems + self.__has_empty_input(question, post, answer_tag)
|
||||
return problems
|
||||
|
||||
# def validate_multiple_choice(self, survey_id, page_nr, question, post):
|
||||
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
# problems = []
|
||||
# return problems
|
||||
|
||||
# def validate_vector(self, survey_id, page_nr, question, post):
|
||||
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
# problems = []
|
||||
# return problems
|
||||
|
||||
# def validate_matrix(self, survey_id, page_nr, question, post):
|
||||
# answer_tag = survey_id.__str__() + '*' + page_nr + '*' + question.id.__str__()
|
||||
# problems = []
|
||||
# return problems
|
||||
|
||||
def __has_empty_input(self, question, post, answer_tag):
|
||||
''' Check for an empty input '''
|
||||
print(answer_tag)
|
||||
if answer_tag not in post or post[answer_tag].strip() == "":
|
||||
return [{'qlabel': question.question,
|
||||
'errmsg': "This question is mandatory"}]
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def __dict_keys_startswith(self, dictionary, string):
|
||||
'''Returns a dictionary containing the elements of <dict> whose keys start
|
||||
with <string>.
|
||||
|
||||
.. note::
|
||||
This function uses dictionary comprehensions (Python >= 2.7)'''
|
||||
return {k: dictionary[k] for k in filter(lambda key: key.startswith(string), dictionary.keys())}
|
||||
|
||||
@@ -426,6 +426,21 @@
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Question validation -->
|
||||
<group colspan="1" string="Question required">
|
||||
<field name="constr_mandatory" string="Is this question mandatory?"/>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_mandatory','=',False)]}">
|
||||
<field name="constr_type" string="Users must answer..."/>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_type','not in',['at least','a range'])]}">
|
||||
<field name="constr_minimum_req_ans" nolabel="1" />
|
||||
</group>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_type','not in',['at most','a range', 'exactly'])]}">
|
||||
<field name="constr_maximum_req_ans" nolabel="1" />
|
||||
</group>
|
||||
<field name="constr_error_msg" string="Error message"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Answer validation -->
|
||||
<group colspan="1" string="Answer Validation" attrs="{'invisible':[('type','not in',['textbox','numerical_box','datetime'])]}">
|
||||
<group>
|
||||
@@ -444,29 +459,16 @@
|
||||
<field name="validation_min_int_value" string="between"/>
|
||||
<field name="validation_max_int_value" string="and"/>
|
||||
</group>
|
||||
<group colspan="2" attrs="{'invisible':[('validation_type','!=','is_date')]}">
|
||||
<!-- <group colspan="2" attrs="{'invisible':[('validation_type','!=','is_date')]}">
|
||||
<field name="validation_min_date" string="between"/>
|
||||
<field name="validation_max_date" string="and"/>
|
||||
</group>
|
||||
</group> -->
|
||||
<field name="validation_error_msg" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
<!-- Question validation -->
|
||||
<group colspan="1" string="Question required">
|
||||
<field name="constr_mandatory" string="Is this question mandatory?"/>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_mandatory','=',False)]}">
|
||||
<field name="constr_type" string="Users must answer..."/>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_type','not in',['at least','a range'])]}">
|
||||
<field name="constr_minimum_req_ans" nolabel="1" />
|
||||
</group>
|
||||
<group colspan="2" attrs="{'invisible':[('constr_type','not in',['at most','a range', 'exactly'])]}">
|
||||
<field name="constr_maximum_req_ans" nolabel="1" />
|
||||
</group>
|
||||
<field name="constr_error_msg" string="Error message"/>
|
||||
</group>
|
||||
</group>
|
||||
|
||||
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
<tr><th>Title</th><th>Category</th><th>Description</th><th>Public URL</th></tr>
|
||||
<t t-foreach="surveys" t-as="survey">
|
||||
<tr>
|
||||
<td><t t-esc="survey.title" /></td>
|
||||
<td><t t-esc="survey.category"/></td>
|
||||
<td><t t-if="survey.description is not False"><t t-esc="survey.description"/></t></td>
|
||||
<td><span t-field="survey.title" /></td>
|
||||
<td><span t-field="survey.category"/></td>
|
||||
<td><t t-if="survey.description is not False"><span t-field="survey.description"/></t></td>
|
||||
<td><a t-att-href="survey.public_url"><t t-esc="survey.id" /></a></td>
|
||||
</tr>
|
||||
</t>
|
||||
@@ -45,16 +45,14 @@
|
||||
<div class="wrap">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-1"> </div>
|
||||
<div class="col-md-1"> </div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<t t-if="pagination['current'] == -1">
|
||||
<div class='jumbotron'>
|
||||
<h1>
|
||||
<t t-esc='survey.title'/>
|
||||
<span t-field='survey.title'/>
|
||||
<t t-if="survey.description is not False">
|
||||
<br/>
|
||||
<small><t t-esc='survey.description'/></small>
|
||||
<small><span t-field='survey.description'/></small>
|
||||
</t>
|
||||
</h1>
|
||||
</div>
|
||||
@@ -69,7 +67,11 @@
|
||||
<t t-if="pagination['current'] != -1">
|
||||
<div class='page-header'>
|
||||
<h1>
|
||||
<t t-esc='survey.title'/>
|
||||
<span t-field='survey.title'/>
|
||||
<t t-if="survey.description is not False">
|
||||
<br/>
|
||||
<small><span t-field='survey.description'/></small>
|
||||
</t>
|
||||
</h1>
|
||||
</div>
|
||||
<t t-set='page' t-value="survey.page_ids[pagination['current']]" />
|
||||
@@ -78,8 +80,6 @@
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col-md-1"> </div>
|
||||
<div class="col-md-1"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -99,8 +99,8 @@
|
||||
<!-- A page -->
|
||||
<template id="page" name="Page">
|
||||
<div>
|
||||
<h2><t t-esc='page.title' /></h2>
|
||||
<p><t t-if="page.description"><t t-esc='page.description'/></t></p>
|
||||
<h2><span t-field='page.title' /></h2>
|
||||
<p><t t-if="page.description"><span t-field='page.description'/></t></p>
|
||||
<p class="text-info text-right">Questions marked with <span class="glyphicon glyphicon-exclamation-sign"></span> are mandatory.</p>
|
||||
</div>
|
||||
<hr/>
|
||||
@@ -113,9 +113,9 @@
|
||||
</div>
|
||||
<div class="panel-body text-danger">
|
||||
<ul>
|
||||
<t t-foreach="problems" t-as='problem'>
|
||||
<li><strong><t t-esc="problem['qlabel']"/> :</strong> <t t-esc="problem['errmsg']"/></li>
|
||||
</t>
|
||||
<t t-foreach="problems" t-as='problem'>
|
||||
<li><strong><t t-esc="problem['qlabel']"/> :</strong> <t t-esc="problem['errmsg']"/></li>
|
||||
</t>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -146,12 +146,12 @@
|
||||
<t t-if="question.constr_mandatory"><span class="glyphicon glyphicon-exclamation-sign"></span></t>
|
||||
<span t-field='question.question'/><br/>
|
||||
|
||||
<small><t t-if="question.description"><t t-esc='question.description'/></t></small>
|
||||
<small><t t-if="question.description"><span t-field='question.description'/></t></small>
|
||||
</h3>
|
||||
</t>
|
||||
<t t-if="is_vector_element"> <!-- else -->
|
||||
<t t-if="question.type == 'simple_choice_scale'">
|
||||
<t t-field='question.question'/><t t-raw="'</td><td>'" />
|
||||
<span t-field='question.question'/><t t-raw="'</td><td>'" />
|
||||
</t>
|
||||
</t> <!-- endif -->
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
<div class="radio-inline">
|
||||
<label>
|
||||
<input type="radio" t-att-name="survey.id.__str__() + '*' + pagination['current'].__str__() + '*' + question.id.__str__()" t-att-value='suggestion.value' />
|
||||
<t t-esc='suggestion.value'/>
|
||||
<span t-field='suggestion.value'/>
|
||||
</label>
|
||||
</div>
|
||||
</t>
|
||||
@@ -186,6 +186,7 @@
|
||||
|
||||
<t t-if="question.type in ['simple_choice_dropdown']">
|
||||
<select class="form-control" t-att-name="survey.id.__str__() + '*' + pagination['current'].__str__() + '*' + question.id.__str__()">
|
||||
<option disabled="1" selected="1">Choose...</option>
|
||||
<t t-foreach='question.suggested_answers_ids' t-as='suggestion'>
|
||||
<option><t t-esc='suggestion.value'/></option>
|
||||
</t>
|
||||
@@ -197,7 +198,7 @@
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" t-att-name="survey.id.__str__() + '*' + pagination['current'].__str__() + '*' + question.id.__str__() + '*' + suggestion.id.__str__()" t-att-value='suggestion.value' />
|
||||
<t t-esc='suggestion.value'/>
|
||||
<span t-field='suggestion.value'/>
|
||||
</label>
|
||||
</div>
|
||||
</t>
|
||||
@@ -229,7 +230,6 @@
|
||||
|
||||
</t>
|
||||
|
||||
|
||||
<t t-if="question.type in ['matrix']">
|
||||
<table class="table table-responsive">
|
||||
<t t-foreach='question.children_ids' t-as='question'>
|
||||
@@ -238,15 +238,9 @@
|
||||
</table>
|
||||
</t>
|
||||
|
||||
|
||||
<!-- Comments -->
|
||||
<t t-if="question.comments_allowed">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Any comments ?</div>
|
||||
<div class="panel-body">
|
||||
TODO: show comments box here
|
||||
</div>
|
||||
</div>
|
||||
Other: <input type="text" class="form-control" t-att-name="survey.id.__str__() + '*' + pagination['current'].__str__() + '*' + question.id.__str__() + '*comments'"/>
|
||||
</t>
|
||||
|
||||
</template>
|
||||
@@ -263,10 +257,10 @@
|
||||
<div class="col-md-8">
|
||||
<div class='jumbotron'>
|
||||
<h1>
|
||||
<t t-esc='survey.title'/>
|
||||
<span t-field='survey.title'/>
|
||||
<t t-if="survey.description is not False">
|
||||
<br/>
|
||||
<small><t t-esc='survey.description'/></small>
|
||||
<small><span t-field='survey.description'/></small>
|
||||
</t>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user