formdefs: allow time in publication/expiration dates (#5268)

This commit is contained in:
Frédéric Péters 2014-08-19 15:03:08 +02:00
parent 925ade459f
commit 63f4131f71
5 changed files with 92 additions and 25 deletions

View File

@ -48,3 +48,27 @@ def test_is_disabled_expiration_date():
formdef.expiration_date = '%s-%02d-%02d' % (datetime.datetime.today() + datetime.timedelta(1)).timetuple()[:3]
assert not formdef.is_disabled()
def test_is_disabled_publication_datetime():
formdef = FormDef()
formdef.publication_date = '%s-%02d-%02d %02d:%02d' % (
datetime.datetime.now() - datetime.timedelta(hours=1)).timetuple()[:5]
assert not formdef.is_disabled()
formdef.publication_date = '%s-%02d-%02d %02d:%02d' % (
datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5]
assert formdef.is_disabled()
def test_is_disabled_expiration_datetime():
formdef = FormDef()
formdef.expiration_date = '%s-%02d-%02d %02d:%02d' % (
datetime.datetime.now() - datetime.timedelta(hours=1)).timetuple()[:5]
assert formdef.is_disabled()
formdef.expiration_date = '%s-%02d-%02d %02d:%02d' % (
datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5]
assert not formdef.is_disabled()

View File

@ -532,10 +532,10 @@ class FormDefPage(Directory):
hint=_('Redirection will only be performed if the form is disabled and a URL is given. '\
'Common substitution variables are available with the [variable] syntax.'),
value=self.formdef.disabled_redirection)
form.add(DateWidget, 'publication_date',
form.add(DateTimeWidget, 'publication_date',
title=_('Publication Date'),
value=self.formdef.publication_date)
form.add(DateWidget, 'expiration_date',
form.add(DateTimeWidget, 'expiration_date',
title=_('Expiration Date'),
value=self.formdef.expiration_date)

View File

@ -36,7 +36,7 @@ from qommon.storage import StorableObject
from quixote import get_request, get_publisher
from qommon.form import *
from qommon.misc import simplify, date_format
from qommon.misc import simplify, get_as_datetime
from qommon import get_cfg
from qommon.substitution import Substitutions
@ -745,14 +745,14 @@ class FormDef(StorableObject):
return True
if self.publication_date:
try:
publication_datetime = datetime.datetime.strptime(self.publication_date, date_format())
publication_datetime = get_as_datetime(self.publication_date)
except ValueError:
return False
if publication_datetime > datetime.datetime.now():
return True
if self.expiration_date:
try:
expiration_datetime = datetime.datetime.strptime(self.expiration_date, date_format())
expiration_datetime = get_as_datetime(self.expiration_date)
except ValueError:
return False
if expiration_datetime < datetime.datetime.now():

View File

@ -673,25 +673,33 @@ class DateWidget(StringWidget):
self.value = self.value.encode(get_publisher().site_charset)
return self.value
def get_format_string(self):
return misc.date_format()
def _parse(self, request):
StringWidget._parse(self, request)
if self.value is not None:
format_string = misc.date_format()
try:
value = time.strptime(self.value, format_string)
except ValueError:
for format_string in (self.get_format_string(),
misc.date_format(), '%Y-%m-%d'):
try:
value = time.strptime(self.value, format_string)
except ValueError:
continue
break
else:
self.error = _('invalid date')
self.value = None
else:
if value[0] < 1800 or value[0] > 2099:
self.error = _('invalid date')
self.value = None
elif self.minimum_date and value[:3] < self.minimum_date[:3]:
self.error = _('invalid date: date must be on or after %s') % strftime(
format_string, datetime.datetime(*self.minimum_date[:6]))
elif self.maximum_date and value[:3] > self.maximum_date[:3]:
self.error = _('invalid date; date must be on or before %s') % strftime(
format_string, datetime.datetime(*self.maximum_date[:6]))
return
if value[0] < 1800 or value[0] > 2099:
self.error = _('invalid date')
self.value = None
elif self.minimum_date and value[:3] < self.minimum_date[:3]:
self.error = _('invalid date: date must be on or after %s') % strftime(
misc.date_format(), datetime.datetime(*self.minimum_date[:6]))
elif self.maximum_date and value[:3] > self.maximum_date[:3]:
format_string = misc.date_format()
self.error = _('invalid date; date must be on or before %s') % strftime(
misc.date_format(), datetime.datetime(*self.maximum_date[:6]))
def prepare_javascript(cls):
get_response().add_javascript(['jquery.js', 'bootstrap-datetimepicker.js'])
@ -711,11 +719,16 @@ class DateWidget(StringWidget):
self.prepare_javascript()
date_format = misc.date_format().replace('%Y', 'yyyy').replace(
'%m', 'mm').replace('%d', 'dd')
date_format = self.get_format_string().replace('%Y', 'yyyy').replace(
'%m', 'mm').replace('%d', 'dd').replace('%H', 'hh').replace(
'%M', 'ii').replace('%S', 'ss')
args = []
args.append('format: "%s"' % date_format)
args.append('minView: 2')
if not 'hh' in date_format:
# if the date format doesn't contain the time, set widget not to go
# into the time pages
args.append('minView: 2')
args.append('autoclose: true')
args.append('weekStart: 1')
@ -723,14 +736,16 @@ class DateWidget(StringWidget):
start_date = date_format.replace(
'yyyy', '%04d' % self.minimum_date[0]).replace(
'mm', '%02d' % self.minimum_date[1]).replace(
'dd', '%02d' % self.minimum_date[2])
'dd', '%02d' % self.minimum_date[2]).replace(
'hh', '00').replace('ii', '00').replace('ss', '00')
args.append('startDate: "%s"' % start_date)
if self.maximum_date:
end_date = date_format.replace(
'yyyy', '%04d' % self.maximum_date[0]).replace(
'mm', '%02d' % self.maximum_date[1]).replace(
'dd', '%02d' % self.maximum_date[2])
'dd', '%02d' % self.maximum_date[2]).replace(
'hh', '00').replace('ii', '00').replace('ss', '00')
args.append('endDate: "%s"' % end_date)
for key, value in self.jpicker_args.iteritems():
args.append("%s: %s" % (key, value))
@ -752,6 +767,20 @@ $(function() {
return t
class DateTimeWidget(DateWidget):
'''StringWidget which checks the value entered is a correct date/time'''
content_extra_css_class = 'date'
def __init__(self, name, value=None, **kwargs):
DateWidget.__init__(self, name, value=value, **kwargs)
self.attrs['size'] = '16'
self.attrs['maxlength'] = '16'
def get_format_string(self):
return misc.datetime_format()
class RegexStringWidget(StringWidget):
'''StringWidget which checks the value entered is a correct regex'''
def _parse(self, request):

View File

@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import datetime
import re
import os
import time
@ -287,11 +288,14 @@ def get_datetime_language():
def localstrftime(t):
if not t:
return ''
return strftime.strftime(datetime_format(), t)
def datetime_format():
format_string = '%Y-%m-%d %H:%M'
lang = get_datetime_language()
if lang == 'fr':
format_string = '%d/%m/%Y %H:%M'
return strftime.strftime(format_string, t)
return format_string
def date_format():
format_string = '%Y-%m-%d'
@ -300,6 +304,16 @@ def date_format():
format_string = '%d/%m/%Y'
return format_string
def get_as_datetime(s):
for format_string in (datetime_format(), date_format(), '%Y-%m-%d %H:%M', '%Y-%m-%d'):
try:
return datetime.datetime.strptime(s, format_string)
except ValueError:
pass
raise ValueError()
def ellipsize(s, length = 30):
if type(s) is not unicode:
s = unicode(s, get_publisher().site_charset, 'replace')