diff --git a/ietf/secr/meetings/forms.py b/ietf/secr/meetings/forms.py index 9f6a5d589..5d15e9893 100644 --- a/ietf/secr/meetings/forms.py +++ b/ietf/secr/meetings/forms.py @@ -166,36 +166,17 @@ class NewSessionForm(forms.Form): return cleaned_data -class NonSessionEditForm(forms.Form): - name = forms.CharField(help_text='Name that appears on the agenda') - short = forms.CharField(max_length=32,label='Short Name',help_text='Enter an abbreviated session name (used for material file names)') - location = forms.ModelChoiceField(queryset=Room.objects) - 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:
- Tutorials = Education,
- Code Sprint = Tools Team,
- Technical Plenary = IAB,
- Administrative Plenary = IAOC or IESG''',empty_label=None) - - def __init__(self,*args,**kwargs): - meeting = kwargs.pop('meeting') - self.session = kwargs.pop('session') - super(NonSessionEditForm, self).__init__(*args,**kwargs) - self.fields['location'].queryset = Room.objects.filter(meeting=meeting) - - def clean_group(self): - group = self.cleaned_data['group'] - if 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 TimeSlotForm(forms.Form): day = forms.ChoiceField(choices=DAYS_CHOICES) time = forms.TimeField() duration = ietf.utils.fields.DurationField() name = forms.CharField(help_text='Name that appears on the agenda') + def __init__(self,*args,**kwargs): + super(TimeSlotForm, self).__init__(*args,**kwargs) + self.fields["time"].widget.attrs["placeholder"] = "HH:MM" + self.fields["duration"].widget.attrs["placeholder"] = "HH:MM" + def clean_duration(self): '''Limit to HH:MM format''' duration = self.data['duration'] @@ -208,14 +189,21 @@ class NonSessionForm(TimeSlotForm): type = forms.ModelChoiceField(queryset=TimeSlotTypeName.objects.filter(used=True).exclude(slug__in=('session',)),empty_label=None) group = forms.ModelChoiceField( queryset=Group.objects.filter(type__in=['ietf','team'],state='active'), - help_text='Required for Session types: other, plenary', + help_text='''Select a group to associate with this session. For example:
+ Tutorials = Education,
+ Code Sprint = Tools Team,
+ 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(NonSessionForm, self).__init__(*args,**kwargs) - self.fields["time"].widget.attrs["placeholder"] = "HH:MM" - self.fields["duration"].widget.attrs["placeholder"] = "HH:MM" + self.fields['location'].queryset = Room.objects.filter(meeting=self.meeting) def clean(self): super(NonSessionForm, self).clean() @@ -225,13 +213,19 @@ class NonSessionForm(TimeSlotForm): group = cleaned_data['group'] type = cleaned_data['type'] short = cleaned_data['short'] - if type.slug in ('other','plenary') and not group: + 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') and not short: + 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') diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py index 46eb53a96..8fc6bb6df 100644 --- a/ietf/secr/meetings/tests.py +++ b/ietf/secr/meetings/tests.py @@ -207,7 +207,15 @@ class SecrMeetingTestCase(TestCase): self.client.login(username="secretary", password="secretary+password") response = self.client.get(url) self.assertEqual(response.status_code, 200) - + response = self.client.post(url, { + 'day': 0, + 'time':'08:00', + 'duration':'01:00', + 'name':'Test Morning Session' + }, follow=True) + self.assertRedirects(response, url) + self.assertTrue('Test Morning Session' in response.content) + def test_meetings_times_delete(self): meeting = make_meeting_test_data() qs = TimeSlot.objects.filter(meeting=meeting,type='session') @@ -266,6 +274,30 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) self.assertTrue('invalid format' in response.content) + def test_meetings_nonsession_edit(self): + meeting = make_meeting_test_data() + session = meeting.session_set.exclude(name='').first() # get first non-session session + timeslot = session.official_timeslotassignment().timeslot + url = reverse('ietf.secr.meetings.views.non_session_edit',kwargs={'meeting_id':42,'schedule_name':meeting.agenda.name,'slot_id':timeslot.pk}) + redirect_url = reverse('ietf.secr.meetings.views.non_session',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) + new_time = timeslot.time + datetime.timedelta(days=1) + self.client.login(username="secretary", password="secretary+password") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + response = self.client.post(url, { + 'name':'IETF Hackathon', + 'short':'hackathon', + 'location':timeslot.location.id, + 'group':session.group.id, + 'time':new_time.strftime('%H:%M'), + 'duration':'01:00', + 'day':'2', + 'type':'other', + }) + self.assertRedirects(response, redirect_url) + timeslot = session.official_timeslotassignment().timeslot + self.assertEqual(timeslot.time,new_time) + def test_meetings_select_group(self): make_meeting_test_data() url = reverse('ietf.secr.meetings.views.select_group',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py index 8b0675481..e20f4ea60 100644 --- a/ietf/secr/meetings/views.py +++ b/ietf/secr/meetings/views.py @@ -15,13 +15,14 @@ from django.utils.functional import curry from ietf.ietfauth.utils import role_required from ietf.utils.mail import send_mail +from ietf.meeting.forms import duration_string from ietf.meeting.helpers import get_meeting, make_materials_directories from ietf.meeting.models import Meeting, Session, Room, TimeSlot, SchedTimeSessAssignment, Schedule from ietf.group.models import Group, GroupEvent from ietf.person.models import Person from ietf.secr.meetings.blue_sheets import create_blue_sheets from ietf.secr.meetings.forms import ( BaseMeetingRoomFormSet, MeetingModelForm, MeetingSelectForm, - MeetingRoomForm, NewSessionForm, NonSessionEditForm, NonSessionForm, TimeSlotForm, + MeetingRoomForm, NewSessionForm, NonSessionForm, TimeSlotForm, UploadBlueSheetForm, get_next_slot ) from ietf.secr.proceedings.views import build_choices from ietf.secr.proceedings.utils import handle_upload_file @@ -459,23 +460,20 @@ def non_session(request, meeting_id, schedule_name): slots = slots.order_by('-type__name','time') if request.method == 'POST': - form = NonSessionForm(request.POST) + form = NonSessionForm(request.POST, meeting=meeting) if form.is_valid(): - day = form.cleaned_data['day'] - time = form.cleaned_data['time'] + time = get_timeslot_time(form, meeting) name = form.cleaned_data['name'] short = form.cleaned_data['short'] type = form.cleaned_data['type'] group = form.cleaned_data['group'] duration = form.cleaned_data['duration'] - t = meeting.date + datetime.timedelta(days=int(day)) - new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute) # create TimeSlot object timeslot = TimeSlot.objects.create(type=type, meeting=meeting, name=name, - time=new_time, + time=time, duration=duration, show_location=form.cleaned_data['show_location']) @@ -501,7 +499,7 @@ def non_session(request, meeting_id, schedule_name): messages.success(request, 'Non-Sessions updated successfully') return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name) else: - form = NonSessionForm(initial={'show_location':True}) + form = NonSessionForm(initial={'show_location':True}, meeting=meeting) if TimeSlot.objects.filter(meeting=meeting,type='other',location__isnull=True): messages.warning(request, 'There are non-session items which do not have a room assigned') @@ -552,14 +550,22 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id): if button_text == 'Cancel': return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name) - form = NonSessionEditForm(request.POST,meeting=meeting, session=session) + form = NonSessionForm(request.POST,meeting=meeting,session=session) if form.is_valid(): location = form.cleaned_data['location'] group = form.cleaned_data['group'] name = form.cleaned_data['name'] short = form.cleaned_data['short'] + duration = form.cleaned_data['duration'] + slot_type = form.cleaned_data['type'] + show_location = form.cleaned_data['show_location'] + time = get_timeslot_time(form, meeting) slot.location = location slot.name = name + slot.time = time + slot.duration = duration + slot.type = slot_type + slot.show_location = show_location slot.save() # save group to session object session.group = group @@ -573,11 +579,17 @@ def non_session_edit(request, meeting_id, schedule_name, slot_id): else: # we need to pass the session to the form in order to disallow changing # of group after materials have been uploaded + delta = slot.time.date() - meeting.date initial = {'location':slot.location, 'group':session.group, 'name':session.name, - 'short':session.short} - form = NonSessionEditForm(meeting=meeting,session=session,initial=initial) + 'short':session.short, + 'day':delta.days, + 'time':slot.time.strftime('%H:%M'), + 'duration':duration_string(slot.duration), + 'show_location':slot.show_location, + 'type':slot.type} + form = NonSessionForm(initial=initial, meeting=meeting, session=session) return render(request, 'meetings/non_session_edit.html', { 'meeting': meeting, @@ -889,25 +901,21 @@ def times(request, meeting_id, schedule_name): if request.method == 'POST': form = TimeSlotForm(request.POST) if form.is_valid(): - day = form.cleaned_data['day'] - time = form.cleaned_data['time'] + time = get_timeslot_time(form, meeting) duration = form.cleaned_data['duration'] name = form.cleaned_data['name'] - t = meeting.date + datetime.timedelta(days=int(day)) - new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute) - # don't allow creation of timeslots with same start time as existing timeslots # assert False, (new_time, time_seen) - if new_time in time_seen: - messages.error(request, 'There is already a timeslot for %s. To change you must delete the old one first.' % new_time.strftime('%a %H:%M')) + if time in time_seen: + messages.error(request, 'There is already a timeslot for %s. To change you must delete the old one first.' % time.strftime('%a %H:%M')) return redirect('ietf.secr.meetings.views.times', meeting_id=meeting_id,schedule_name=schedule_name) for room in meeting.room_set.all(): TimeSlot.objects.create(type_id='session', meeting=meeting, name=name, - time=new_time, + time=time, location=room, duration=duration) @@ -924,6 +932,14 @@ def times(request, meeting_id, schedule_name): 'times': times}, ) +def get_timeslot_time(form, meeting): + '''Returns datetime calculated from day and time form fields''' + time = form.cleaned_data['time'] + day = form.cleaned_data['day'] + + date = meeting.date + datetime.timedelta(days=int(day)) + return datetime.datetime(date.year,date.month,date.day,time.hour,time.minute) + @role_required('Secretariat') def times_edit(request, meeting_id, schedule_name, time): ''' @@ -944,15 +960,12 @@ def times_edit(request, meeting_id, schedule_name, time): form = TimeSlotForm(request.POST) if form.is_valid(): day = form.cleaned_data['day'] - time = form.cleaned_data['time'] + time = get_timeslot_time(form, meeting) duration = form.cleaned_data['duration'] name = form.cleaned_data['name'] - t = meeting.date + datetime.timedelta(days=int(day)) - new_time = datetime.datetime(t.year,t.month,t.day,time.hour,time.minute) - for timeslot in timeslots: - timeslot.time = new_time + timeslot.time = time timeslot.duration = duration timeslot.name = name timeslot.save() diff --git a/ietf/secr/templates/meetings/non_session.html b/ietf/secr/templates/meetings/non_session.html index cae8c1979..69b499226 100644 --- a/ietf/secr/templates/meetings/non_session.html +++ b/ietf/secr/templates/meetings/non_session.html @@ -18,6 +18,7 @@ Show Loc. Type + @@ -28,13 +29,10 @@ {{ item.name }} {{ item.session.short }} {{ item.session.group.acronym }} - {% if item.type.slug != 'break' and item.type.slug != 'registration' %} - {{ item.location }} - {% else %} - {{ item.location }} - {% endif %} + {{ item.location }} {{ item.show_location }} {{ item.type }} + Edit Delete {% endfor %}