Skip to content

Commit

Permalink
Prevent invalid data to be silently accepted
Browse files Browse the repository at this point in the history
When a user wants sets a ``Date`` or ``Datetime`` value and misses
one of the fields (day, year, hour or minute) it is silently set to
None without any 'input is not valid' error message being displayed.

Unfortunately it can not be checked on a validator because the input
value has already been converted to a ``datetime``.

This commit works around it making sure an error is raised and only
convert it to None if both *day* and *year* are left empty.
  • Loading branch information
bogdangi authored and gforcada committed Oct 21, 2015
1 parent 3af21cf commit b0a9533
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 12 deletions.
4 changes: 2 additions & 2 deletions HISTORY.rst
Expand Up @@ -4,8 +4,8 @@ Changelog
1.2.8 (unreleased)
------------------

- Nothing changed yet.

- Prevent invalid data to be silently accepted.
[bogdangi]

1.2.7 (2015-04-29)
------------------
Expand Down
26 changes: 18 additions & 8 deletions src/collective/z3cform/datetimewidget/converter.py
Expand Up @@ -25,16 +25,21 @@
from collective.z3cform.datetimewidget.interfaces import DateValidationError, DatetimeValidationError

class DateDataConverter(BaseDataConverter):

def toWidgetValue(self, value):
if value is self.field.missing_value:
return ('', '', '')
return (value.year, value.month, value.day)

def toFieldValue(self, value):
for val in value:
if not val:
return self.field.missing_value
if len(value) != 3:
raise DateValidationError

year, month, day = value

if not year \
and not day:
return self.field.missing_value

try:
value = map(int, value)
Expand All @@ -46,16 +51,21 @@ def toFieldValue(self, value):
raise DateValidationError

class DatetimeDataConverter(DateDataConverter):

def toWidgetValue(self, value):
if value is self.field.missing_value:
return ('', '', '', '00', '00')
return (value.year, value.month, value.day, value.hour, value.minute)

def toFieldValue(self, value):
for val in value:
if not val:
return self.field.missing_value
if len(value) != 5:
raise DatetimeValidationError

year, month, day, hour, minute = value

if not year \
and not day:
return self.field.missing_value

try:
value = map(int, value)
Expand Down
43 changes: 41 additions & 2 deletions src/collective/z3cform/datetimewidget/converter.txt
Expand Up @@ -37,10 +37,10 @@ We can also convert widget values to field values.
>>> converter.toFieldValue(('2009', '5', '10'))
datetime.date(2009, 5, 10)

If any of the widget value components is missing, a value of None will be
If day and year of the widget value components is missing, a value of None will be
returned.

>>> converter.toFieldValue(('', '5', '10')) is None
>>> converter.toFieldValue(('', '5', '')) is None
True

If all of the widget value components are present but they don't correspond to
Expand All @@ -52,3 +52,42 @@ a valid date, a validation error will be raised.
DateValidationError


Let's set up a datetime field, datetime widget, and a converter adapting both of them.

>>> from zope.schema import Datetime
>>> from collective.z3cform.datetimewidget import DatetimeWidget
>>> from collective.z3cform.datetimewidget.converter import DatetimeDataConverter
>>> field = Datetime()
>>> request = TestRequest()
>>> widget = DatetimeWidget(request)
>>> converter = DatetimeDataConverter(field, widget)

Now we can convert field values to widget values.

>>> from datetime import datetime
>>> converter.toWidgetValue(datetime(2009, 5, 10, 15, 35))
(2009, 5, 10, 15, 35)

A value of None results in a tuple of empty strings.

>>> converter.toWidgetValue(None)
('', '', '', '00', '00')

We can also convert widget values to field values.

>>> converter.toFieldValue(('2009', '5', '10', '15', '35'))
datetime.datetime(2009, 5, 10, 15, 35)

If day and year of the widget value components is missing, a value of None will be
returned.

>>> converter.toFieldValue(('', '5', '', '00', '00')) is None
True

If all of the widget value components are present but they don't correspond to
a valid date, a validation error will be raised.

>>> converter.toFieldValue(('2009', '42', '42', '42', '82'))
Traceback (most recent call last):
...
DatetimeValidationError

0 comments on commit b0a9533

Please sign in to comment.