Add full edit capability for non-sessions. Fixes #2235. Commit ready for merge.
- Legacy-Id: 13418
This commit is contained in:
parent
264f6f36e2
commit
930aaccc87
|
@ -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:<br>
|
||||
Tutorials = Education,<br>
|
||||
Code Sprint = Tools Team,<br>
|
||||
Technical Plenary = IAB,<br>
|
||||
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:<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(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')
|
||||
|
||||
|
|
|
@ -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'})
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<th>Show Loc.</th>
|
||||
<th>Type</th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -28,13 +29,10 @@
|
|||
<td>{{ item.name }}</td>
|
||||
<td>{{ item.session.short }}</td>
|
||||
<td>{{ item.session.group.acronym }}</td>
|
||||
{% if item.type.slug != 'break' and item.type.slug != 'registration' %}
|
||||
<td><a href="{% url "ietf.secr.meetings.views.non_session_edit" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">{{ item.location }}</a></td>
|
||||
{% else %}
|
||||
<td>{{ item.location }}</td>
|
||||
{% endif %}
|
||||
<td>{{ item.location }}</td>
|
||||
<td>{{ item.show_location }}</td>
|
||||
<td>{{ item.type }}</td>
|
||||
<td><a href="{% url "ietf.secr.meetings.views.non_session_edit" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">Edit</a></td>
|
||||
<td><a href="{% url "ietf.secr.meetings.views.non_session_delete" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">Delete</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
Loading…
Reference in a new issue