add time and duration to interim request form

- Legacy-Id: 10884
This commit is contained in:
Ryan Cross 2016-03-01 23:44:49 +00:00
parent 3a1af7dc83
commit 269547a757
2 changed files with 112 additions and 2 deletions

View file

@ -1,6 +1,11 @@
import datetime
import re
from django import forms
from django.forms.fields import Field
from django.utils.encoding import force_text
from django.utils import six
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role
from ietf.meeting.models import Meeting, Schedule, TimeSlot, Session, SchedTimeSessAssignment, countries, timezones
@ -9,6 +14,93 @@ from ietf.meeting.models import Meeting, Schedule, TimeSlot, Session, SchedTimeS
countries.insert(0, ('', '-'*9 ))
timezones.insert(0, ('', '-'*9 ))
# -------------------------------------------------
# DurationField from Django 1.8
# -------------------------------------------------
def duration_string(duration):
days = duration.days
seconds = duration.seconds
microseconds = duration.microseconds
minutes = seconds // 60
seconds = seconds % 60
hours = minutes // 60
minutes = minutes % 60
string = '{:02d}:{:02d}:{:02d}'.format(hours, minutes, seconds)
if days:
string = '{} '.format(days) + string
if microseconds:
string += '.{:06d}'.format(microseconds)
return string
standard_duration_re = re.compile(
r'^'
r'(?:(?P<days>-?\d+) (days?, )?)?'
r'((?:(?P<hours>\d+):)(?=\d+:\d+))?'
r'(?:(?P<minutes>\d+):)?'
r'(?P<seconds>\d+)'
r'(?:\.(?P<microseconds>\d{1,6})\d{0,6})?'
r'$'
)
# Support the sections of ISO 8601 date representation that are accepted by
# timedelta
iso8601_duration_re = re.compile(
r'^P'
r'(?:(?P<days>\d+(.\d+)?)D)?'
r'(?:T'
r'(?:(?P<hours>\d+(.\d+)?)H)?'
r'(?:(?P<minutes>\d+(.\d+)?)M)?'
r'(?:(?P<seconds>\d+(.\d+)?)S)?'
r')?'
r'$'
)
def parse_duration(value):
"""Parses a duration string and returns a datetime.timedelta.
The preferred format for durations in Django is '%d %H:%M:%S.%f'.
Also supports ISO 8601 representation.
"""
match = standard_duration_re.match(value)
if not match:
match = iso8601_duration_re.match(value)
if match:
kw = match.groupdict()
if kw.get('microseconds'):
kw['microseconds'] = kw['microseconds'].ljust(6, '0')
kw = {k: float(v) for k, v in six.iteritems(kw) if v is not None}
return datetime.timedelta(**kw)
class DurationField(Field):
default_error_messages = {
'invalid': 'Enter a valid duration.',
}
def prepare_value(self, value):
if isinstance(value, datetime.timedelta):
return duration_string(value)
return value
def to_python(self, value):
if value in self.empty_values:
return None
if isinstance(value, datetime.timedelta):
return value
value = parse_duration(force_text(value))
if value is None:
raise ValidationError(self.error_messages['invalid'], code='invalid')
return value
# -------------------------------------------------
# Helpers
# -------------------------------------------------
class GroupModelChoiceField(forms.ModelChoiceField):
'''
Custom ModelChoiceField, changes the label to a more readable format
@ -16,9 +108,15 @@ class GroupModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.acronym
# -------------------------------------------------
# Forms
# -------------------------------------------------
class InterimRequestForm(forms.Form):
group = GroupModelChoiceField(queryset = Group.objects.filter(type__in=('wg','rg'),state='active').order_by('acronym'))
date = forms.DateField()
time = forms.TimeField()
duration = DurationField()
face_to_face = forms.BooleanField(required=False)
city = forms.CharField(max_length=255,required=False)
country = forms.ChoiceField(choices=countries,required=False)
@ -41,6 +139,8 @@ class InterimRequestForm(forms.Form):
agenda = self.cleaned_data.get('agenda')
agenda_note = self.cleaned_data.get('agenda_note')
date = self.cleaned_data.get('date')
time = self.cleaned_data.get('time')
duration = self.cleaned_data.get('duration')
group = self.cleaned_data.get('group')
city = self.cleaned_data.get('city')
country = self.cleaned_data.get('country')
@ -51,8 +151,10 @@ class InterimRequestForm(forms.Form):
meeting = Meeting.objects.create(number=number,type_id='interim',date=date,city=city,
country=country,agenda_note=agenda_note,time_zone=timezone)
schedule = Schedule.objects.create(meeting=meeting, owner=self.person, visible=True, public=True)
slot = TimeSlot.objects.create(meeting=meeting, type_id="session", duration=30 * 60,
time=datetime.datetime.combine(datetime.date.today(), datetime.time(9, 30)))
meeting.agenda = schedule
meeting.save()
slot = TimeSlot.objects.create(meeting=meeting, type_id="session", duration=duration,
time=datetime.datetime.combine(date, time))
session = Session.objects.create(meeting=meeting,
group=group,
requested_by=self.person,

View file

@ -389,6 +389,9 @@ class InterimTests(TestCase):
def test_interim_request_submit(self):
make_meeting_test_data()
date = datetime.date.today() + datetime.timedelta(days=30)
time = datetime.datetime.now().time().replace(microsecond=0,second=0)
dt = datetime.datetime.combine(date, time)
duration = datetime.timedelta(hours=3)
group = Group.objects.get(acronym='mars')
city = 'San Francisco'
country = 'US'
@ -399,6 +402,8 @@ class InterimTests(TestCase):
self.client.login(username="secretary", password="secretary+password")
data = {'group':group.pk,
'date':date.strftime("%Y-%m-%d"),
'time':time.strftime('%H:%M'),
'duration':'03:00:00',
'city':city,
'country':country,
'timezone':timezone,
@ -421,6 +426,9 @@ class InterimTests(TestCase):
self.assertEqual(meeting.agenda_note,agenda_note)
session = meeting.session_set.first()
self.assertEqual(session.remote_instructions,remote_instructions)
timeslot = session.official_timeslotassignment().timeslot
self.assertEqual(timeslot.time,dt)
self.assertEqual(timeslot.duration,duration)