WEBUI: HTML5 datetime for all timeforms

refs #35
This commit is contained in:
boyska 2017-01-03 12:45:49 +01:00
parent 9c84669749
commit 3718649cd3
No known key found for this signature in database
GPG key ID: 7395DCAE58289CA9
4 changed files with 136 additions and 139 deletions

132
larigira/timeform_base.py Normal file
View file

@ -0,0 +1,132 @@
from datetime import datetime
from pytimeparse.timeparse import timeparse
from flask_wtf import Form
from wtforms import StringField, Field, validators, SubmitField, \
SelectMultipleField, ValidationError
import wtforms.widgets
class DateTimeInput(wtforms.widgets.Input):
input_type = 'datetime-local'
class EasyDateTimeField(Field):
'''
a "fork" of DateTimeField which uses HTML5 datetime-local
The format is not customizable, because it is imposed by the HTML5 specification
'''
widget = DateTimeInput()
def __init__(self, label=None, validators=None, **kwargs):
super(EasyDateTimeField, self).__init__(label, validators, **kwargs)
self.format = '%Y-%m-%dT%H:%M:%S'
def _value(self):
if self.raw_data:
return ' '.join(self.raw_data)
else:
return self.data and self.data.strftime(self.format) or ''
def process_formdata(self, valuelist):
if valuelist:
date_str = ' '.join(valuelist)
try:
self.data = datetime.strptime(date_str, self.format)
except ValueError:
self.data = None
raise ValueError(self.gettext(
'Not a valid datetime value <tt>{}</tt>').format(date_str))
class SingleAlarmForm(Form):
nick = StringField('Alarm nick', validators=[validators.required()],
description='A simple name to recognize this alarm')
dt = EasyDateTimeField('Date and time', validators=[validators.required()],
description='Date to ring on, expressed as '
'2000-12-31T13:42:00')
submit = SubmitField('Submit')
def populate_from_timespec(self, timespec):
if 'nick' in timespec:
self.nick.data = timespec['nick']
if 'timestamp' in timespec:
self.dt.data = datetime.fromtimestamp(timespec['timestamp'])
def singlealarm_receive(form):
return {
'kind': 'single',
'nick': form.nick.data,
'timestamp': int(form.dt.data.strftime('%s'))
}
class FrequencyAlarmForm(Form):
nick = StringField('Alarm nick', validators=[validators.required()],
description='A simple name to recognize this alarm')
interval = StringField('Frequency',
validators=[validators.required()],
description='in seconds, or human-readable '
'(like 9w3d12h)')
start = EasyDateTimeField('Start date and time',
validators=[validators.optional()],
description='Before this, no alarm will ring. '
'Expressed as YYYY-MM-DDTHH:MM:SS. If omitted, '
'the alarm will always ring')
end = EasyDateTimeField('End date and time',
validators=[validators.optional()],
description='After this, no alarm will ring. '
'Expressed as YYYY-MM-DDTHH:MM:SS. If omitted, '
'the alarm will always ring')
weekdays = SelectMultipleField('Days on which the alarm should be played',
choices=[('1', 'Monday'),
('2', 'Tuesday'),
('3', 'Wednesday'),
('4', 'Thursday'),
('5', 'Friday'),
('6', 'Saturday'),
('7', 'Sunday')],
default=list('1234567'),
validators=[validators.required()],
description='The alarm will ring only on '
'selected weekdays')
submit = SubmitField('Submit')
def populate_from_timespec(self, timespec):
if 'nick' in timespec:
self.nick.data = timespec['nick']
if 'start' in timespec:
self.start.data = datetime.fromtimestamp(timespec['start'])
if 'end' in timespec:
self.end.data = datetime.fromtimestamp(timespec['end'])
if 'weekdays' in timespec:
self.weekdays.data = timespec['weekdays']
else:
self.weekdays.data = list('1234567')
self.interval.data = timespec['interval']
def validate_interval(form, field):
try:
int(field.data)
except ValueError:
if timeparse(field.data) is None:
raise ValidationError("interval must either be a number "
"(in seconds) or a human-readable "
"string like '1h2m' or '1d12h'")
def frequencyalarm_receive(form):
obj = {
'kind': 'frequency',
'nick': form.nick.data,
'interval': form.interval.data,
'weekdays': form.weekdays.data,
}
if form.start.data:
obj['start'] = int(form.start.data.strftime('%s'))
else:
obj['start'] = 0
if form.end.data:
obj['end'] = int(form.end.data.strftime('%s'))
return obj

View file

@ -1,75 +0,0 @@
from datetime import datetime
from pytimeparse.timeparse import timeparse
from flask_wtf import Form
from wtforms import StringField, DateTimeField, validators, \
SubmitField, ValidationError, SelectMultipleField
class FrequencyAlarmForm(Form):
nick = StringField('Alarm nick', validators=[validators.required()],
description='A simple name to recognize this alarm')
interval = StringField('Frequency',
validators=[validators.required()],
description='in seconds, or human-readable '
'(like 9w3d12h)')
start = DateTimeField('Start date and time',
validators=[validators.optional()],
description='Date before which no alarm will ring, '
'expressed as YYYY-MM-DD HH:MM:SS; if omitted, the '
'alarm will always ring')
end = DateTimeField('End date and time',
validators=[validators.optional()],
description='Date after which no alarm will ring, '
'expressed as YYYY-MM-DD HH:MM:SS; if omitted, the '
'alarm will always ring')
weekdays = SelectMultipleField('Days on which the alarm should be played',
choices=[('1', 'Monday'),
('2', 'Tuesday'),
('3', 'Wednesday'),
('4', 'Thursday'),
('5', 'Friday'),
('6', 'Saturday'),
('7', 'Sunday')],
default=list('1234567'),
validators=[validators.required()],
description='The alarm will ring only on '
'selected weekdays')
submit = SubmitField('Submit')
def populate_from_timespec(self, timespec):
if 'nick' in timespec:
self.nick.data = timespec['nick']
if 'start' in timespec:
self.start.data = datetime.fromtimestamp(timespec['start'])
if 'end' in timespec:
self.end.data = datetime.fromtimestamp(timespec['end'])
if 'weekdays' in timespec:
self.weekdays.data = timespec['weekdays']
else:
self.weekdays.data = list('1234567')
self.interval.data = timespec['interval']
def validate_interval(form, field):
try:
int(field.data)
except ValueError:
if timeparse(field.data) is None:
raise ValidationError("interval must either be a number "
"(in seconds) or a human-readable "
"string like '1h2m' or '1d12h'")
def frequencyalarm_receive(form):
obj = {
'kind': 'frequency',
'nick': form.nick.data,
'interval': form.interval.data,
'weekdays': form.weekdays.data,
}
if form.start.data:
obj['start'] = int(form.start.data.strftime('%s'))
else:
obj['start'] = 0
if form.end.data:
obj['end'] = int(form.end.data.strftime('%s'))
return obj

View file

@ -1,60 +0,0 @@
from datetime import datetime
from flask_wtf import Form
from wtforms import StringField, Field, validators, SubmitField
import wtforms.widgets
class DateTimeInput(wtforms.widgets.Input):
input_type = 'datetime-local'
class EasyDateTimeField(Field):
'''
a "fork" of DateTimeField which uses HTML5 datetime-local
The format is not customizable, because it is imposed by the HTML5 specification
'''
widget = DateTimeInput()
def __init__(self, label=None, validators=None, **kwargs):
super(EasyDateTimeField, self).__init__(label, validators, **kwargs)
self.format = '%Y-%m-%dT%H:%M:%S'
def _value(self):
if self.raw_data:
return ' '.join(self.raw_data)
else:
return self.data and self.data.strftime(self.format) or ''
def process_formdata(self, valuelist):
if valuelist:
date_str = ' '.join(valuelist)
try:
self.data = datetime.strptime(date_str, self.format)
except ValueError:
self.data = None
raise ValueError(self.gettext('Not a valid datetime value <tt>{}</tt>').format(date_str))
class SingleAlarmForm(Form):
nick = StringField('Alarm nick', validators=[validators.required()],
description='A simple name to recognize this alarm')
dt = EasyDateTimeField('Date and time', validators=[validators.required()],
description='Date to ring on, expressed as '
'2000-12-31T13:42:00')
submit = SubmitField('Submit')
def populate_from_timespec(self, timespec):
if 'nick' in timespec:
self.nick.data = timespec['nick']
if 'timestamp' in timespec:
self.dt.data = datetime.fromtimestamp(timespec['timestamp'])
def singlealarm_receive(form):
return {
'kind': 'single',
'nick': form.nick.data,
'timestamp': int(form.dt.data.strftime('%s'))
}

View file

@ -68,12 +68,12 @@ setup(name='larigira',
'single = larigira.timegen_every:SingleAlarm', 'single = larigira.timegen_every:SingleAlarm',
], ],
'larigira.timeform_create': [ 'larigira.timeform_create': [
'single = larigira.timeform_single:SingleAlarmForm', 'single = larigira.timeform_base:SingleAlarmForm',
'frequency = larigira.timeform_frequency:FrequencyAlarmForm', 'frequency = larigira.timeform_base:FrequencyAlarmForm',
], ],
'larigira.timeform_receive': [ 'larigira.timeform_receive': [
'single = larigira.timeform_single:singlealarm_receive', 'single = larigira.timeform_base:singlealarm_receive',
'frequency = larigira.timeform_frequency:frequencyalarm_receive', 'frequency = larigira.timeform_base:frequencyalarm_receive',
], ],
'larigira.audioform_create': [ 'larigira.audioform_create': [
'static = larigira.audioform_static:StaticAudioForm', 'static = larigira.audioform_static:StaticAudioForm',