Skip to content

Commit 67b2fc1

Browse files
committed
Extended the form fields used for duration to accept additional formats, including formats the secretariat are currently using, in order to avoid trouble with the TimedeltaField --> DurationField transition.
- Legacy-Id: 12598
1 parent 3d6b370 commit 67b2fc1

4 files changed

Lines changed: 68 additions & 6 deletions

File tree

ietf/meeting/migrations/0043_auto_20161219_1345.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ class Migration(migrations.Migration):
1515
migrations.AddField(
1616
model_name='meeting',
1717
name='xidsubmit_cutoff_time_utc',
18-
field=models.DurationField(default=datetime.timedelta(0, 86399), help_text=b'The time of day (UTC) after which submission will be closed. Use for example 23 hours, 59 minutes, 59 seconds.', blank=True),
18+
field=models.DurationField(default=datetime.timedelta(0, 86399), help_text=b"The time of day (UTC) after which submission will be closed. Use for example 23:59:59.", blank=True),
1919
),
2020
migrations.AddField(
2121
model_name='meeting',
2222
name='xidsubmit_cutoff_warning_days',
23-
field=models.DurationField(default=datetime.timedelta(21), help_text=b'How long before the 00 cutoff to start showing cutoff warnings. Use for example 21 days or 3 weeks.', blank=True),
23+
field=models.DurationField(default=datetime.timedelta(21), help_text=b"How long before the 00 cutoff to start showing cutoff warnings. Use for example '21' or '21 days'.", blank=True),
2424
),
2525
migrations.AddField(
2626
model_name='session',

ietf/meeting/models.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ class Meeting(models.Model):
6868
help_text = "The number of days before the meeting start date when the submission of -01 drafts etc. will be closed.")
6969
idsubmit_cutoff_time_utc = models.DurationField(blank=True,
7070
default=settings.IDSUBMIT_DEFAULT_CUTOFF_TIME_UTC,
71-
help_text = "The time of day (UTC) after which submission will be closed. Use for example 23 hours, 59 minutes, 59 seconds.")
71+
help_text = "The time of day (UTC) after which submission will be closed. Use for example 23:59:59.")
7272
idsubmit_cutoff_warning_days = models.DurationField(blank=True,
7373
default=settings.IDSUBMIT_DEFAULT_CUTOFF_WARNING_DAYS,
74-
help_text = "How long before the 00 cutoff to start showing cutoff warnings. Use for example 21 days or 3 weeks.")
74+
help_text = "How long before the 00 cutoff to start showing cutoff warnings. Use for example '21' or '21 days'.")
7575
submission_start_day_offset = models.IntegerField(blank=True,
7676
default=settings.MEETING_MATERIALS_DEFAULT_SUBMISSION_START_DAYS,
7777
help_text = "The number of days before the meeting start date after which meeting materials will be accepted.")

ietf/secr/meetings/forms.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ietf.group.models import Group
77
from ietf.meeting.models import Meeting, Room, TimeSlot, Session, SchedTimeSessAssignment
88
from ietf.name.models import TimeSlotTypeName
9-
9+
import ietf.utils.fields
1010

1111
DAYS_CHOICES = ((-1,'Saturday'),
1212
(0,'Sunday'),
@@ -87,10 +87,18 @@ def valid_value(self, value):
8787
# Forms
8888
#----------------------------------------------------------
8989
class MeetingModelForm(forms.ModelForm):
90+
idsubmit_cutoff_time_utc = ietf.utils.fields.DurationField()
91+
idsubmit_cutoff_warning_days = ietf.utils.fields.DurationField()
9092
class Meta:
9193
model = Meeting
9294
exclude = ('type', 'agenda', 'session_request_lock_message')
9395

96+
97+
def __init__(self,*args,**kwargs):
98+
super(MeetingModelForm, self).__init__(*args,**kwargs)
99+
for f in [ 'idsubmit_cutoff_warning_days', 'idsubmit_cutoff_time_utc', ]:
100+
self.fields[f].help_text = kwargs['instance']._meta.get_field(f).help_text
101+
94102
def clean_number(self):
95103
number = self.cleaned_data['number']
96104
if not number.isdigit():
@@ -174,7 +182,7 @@ def clean_group(self):
174182
class TimeSlotForm(forms.Form):
175183
day = forms.ChoiceField(choices=DAYS_CHOICES)
176184
time = forms.TimeField()
177-
duration = forms.DurationField(help_text="Enter duration as 'DD HH:MM:SS', or parts thereof. '3:42' means 3 minutes, 42 seconds, not 3 hours 42 minutes.")
185+
duration = ietf.utils.fields.DurationField()
178186
name = forms.CharField(help_text='Name that appears on the agenda')
179187

180188
class NonSessionForm(TimeSlotForm):

ietf/utils/fields.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
# Copyright The IETF Trust 2007, All Rights Reserved
2+
3+
import re
4+
import six
5+
import datetime
6+
7+
import debug
8+
19
from django import forms
210
from django.core.validators import validate_email
11+
from django.core.exceptions import ValidationError
12+
from django.utils.dateparse import parse_duration
313

414
class MultiEmailField(forms.Field):
515
def to_python(self, value):
@@ -64,3 +74,47 @@ def __init__(self, date_format, picker_settings={}, *args, **kwargs):
6474
self.widget.attrs["placeholder"] = date_format
6575
for k, v in picker_settings.iteritems():
6676
self.widget.attrs["data-date-%s" % k] = v
77+
78+
79+
# This accepts any ordered combination of labelled days, hours, minutes, seconds
80+
ext_duration_re = re.compile(
81+
r'^'
82+
r'(?:(?P<days>-?\d+) ?(?:d|days))?'
83+
r'(?:[, ]*(?P<hours>-?\d+) ?(?:h|hours))?'
84+
r'(?:[, ]*(?P<minutes>-?\d+) ?(?:m|minutes))?'
85+
r'(?:[, ]*(?P<seconds>-?\d+) ?(?:s|seconds))?'
86+
r'$'
87+
)
88+
# This requires hours and minutes, and accepts optional X days and :SS
89+
mix_duration_re = re.compile(
90+
r'^'
91+
r'(?:(?P<days>-?\d+) ?(?:d|days)[, ]*)?'
92+
r'(?:(?P<hours>-?\d+))'
93+
r'(?::(?P<minutes>-?\d+))'
94+
r'(?::(?P<seconds>-?\d+))?'
95+
r'$'
96+
)
97+
98+
def parse_duration_ext(value):
99+
if value.strip() != '':
100+
match = ext_duration_re.match(value)
101+
if not match:
102+
match = mix_duration_re.match(value)
103+
if not match:
104+
return parse_duration(value)
105+
else:
106+
kw = match.groupdict()
107+
kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None}
108+
return datetime.timedelta(**kw)
109+
110+
class DurationField(forms.DurationField):
111+
def to_python(self, value):
112+
if value in self.empty_values:
113+
return None
114+
if isinstance(value, datetime.timedelta):
115+
return value
116+
value = parse_duration_ext(value)
117+
if value is None:
118+
raise ValidationError(self.error_messages['invalid'], code='invalid')
119+
return value
120+

0 commit comments

Comments
 (0)