--- a/app/soc/views/helper/surveys.py Fri Jul 03 12:10:24 2009 +0200
+++ b/app/soc/views/helper/surveys.py Fri Jul 03 14:19:23 2009 +0200
@@ -42,6 +42,7 @@
from soc.logic import dicts
from soc.logic.lists import Lists
+from soc.models.survey import COMMENT_PREFIX
from soc.models.survey import SurveyContent
@@ -83,20 +84,26 @@
pick_quant=self.addQuantField,
)
+ self.kwargs['data'] = {}
super(SurveyForm, self).__init__(*args, **self.kwargs)
- def getFields(self):
+ def getFields(self, post_dict=None):
"""Build the SurveyContent (questions) form fields.
+ params:
+ post_dict: dict with POST data that will be used for validation
+
Populates self.survey_fields, which will be ordered in self.insert_fields.
+ Also populates self.data, which will be used in form validation.
"""
if not self.survey_content:
return
+ post_dict = post_dict or {}
self.survey_fields = {}
schema = SurveyContentSchema(self.survey_content.schema)
- has_record = (not self.editing) and self.survey_record
+ has_record = (not self.editing) and (self.survey_record or post_dict)
extra_attrs = {}
# figure out whether we want a read-only view
@@ -117,23 +124,51 @@
# a comment made by the user
comment = ''
- if has_record and hasattr(self.survey_record, field):
+
+ # flag to know where the value came from
+ from_content = False
+
+ if has_record and field in post_dict:
+ # entered value that is not yet saved
+ value = post_dict[field]
+ if COMMENT_PREFIX + field in post_dict:
+ comment = post_dict[COMMENT_PREFIX + field]
+ elif has_record and hasattr(self.survey_record, field):
# previously entered value
value = getattr(self.survey_record, field)
- if hasattr(self.survey_record, 'comment_for_' + field):
- comment = getattr(self.survey_record, 'comment_for_' + field)
+ if hasattr(self.survey_record, COMMENT_PREFIX + field):
+ comment = getattr(self.survey_record, COMMENT_PREFIX + field)
else:
# use prompts set by survey creator
value = getattr(self.survey_content, field)
+ from_content = True
label = schema.getLabel(field)
if label is None:
continue
- # dispatch to field-specific methods
+ # fix validation for pick_multi fields
+ is_multi = schema.getType(field) == 'pick_multi'
+ if not from_content and schema.getType(field) == 'pick_multi':
+ if isinstance(value, basestring):
+ value = value.split(',')
+ elif from_content and is_multi:
+ value = []
+
+ # record field value for validation
+ if not from_content:
+ self.data[field] = value
+
+ # find correct field type
addField = self.fields_map[schema.getType(field)]
addField(field, value, extra_attrs, schema, label=label, comment=comment)
+ # handle comments
+ comment_name = COMMENT_PREFIX + field
+ if comment_name in post_dict or hasattr(self.survey_record, comment_name):
+ self.data[comment_name] = comment
+ self.addCommentField(field, comment, extra_attrs, tip='Add a comment.')
+
return self.insertFields()
def insertFields(self):
@@ -147,9 +182,11 @@
position = position * 2
self.fields.insert(position, property, self.survey_fields[property])
if not self.editing:
- property = 'comment_for_' + property
- self.fields.insert(position - 1, property,
- self.survey_fields[property])
+ # add comment if field has one and this isn't an edit view
+ property = COMMENT_PREFIX + property
+ if property in self.survey_fields:
+ self.fields.insert(position - 1, property,
+ self.survey_fields[property])
return self.fields
def addLongField(self, field, value, attrs, schema, req=False, label='',
@@ -176,7 +213,6 @@
widget=widget, initial=value)
self.survey_fields[field] = question
- self.addCommentField(field, comment, attrs, tip)
def addShortField(self, field, value, attrs, schema, req=False, label='',
tip='', comment=''):
@@ -203,7 +239,6 @@
widget=widget, max_length=140, initial=value)
self.survey_fields[field] = question
- self.addCommentField(field, comment, attrs, tip)
def addSingleField(self, field, value, attrs, schema, req=False, label='',
tip='', comment=''):
@@ -240,7 +275,6 @@
choices=tuple(these_choices), widget=widget)
self.survey_fields[field] = question
- self.addCommentField(field, comment, attrs, tip)
def addMultiField(self, field, value, attrs, schema, req=False, label='',
tip='', comment=''):
@@ -276,7 +310,6 @@
initial=value)
self.survey_fields[field] = question
- self.addCommentField(field, comment, attrs, tip)
def addQuantField(self, field, value, attrs, schema, req=False, label='',
tip='', comment=''):
@@ -309,14 +342,13 @@
choices=tuple(these_choices), widget=widget,
initial=value)
self.survey_fields[field] = question
- self.addCommentField(field, comment, attrs, tip)
def addCommentField(self, field, comment, attrs, tip):
if not self.editing:
widget = widgets.Textarea(attrs=attrs)
- comment = CharField(help_text=tip, required=False, label='Comments',
+ comment_field = CharField(help_text=tip, required=False, label='Comments',
widget=widget, initial=comment)
- self.survey_fields['comment_for_' + field] = comment
+ self.survey_fields[COMMENT_PREFIX + field] = comment_field
class Meta(object):
model = SurveyContent
@@ -606,10 +638,11 @@
post_dict: dictionary with data from the POST request
"""
- # TODO(ljvderijk) deal with the comment fields
+ # TODO(ljvderijk) deal with the comment fields neatly
# get the schema for this survey
- schema = eval(survey.survey_content.schema)
+ schema = SurveyContentSchema(survey.survey_content.schema)
+ schema_dict = schema.schema
# fill a dictionary with the data to be stored in the SurveyRecord
response_dict = {}
@@ -617,16 +650,25 @@
for name, value in post_dict.items():
# make sure name is a string
name = name.encode()
- if name not in schema:
+
+ if name not in schema_dict:
# property not in survey schema ignore
continue
else:
- pick_multi = schema[name]['type'] == 'pick_multi'
+ pick_multi = schema.getType(name) == 'pick_multi'
if pick_multi and hasattr(post_dict, 'getlist'): # it's a multidict
- response_dict[name] = ','.join(post_dict.getlist(name))
- else:
- response_dict[name] = value
+ # validation asks for a list of values
+ value = post_dict.getlist(name)
+
+ response_dict[name] = value
+
+ # handle comments
+ comment_name = COMMENT_PREFIX + name
+ if comment_name in post_dict:
+ comment = post_dict.get(comment_name)
+ if comment:
+ response_dict[comment_name] = comment
return response_dict
@@ -796,16 +838,16 @@
except StopIteration:
# bail out early if survey_records.run() is empty
return header, survey.link_id
-
+
# generate results list
recs = record_query.run()
recs = _get_records(recs, properties)
-
+
# write results to CSV
output = StringIO.StringIO()
writer = csv.writer(output)
writer.writerow(properties)
writer.writerows(recs)
-
+
return header + output.getvalue(), survey.link_id
return wrapper
--- a/app/soc/views/models/survey.py Fri Jul 03 12:10:24 2009 +0200
+++ b/app/soc/views/models/survey.py Fri Jul 03 14:19:23 2009 +0200
@@ -43,6 +43,7 @@
from soc.views import out_of_band
from soc.views.helper import access
from soc.views.helper import decorators
+from soc.views.helper import forms as forms_helper
from soc.views.helper import redirects
from soc.views.helper import responses
from soc.views.helper import surveys
@@ -523,13 +524,14 @@
return record_logic.getForFields(filter, unique=True)
def takeGet(self, request, template, context, params, entity, record,
- **kwargs):
+ form_data=None, **kwargs):
"""Handles the GET request for the Survey's take page.
Args:
template: the template used for this view
entity: the Survey entity
record: a SurveyRecord entity
+ form_data: dict with form data that will be used for validation
rest: see base.View.public()
"""
@@ -537,7 +539,15 @@
survey_record=record,
survey_logic=self._params['logic'])
- survey_form.getFields()
+ # fetch field contents and pass request data, if any
+ survey_form.getFields(post_dict=form_data)
+
+ # validate request data
+ if form_data and not survey_form.is_valid():
+ survey_form.full_clean()
+ context['survey_form'] = survey_form
+ return self._constructResponse(request, entity=None, context=context,
+ form=survey_form, params=params, template=template)
# fill context with the survey and additional information
context['survey_form'] = survey_form
@@ -576,8 +586,20 @@
survey_logic = params['logic']
record_logic = survey_logic.getRecordLogic()
- # TODO: check the validity of the form data
- properties = surveys.getSurveyResponseFromPost(entity, request.POST)
+ # create a form to validate
+ survey_form = surveys.SurveyForm(survey_content=entity.survey_content,
+ survey_record=None,
+ survey_logic=self._params['logic'])
+ # fill form with request data
+ survey_form.getFields(post_dict=request.POST)
+
+ if not survey_form.is_valid():
+ # redirect to takeGet so we can handle errors
+ return self.takeGet(request, template, context, params, entity, record,
+ form_data=properties)
+
+ # retrieve the data from the form
+ _, properties = forms_helper.collectCleanedFields(survey_form)
# add the required SurveyRecord properties
properties['user'] = user_logic.getForCurrentAccount()
@@ -614,7 +636,7 @@
Args:
context: the context for the view to update
survey: a Survey entity
- survey_record: a SurveyRecordEntity
+ survey_record: a SurveyRecordEntity
"""
if not survey.survey_end: