datatracker/ietf/secr/meetings/forms.py

214 lines
8.5 KiB
Python

# Copyright The IETF Trust 2013-2019, All Rights Reserved
import datetime
import re
from django import forms
import debug # pyflakes:ignore
from ietf.group.models import Group
from ietf.meeting.models import Meeting, Room, TimeSlot, Session, SchedTimeSessAssignment
from ietf.name.models import TimeSlotTypeName
import ietf.utils.fields
# using Django week_day lookup values (Sunday=1)
SESSION_DAYS = ((2,'Monday'),
(3,'Tuesday'),
(4,'Wednesday'),
(5,'Thursday'),
(6,'Friday'))
SESSION_DURATION_RE = re.compile(r'^\d{2}:\d{2}')
#----------------------------------------------------------
# Helper Functions
#----------------------------------------------------------
def get_next_slot(slot):
'''Takes a TimeSlot object and returns the next TimeSlot same day and same room, None if there
aren't any. You must check availability of the slot as we sometimes need to get the next
slot whether it's available or not. For use with combine option.
'''
same_day_slots = TimeSlot.objects.filter(meeting=slot.meeting,location=slot.location,time__day=slot.time.day).order_by('time')
try:
i = list(same_day_slots).index(slot)
return same_day_slots[i+1]
except IndexError:
return None
def get_times(meeting,day):
'''
Takes a Meeting object and an integer representing the week day (sunday=1).
Returns a list of tuples for use in a ChoiceField. The value is start_time,
The label is [start_time]-[end_time].
'''
# pick a random room
rooms = Room.objects.filter(meeting=meeting,session_types='regular')
if rooms:
room = rooms[0]
else:
room = None
slots = TimeSlot.objects.filter(meeting=meeting,time__week_day=day,location=room).order_by('time')
choices = [ (t.time.strftime('%H%M'), '%s-%s' % (t.time.strftime('%H%M'), t.end_time().strftime('%H%M'))) for t in slots ]
return choices
#----------------------------------------------------------
# Base Classes
#----------------------------------------------------------
class BaseMeetingRoomFormSet(forms.models.BaseInlineFormSet):
def clean(self):
'''Check that any rooms marked for deletion are not in use'''
for form in self.deleted_forms:
room = form.cleaned_data['id']
schedtimesessassignments = SchedTimeSessAssignment.objects.filter(timeslot__location=room,
session__isnull=False)
if schedtimesessassignments:
raise forms.ValidationError('Cannot delete meeting room %s. Already assigned to some session.' % room.name)
class TimeSlotModelChoiceField(forms.ModelChoiceField):
'''
Custom ModelChoiceField, changes the label to a more readable format
'''
def label_from_instance(self, obj):
return "%s %s - %s" % (obj.time.strftime('%a %H:%M'),obj.name,obj.location)
class TimeChoiceField(forms.ChoiceField):
'''
We are modifying the time choice field with javascript so the value submitted may not have
been in the initial select list. Just override valid_value validaion.
'''
def valid_value(self, value):
return True
#----------------------------------------------------------
# Forms
#----------------------------------------------------------
class MeetingSelectForm(forms.Form):
meeting = forms.ChoiceField()
def __init__(self,*args,**kwargs):
choices = kwargs.pop('choices')
super(MeetingSelectForm, self).__init__(*args,**kwargs)
self.fields['meeting'].widget.choices = choices
class MeetingModelForm(forms.ModelForm):
idsubmit_cutoff_time_utc = ietf.utils.fields.DurationField()
idsubmit_cutoff_warning_days = ietf.utils.fields.DurationField()
class Meta:
model = Meeting
exclude = ('type', 'schedule', 'session_request_lock_message')
def __init__(self,*args,**kwargs):
super(MeetingModelForm, self).__init__(*args,**kwargs)
if 'instance' in kwargs:
for f in [ 'idsubmit_cutoff_warning_days', 'idsubmit_cutoff_time_utc', ]:
self.fields[f].help_text = kwargs['instance']._meta.get_field(f).help_text
def clean_number(self):
number = self.cleaned_data['number']
if not number.isdigit():
raise forms.ValidationError('Meeting number must be an integer')
return number
def save(self, force_insert=False, force_update=False, commit=True):
meeting = super(MeetingModelForm, self).save(commit=False)
meeting.type_id = 'ietf'
if commit:
meeting.save()
return meeting
class MeetingRoomForm(forms.ModelForm):
class Meta:
model = Room
exclude = ['resources']
class TimeSlotForm(forms.Form):
day = forms.ChoiceField()
time = forms.TimeField()
duration = ietf.utils.fields.DurationField()
name = forms.CharField(help_text='Name that appears on the agenda')
def __init__(self,*args,**kwargs):
if 'meeting' in kwargs:
self.meeting = kwargs.pop('meeting')
super(TimeSlotForm, self).__init__(*args,**kwargs)
self.fields["time"].widget.attrs["placeholder"] = "HH:MM"
self.fields["duration"].widget.attrs["placeholder"] = "HH:MM"
self.fields["day"].choices = self.get_day_choices()
def clean_duration(self):
'''Limit to HH:MM format'''
duration = self.data['duration']
if not SESSION_DURATION_RE.match(duration):
raise forms.ValidationError('{} value has an invalid format. It must be in HH:MM format'.format(duration))
return self.cleaned_data['duration']
def get_day_choices(self):
'''Get day choices for form based on meeting duration'''
choices = []
start = self.meeting.date
for n in range(self.meeting.days):
date = start + datetime.timedelta(days=n)
choices.append((n, date.strftime("%a %b %d")))
return choices
class MiscSessionForm(TimeSlotForm):
short = forms.CharField(max_length=32,label='Short Name',help_text='Enter an abbreviated session name (used for material file names)',required=False)
type = forms.ModelChoiceField(queryset=TimeSlotTypeName.objects.filter(used=True).exclude(slug__in=('regular',)),empty_label=None)
group = forms.ModelChoiceField(
queryset=Group.objects.filter(type__in=['ietf','team'],state='active'),
help_text='''Select a group to associate with this session. For example:<br>
Tutorials = Education,<br>
Code Sprint = Tools Team,<br>
Plenary = IETF''',
required=False)
location = forms.ModelChoiceField(queryset=Room.objects, required=False)
show_location = forms.BooleanField(required=False)
def __init__(self,*args,**kwargs):
if 'meeting' in kwargs:
self.meeting = kwargs.pop('meeting')
if 'session' in kwargs:
self.session = kwargs.pop('session')
super(MiscSessionForm, self).__init__(*args,**kwargs)
self.fields['location'].queryset = Room.objects.filter(meeting=self.meeting)
def clean(self):
super(MiscSessionForm, self).clean()
if any(self.errors):
return
cleaned_data = self.cleaned_data
group = cleaned_data['group']
type = cleaned_data['type']
short = cleaned_data['short']
if type.slug in ('other','plenary','lead') and not group:
raise forms.ValidationError('ERROR: a group selection is required')
if type.slug in ('other','plenary','lead') and not short:
raise forms.ValidationError('ERROR: a short name is required')
return cleaned_data
def clean_group(self):
group = self.cleaned_data['group']
if hasattr(self, 'session') and self.session.group != group and self.session.materials.all():
raise forms.ValidationError("ERROR: can't change group after materials have been uploaded")
return group
class UploadBlueSheetForm(forms.Form):
file = forms.FileField(help_text='example: bluesheets-84-ancp-01.pdf')
def clean_file(self):
file = self.cleaned_data['file']
if not re.match(r'bluesheets-\d+',file.name):
raise forms.ValidationError('Incorrect filename format')
return file
class RegularSessionEditForm(forms.ModelForm):
class Meta:
model = Session
fields = ['agenda_note']