diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py index 0f6581176..d5b75bcf9 100644 --- a/ietf/meeting/helpers.py +++ b/ietf/meeting/helpers.py @@ -67,6 +67,9 @@ def build_all_agenda_slices(meeting): date_slices = {} for ts in meeting.timeslot_set.exclude(type__in=['reg','break']).order_by('time','name'): + #for ts in meeting.timeslot_set.exclude(type__in=['reg','break','other']).order_by('time','name'): + #for ts in meeting.timeslot_set.order_by('time','name'): + #for ts in meeting.timeslot_set.filter(type='offagenda').order_by('time','name'): ymd = ts.time.date() if ymd not in date_slices and ts.location != None: diff --git a/ietf/meeting/migrations/0005_auto_20150318_1116.py b/ietf/meeting/migrations/0005_auto_20150318_1116.py new file mode 100644 index 000000000..1068f49df --- /dev/null +++ b/ietf/meeting/migrations/0005_auto_20150318_1116.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import datetime +from django.db import migrations + + +def backfill_91_other_meetings(apps, schema_editor): + + Meeting = apps.get_model('meeting', 'Meeting') + Schedule = apps.get_model('meeting', 'Schedule') + ScheduledSession = apps.get_model('meeting', 'ScheduledSession') + Room = apps.get_model('meeting', 'Room') + Group = apps.get_model('group', 'Group') + Person = apps.get_model('person', 'Person') + + ietf91 = Meeting.objects.filter(number=91).first() + + if not ietf91: + print "IETF91 not found, no data changed" + else: + agenda91 = Schedule.objects.get(meeting=ietf91,pk=ietf91.agenda.pk) + + south_pacific_1 = Room.objects.get(meeting=ietf91,name="South Pacific 1") + south_pacific_2 = Room.objects.get(meeting=ietf91,name="South Pacific 2") + rainbow_12 = Room.objects.get(meeting=ietf91,name="Rainbow Suite 1/2") + lehua_suite = Room.objects.get(meeting=ietf91,name="Lehua Suite") + kahili = Room.objects.get(meeting=ietf91,name="Kahili") + coral_2 = Room.objects.get(meeting=ietf91,name="Coral 2") + + south_pacific_3 = Room.objects.create(meeting=ietf91,name="South Pacific 3",capacity=20) + rainbow_suite_3 = Room.objects.create(meeting=ietf91,name="Rainbow Suite 3",capacity=20) + rainbow_23 = Room.objects.create(meeting=ietf91,name="Rainbow Suite 2/3",capacity=210) + south_pacific_34 = Room.objects.create(meeting=ietf91,name="South Pacific 3/4",capacity=210) + iolani_67 = Room.objects.create(meeting=ietf91,name="Iolani 6/7",capacity=40) + sea_pearl_12 = Room.objects.create(meeting=ietf91,name="Sea Pearl 1/2",capacity=40) + sea_pearl_2 = Room.objects.create(meeting=ietf91,name="Sea Pearl 2",capacity=20) + coral_lounge = Room.objects.create(meeting=ietf91,name="Coral Lounge", capacity=1200) + hibiscus = Room.objects.create(meeting=ietf91,name="Hibiscus", capacity=20) + tiare = Room.objects.create(meeting=ietf91,name="Tiare Suite", capacity=20) + + iesg = Group.objects.get(acronym='iesg') + iab = Group.objects.get(acronym='iab') + rsoc = Group.objects.get(acronym='rsoc') + iaoc = Group.objects.get(acronym='iaoc') + nomcom = Group.objects.get(acronym='nomcom2014') + isoc = Group.objects.get(acronym='isoc') + secr = Group.objects.get(acronym='secretariat') + isocbot = Group.objects.create(acronym='isocbot',name="Internet Society Board of Trustees",state_id='active',type_id='isoc',parent=isoc) + isocfell = Group.objects.create(acronym='isocfell',name="Internet Society Fellows",state_id='active',type_id='isoc',parent=isoc) + + system = Person.objects.get(name='(System)') + + for d, h, m, duration, type_id, groups, room, slotname, label in [ + ( 9, 8, 0, 120, 'offagenda', [secr], rainbow_suite_3, 'WEIRDS Interop', 'WEIRDS Interop'), + ( 9, 8, 30, 90, 'lead', [iesg], south_pacific_2, 'Breakfast', None), + ( 9, 9, 0, 240, 'offagenda', [secr], lehua_suite, 'RMCAT Interim', 'RMCAT Interim Meeting'), + ( 9, 9, 0, 60, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 9, 9, 0, 150, 'lead', [iesg], south_pacific_2, 'Meeting', None), + ( 9, 9, 0, 360, 'offagenda', [secr], hibiscus, 'Meeting', 'RootOPS'), + ( 9, 9, 30, 360, 'offagenda', [secr], kahili, 'TLS Interim', 'TLS WG Interim'), + ( 9, 11, 0, 480, 'offagenda', [secr], coral_lounge, 'T-Shirt Distribution', 'T-shirt Distribution'), + ( 9, 11, 30, 150, 'lead', [iesg,iab], south_pacific_2, 'Lunch', 'IAB/IESG Lunch'), + ( 9, 12, 0, 360, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 9, 14, 0, 180, 'lead', [iab], south_pacific_2, 'Meeting', None), + ( 9, 16, 0, 120, 'offagenda', [secr], coral_2, 'Meeting', 'Web Object Encryption'), + ( 9, 17, 0, 120, 'offagenda', [secr], sea_pearl_12, 'Reception', "Companion's Reception"), # Should this appear on agenda? + ( 9, 19, 0, 180, 'offagenda', [isocfell], rainbow_23, 'Dinner', 'ISOC Fellows Reception/Dinner'), + ( 9, 19, 0, 180, 'offagenda', [secr], lehua_suite, 'Meeting', 'Huawei'), + ( 9, 21, 0, 180, 'lead', [secr], sea_pearl_12, 'Gathering', 'AMS/IESG/IABIAOC Gathering'), + ( 10, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 10, 7, 0, 120, 'lead', [iesg,iab], south_pacific_2, 'Breakfast', 'IESG/IAB Breakfast'), + ( 10, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 10, 8, 0, 600, 'offagenda', [secr], coral_lounge, 'T-shirt Distribution', 'T-shirt Distribution'), + ( 10, 11, 30, 90, 'offagenda', [secr], south_pacific_2, 'Meeting', 'OPS Directorate Meeting'), + ( 10, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Meeting', 'IETF/3GPP Meeting'), + ( 10, 11, 30, 90, 'offagenda', [secr], lehua_suite, 'Meeting', 'RTG Area Meeting'), + ( 10, 19, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'Huawei'), + ( 11, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 11, 7, 0, 120, 'lead', [iesg], south_pacific_2, 'Breakfast', None), + ( 11, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 11, 7, 0, 120, 'lead', [iab], rainbow_suite_3, 'Breakfast', None), + ( 11, 7, 0, 60, 'lead', [iab], tiare, 'Meeting', 'Vendor Selection Committee Meeting'), + ( 11, 8, 0, 600, 'offagenda', [secr], coral_lounge, 'T-shirt Distribution', 'T-shirt Distribution'), + ( 11, 9, 0, 90, 'offagenda', [secr], south_pacific_2, 'Meeting', 'DHCPv6bis Team Meeting'), + ( 11, 11, 30, 90, 'offagenda', [secr], south_pacific_2, 'Meeting', 'SECdir Meeting'), + ( 11, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Lunch', 'RSAG/ISEB Lunch'), + ( 11, 16, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'Verisign Corporate Meeting'), + ( 12, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 12, 7, 30, 90, 'lead', [iaoc], south_pacific_3, 'Breakfast', None), + ( 12, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 12, 8, 0, 540, 'offagenda', [secr], coral_lounge, 'T-shirt Distribution', 'T-shirt Distribution'), + ( 12, 8, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'DIME WG'), + ( 12, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Lunch', 'RFC Editor Lunch'), + ( 12, 15, 0, 120, 'offagenda', [secr], south_pacific_2, 'Meeting', 'YANG Advice'), + ( 12, 17, 0, 240, 'offagenda', [secr], rainbow_suite_3, 'Meeting', 'Huawei (POC Wil Liu)'), + ( 12, 20, 0, 150, 'offagenda', [secr], south_pacific_2, 'Meeting', 'ICANN SSAC'), + ( 13, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 13, 7, 0, 120, 'lead', [iab], rainbow_suite_3, 'Breakfast', None), + ( 13, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 13, 11, 30, 90, 'lead', [iab], sea_pearl_2, 'Meeting', 'IAB Liaison Oversight'), + ( 13, 11, 30, 90, 'lead', [rsoc], rainbow_suite_3, 'Lunch', None), + ( 14, 0, 0, 900, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'), + ( 14, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'), + ( 14, 11, 0, 360, 'offagenda', [isoc], south_pacific_34,'Meeeting', 'ISOC AC Meeting'), + ( 14, 13, 30, 90, 'lead', [iesg,iab], south_pacific_2, 'Lunch', 'IESG/IAB Lunch'), + ( 14, 18, 0, 60, 'offagenda', [isocbot], rainbow_23, 'Reception', 'ISOC Board Reception for IETF Leadership'), + ( 14, 19, 0, 180, 'offagenda', [isocbot], rainbow_23, 'Dinner', 'ISOC Board Dinner for IETF Leadership'), + ( 15, 8, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Breakfast', 'ISOC Board of Trustees Breakfast'), + ( 15, 8, 0, 540, 'offagenda', [isocbot], south_pacific_34,'Meeting', 'ISOC Board of Trustees Meeting'), + ( 15, 12, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Lunch', 'ISOC Board of Trustees Lunch'), + ( 16, 8, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Breakfast', 'ISOC Board of Trustees Breakfast'), + ( 16, 8, 0, 540, 'offagenda', [isocbot], south_pacific_34,'Meeting', 'ISOC Board of Trustees Meeting'), + ( 16, 12, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Lunch', 'ISOC Board of Trustees Lunch'), + ]: + ts = ietf91.timeslot_set.create(type_id=type_id, name=slotname, + time=datetime.datetime(2014,11,d,h,m,0), + duration=datetime.timedelta(minutes=duration), + location=room,show_location=(type_id not in ['lead','offagenda'])) + for group in groups: + session = ietf91.session_set.create(name= label or "%s %s"%(group.acronym.upper(),slotname), + group=group, attendees=25, + requested=datetime.datetime(2014,11,1,0,0,0), + requested_by=system, status_id='sched') + ScheduledSession.objects.create(schedule=agenda91, timeslot=ts, session=session) + + + + +class Migration(migrations.Migration): + + dependencies = [ + ('meeting', '0004_auto_20150308_0446'), + ('name', '0004_auto_20150318_1140'), + ('group', '0003_auto_20150304_0743'), + ('person', '0004_auto_20150308_0440'), + ] + + operations = [ + migrations.RunPython(backfill_91_other_meetings) + ] diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py index 23e7cc855..bfd3a2f78 100644 --- a/ietf/meeting/models.py +++ b/ietf/meeting/models.py @@ -370,7 +370,7 @@ class TimeSlot(models.Model): return u"%s: %s-%s %s, %s" % (self.meeting.number, self.time.strftime("%m-%d %H:%M"), (self.time + self.duration).strftime("%H:%M"), self.name, location) def end_time(self): return self.time + self.duration - def get_location(self): + def get_hidden_location(self): location = self.location if location: location = location.name @@ -378,6 +378,10 @@ class TimeSlot(models.Model): location = self.meeting.reg_area elif self.type_id == "break": location = self.meeting.break_area + return location + + def get_location(self): + location = self.get_hidden_location() if not self.show_location: location = "" return location @@ -626,8 +630,7 @@ class Schedule(models.Model): .distinct() ) def groups(self): - return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], parent__isnull=False, - session__scheduledsession__schedule=self).distinct().order_by('parent__acronym', 'acronym') + return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], parent__isnull=False, session__scheduledsession__schedule=self).exclude(session__scheduledsession__timeslot__type__in=['lead','offagenda']).distinct().order_by('parent__acronym', 'acronym') # calculate badness of entire schedule def calc_badness(self): diff --git a/ietf/meeting/test_data.py b/ietf/meeting/test_data.py index 997d2e4bf..a3879fab8 100644 --- a/ietf/meeting/test_data.py +++ b/ietf/meeting/test_data.py @@ -20,6 +20,7 @@ def make_meeting_test_data(): pname = RoomResourceName.objects.create(name='projector',slug='proj') projector = ResourceAssociation.objects.create(name=pname,icon="notfound.png",desc="Basic projector") room = Room.objects.create(meeting=meeting, name="Test Room", capacity=123) + breakfast_room = Room.objects.create(meeting=meeting, name="Breakfast Room", capacity=40) room.resources = [projector] # mars WG @@ -42,6 +43,17 @@ def make_meeting_test_data(): scheduled=datetime.datetime.now()) ScheduledSession.objects.create(timeslot=slot, session=ames_session, schedule=schedule) + # IESG breakfast + breakfast_slot = TimeSlot.objects.create(meeting=meeting, type_id="lead", duration=90 * 60, + location=breakfast_room, + time=datetime.datetime.combine(datetime.date.today(),datetime.time(7,0))) + iesg_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="iesg"), + name="IESG Breakfast", + attendees=25, requested_by=system_person, + requested_duration=20, status_id="schedw", + scheduled=datetime.datetime.now()) + ScheduledSession.objects.create(timeslot=breakfast_slot, session=iesg_session, schedule=schedule) + meeting.agenda = schedule meeting.save() diff --git a/ietf/meeting/tests_api.py b/ietf/meeting/tests_api.py index 489fa8a90..6d6def084 100644 --- a/ietf/meeting/tests_api.py +++ b/ietf/meeting/tests_api.py @@ -152,7 +152,10 @@ class ApiTests(TestCase): self.assertTrue(meeting.room_set.filter(name="new room")) timeslots_after = meeting.timeslot_set.count() - self.assertEqual((timeslots_after - timeslots_before), (meeting.room_set.count() - 1) * timeslots_before) + # It's not clear that what that ajax function is doing is the right thing to do, + # but it currently makes a new timeslot for any existing timeslot. + # The condition tested below relies on the timeslots before this test all having different start and end times + self.assertEqual( timeslots_after, 2 * timeslots_before) def test_delete_room(self): meeting = make_meeting_test_data() @@ -201,7 +204,7 @@ class ApiTests(TestCase): r = self.client.get(url) self.assertEqual(r.status_code, 200) info = json.loads(r.content) - self.assertEqual(set([x['short_name'] for x in info]),set(['mars','ames'])) + self.assertEqual(set([x['short_name'] for x in info]),set([s.session.short_name for s in meeting.agenda.scheduledsession_set.all()])) schedule = meeting.agenda url = urlreverse("ietf.meeting.ajax.scheduledsessions_json", @@ -209,7 +212,7 @@ class ApiTests(TestCase): r = self.client.get(url) self.assertEqual(r.status_code, 200) info = json.loads(r.content) - self.assertEqual(len(info),2) + self.assertEqual(len(info),schedule.scheduledsession_set.count()) def test_slot_json(self): diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py index f849499fa..a1db83d9a 100644 --- a/ietf/meeting/tests_views.py +++ b/ietf/meeting/tests_views.py @@ -11,7 +11,7 @@ from pyquery import PyQuery from ietf.doc.models import Document from ietf.meeting.models import Session, TimeSlot from ietf.meeting.test_data import make_meeting_test_data -from ietf.utils.test_utils import TestCase +from ietf.utils.test_utils import TestCase, login_testing_unauthorized class MeetingTests(TestCase): def setUp(self): @@ -124,6 +124,13 @@ class MeetingTests(TestCase): self.assertTrue(session.group.acronym in agenda_content) self.assertTrue(slot.location.name in agenda_content) + def test_agenda_by_room(self): + meeting = make_meeting_test_data() + url = urlreverse("ietf.meeting.views.agenda_by_room",kwargs=dict(num=meeting.number)) + login_testing_unauthorized(self,"secretary",url) + r = self.client.get(url,kwargs=dict(num=meeting.number)) + self.assertTrue(all([x in r.content for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']])) + def test_materials(self): meeting = make_meeting_test_data() session = Session.objects.filter(meeting=meeting, group__acronym="mars").first() diff --git a/ietf/meeting/urls.py b/ietf/meeting/urls.py index 424a57aa8..429f8d723 100644 --- a/ietf/meeting/urls.py +++ b/ietf/meeting/urls.py @@ -33,6 +33,7 @@ urlpatterns = patterns('', (r'^(?P\d+)/agenda(?P.txt)$', views.agenda), (r'^(?P\d+)/agenda.ics$', views.ical_agenda), (r'^(?P\d+)/agenda(?P.csv)$', views.agenda), + (r'^(?P\d+)/agenda/by-room$', views.agenda_by_room), (r'^(?P\d+)/agendas/edit$', views.edit_agendas), (r'^(?P\d+)/timeslots/edit$', views.edit_timeslots), (r'^(?P\d+)/rooms$', ajax.timeslot_roomsurl), diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py index fd4de3a45..05d450219 100644 --- a/ietf/meeting/views.py +++ b/ietf/meeting/views.py @@ -6,6 +6,7 @@ import re import tarfile import urllib from tempfile import mkstemp +from collections import OrderedDict import debug # pyflakes:ignore @@ -367,6 +368,7 @@ def edit_agendas(request, num=None, order=None): def agenda(request, num=None, name=None, base=None, ext=None): base = base if base else 'agenda' ext = ext if ext else '.html' + # This is misleading - urls.py doesn't send ics through here anymore mimetype = { ".html":"text/html; charset=%s"%settings.DEFAULT_CHARSET, ".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET, @@ -380,7 +382,22 @@ def agenda(request, num=None, name=None, base=None, ext=None): return render(request, "meeting/no-"+base+ext, {'meeting':meeting }, content_type=mimetype[ext]) updated = meeting_updated(meeting) - return render(request, "meeting/"+base+ext, {"schedule":schedule, "updated": updated}, content_type=mimetype[ext]) + filtered_assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda']) + return render(request, "meeting/"+base+ext, {"schedule":schedule, "filtered_assignments":filtered_assignments, "updated": updated}, content_type=mimetype[ext]) + +#TODO - let the IAB in +@role_required('Area Director','Secretariat') +@ensure_csrf_cookie +def agenda_by_room(request,num=None): + meeting = get_meeting(num) + schedule = get_schedule(meeting) + ss_by_day = OrderedDict() + for day in schedule.scheduledsession_set.dates('timeslot__time','day'): + ss_by_day[day]=[] + for ss in schedule.scheduledsession_set.order_by('timeslot__location','timeslot__time'): + day = ss.timeslot.time.date() + ss_by_day[day].append(ss) + return render(request,"meeting/agenda_by_room.html",{"meeting":meeting,"ss_by_day":ss_by_day}) def read_agenda_file(num, doc): # XXXX FIXME: the path fragment in the code below should be moved to @@ -611,7 +628,7 @@ def ical_agenda(request, num=None, name=None, ext=None): elif item[0] == '~': include_types |= set([item[1:]]) - assignments = schedule.assignments.filter( + assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda']).filter( Q(timeslot__type__slug__in = include_types) | Q(session__group__acronym__in = include) | Q(session__group__parent__acronym__in = include) diff --git a/ietf/name/fixtures/names.json b/ietf/name/fixtures/names.json index f6dc6373c..8aad8add6 100644 --- a/ietf/name/fixtures/names.json +++ b/ietf/name/fixtures/names.json @@ -1414,7 +1414,7 @@ "order": 0, "used": true, "name": "None Selected", - "desc": "" + "desc": "[None selected]" }, "model": "name.iprlicensetypename", "pk": "none-selected" @@ -2079,6 +2079,26 @@ "model": "name.timeslottypename", "pk": "reserved" }, +{ + "fields": { + "order": 0, + "used": true, + "name": "Leadership", + "desc": "Leadership Meetings" + }, + "model": "name.timeslottypename", + "pk": "lead" +}, +{ + "fields": { + "order": 0, + "used": true, + "name": "Off Agenda", + "desc": "Other Meetings Not Published on Agenda" + }, + "model": "name.timeslottypename", + "pk": "offagenda" +}, { "fields": { "label": "State" diff --git a/ietf/name/migrations/0004_auto_20150318_1140.py b/ietf/name/migrations/0004_auto_20150318_1140.py new file mode 100644 index 000000000..c4274b886 --- /dev/null +++ b/ietf/name/migrations/0004_auto_20150318_1140.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations + + + + +def make_new_slot_types(apps, schema_editor): + + TimeSlotTypeName = apps.get_model("name","TimeSlotTypeName") + TimeSlotTypeName.objects.create(slug='lead',name='Leadership',desc='Leadership Meetings',used=True) + TimeSlotTypeName.objects.create(slug='offagenda',name='Off Agenda',desc='Other Meetings Not Published on Agenda',used=True) + +class Migration(migrations.Migration): + + dependencies = [ + ('name', '0003_fix_ipr_none_selected_choice'), + ] + + operations = [ + migrations.RunPython(make_new_slot_types) + ] diff --git a/ietf/secr/meetings/forms.py b/ietf/secr/meetings/forms.py index d3ee39e2e..1954fa93c 100644 --- a/ietf/secr/meetings/forms.py +++ b/ietf/secr/meetings/forms.py @@ -180,6 +180,7 @@ class TimeSlotForm(forms.Form): class NonSessionForm(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(slug__in=('other','reg','break','plenary')),empty_label=None) + type = forms.ModelChoiceField(queryset=TimeSlotTypeName.objects.filter(used=True).exclude(slug__in=('session',)),empty_label=None) group = forms.ModelChoiceField(queryset=Group.objects.filter(acronym__in=('edu','ietf','iepg','tools','iesg','iab','iaoc')),help_text='Required for Session types: other, plenary',required=False) show_location = forms.BooleanField(required=False) diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py index ddba8a2e5..ad9a1eb3f 100644 --- a/ietf/secr/meetings/tests.py +++ b/ietf/secr/meetings/tests.py @@ -147,21 +147,21 @@ class MainTestCase(TestCase): response = self.client.get(url) self.assertEqual(response.status_code, 200) q = PyQuery(response.content) - self.assertEqual(len(q("#id_rooms_table tr")),2) + self.assertEqual(len(q("#id_rooms_table tr input[type='text']")),meeting.room_set.count()) # test delete # first unschedule sessions so we can delete ScheduledSession.objects.filter(schedule=meeting.agenda).delete() self.client.login(username="secretary", password="secretary+password") - response = self.client.post(url, { + post_dict = { 'room-TOTAL_FORMS': q('input[name="room-TOTAL_FORMS"]').val(), 'room-INITIAL_FORMS': q('input[name="room-INITIAL_FORMS"]').val(), - 'room-0-meeting': q('input[name="room-0-meeting"]').val(), - 'room-0-id': q('input[name="room-0-id"]').val(), - 'room-0-name': q('input[name="room-0-name"]').val(), - 'room-0-capacity': q('input[name="room-0-capacity"]').val(), - 'room-0-DELETE': 'on' - }) + } + for i in range(meeting.room_set.count()): + for attr in ['meeting','id','name','capacity','DELETE']: + key = 'room-%d-%s' % (i,attr) + post_dict[key] = q('input[name="%s"]' % key).val() + response = self.client.post(url, post_dict) self.assertEqual(response.status_code, 302) self.assertEqual(Room.objects.filter(meeting=meeting).count(),0) @@ -176,6 +176,7 @@ class MainTestCase(TestCase): meeting = make_meeting_test_data() qs = TimeSlot.objects.filter(meeting=meeting,type='session') before = qs.count() + expected_deletion_count = qs.filter(time=qs.first().time).count() url = reverse('meetings_times_delete',kwargs={ 'meeting_id':42, 'schedule_name':'test-agenda', @@ -185,7 +186,7 @@ class MainTestCase(TestCase): response = self.client.get(url) self.assertEqual(response.status_code, 302) after = TimeSlot.objects.filter(meeting=meeting,type='session').count() - self.assertEqual(after,before - (Room.objects.filter(meeting=meeting).count())) + self.assertEqual(after,before - expected_deletion_count) def test_meetings_times_edit(self): meeting = make_meeting_test_data() diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py index 1b2e7eed9..7985bfc23 100644 --- a/ietf/secr/meetings/views.py +++ b/ietf/secr/meetings/views.py @@ -95,7 +95,7 @@ def build_nonsession(meeting,schedule): system = Person.objects.get(name='(system)') secretariat = Group.objects.get(acronym='secretariat') - for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary')): + for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary','lead')): new_time = slot.time + delta session = None # create Session object for Tutorials to hold materials @@ -128,15 +128,17 @@ def check_nonsession(meeting,schedule): Ensure non-session timeslots exist and have appropriate ScheduledSession objects for the specified schedule. ''' - slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')) + slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary','lead','offagenda')) if not slots: build_nonsession(meeting,schedule) return None - scheduledsessions = slots.filter(type='plenary').first().scheduledsession_set.all() - if not scheduledsessions.filter(schedule=schedule): - source = scheduledsessions.first().schedule - copy_scheduledsessions(slots,source,schedule) + plenary = slots.filter(type='plenary').first() + if plenary: + scheduledsessions = plenary.scheduledsession_set.all() + if not scheduledsessions.filter(schedule=schedule): + source = scheduledsessions.first().schedule + copy_scheduledsessions(slots,source,schedule) def copy_scheduledsessions(slots,source,target): ''' @@ -435,7 +437,7 @@ def non_session(request, meeting_id, schedule_name): check_nonsession(meeting,schedule) - slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')).order_by('-type__name','time') + slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary','lead')).order_by('-type__name','time') if request.method == 'POST': form = NonSessionForm(request.POST) @@ -458,7 +460,7 @@ def non_session(request, meeting_id, schedule_name): duration=duration, show_location=form.cleaned_data['show_location']) - if timeslot.type.slug not in ('other','plenary'): + if timeslot.type.slug not in ('other','plenary','lead'): group = Group.objects.get(acronym='secretariat') # create associated Session object @@ -501,7 +503,7 @@ def non_session_delete(request, meeting_id, schedule_name, slot_id): meeting = get_object_or_404(Meeting, number=meeting_id) # schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) slot = get_object_or_404(TimeSlot, id=slot_id) - if slot.type_id in ('other','plenary'): + if slot.type_id in ('other','plenary','lead'): scheduledsessions = slot.scheduledsession_set.filter(schedule__meeting=meeting) session_objects = [ x.session for x in scheduledsessions ] for session in session_objects: diff --git a/ietf/templates/meeting/agenda.csv b/ietf/templates/meeting/agenda.csv index c1563f6bc..537a97ace 100644 --- a/ietf/templates/meeting/agenda.csv +++ b/ietf/templates/meeting/agenda.csv @@ -1,7 +1,7 @@ {% load humanize %}{% autoescape off %}{% load ietf_filters %}"Date","Start","End","Session","Room","Area","Acronym","Type","Description","Session ID","Agenda","Slides" -{% for item in schedule.assignments.all.distinct %}{% if item.timeslot.type.slug == "break" %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","Break","{{ schedule.meeting.break_area}}","","","","{{ item.timeslot.name }}","b{{ item.timeslot.pk }}","","" +{% for item in filtered_assignments.all.distinct %}{% if item.timeslot.type.slug == "break" %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","Break","{{ schedule.meeting.break_area}}","","","","{{ item.timeslot.name }}","b{{ item.timeslot.pk }}","","" {% endif %}{% if item.timeslot.type.slug == "reg" %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","{{ item.timeslot.type.name }}","{{ schedule.meeting.reg_area }}","","","","{{ item.timeslot.name }}","r{{item.timeslot.pk}}","","" {% endif %}{% if item.timeslot.type.slug == "other" %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","None","{{ item.timeslot.location.name }}","","{{ item.session.group.acronym }}","{% if item.session.group.parent %}{{item.session.group.parent.acronym|upper}}{% endif %}","{{ item.session.name }}","{{item.session.pk}}","","" {% endif %}{% if item.timeslot.type.slug == "plenary" %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","{{ item.session.name }}","{{ item.timeslot.location.name }}","","{{ item.session.group.acronym }}","","{{ item.session.name }}","{{item.session.pk}}","{% if item.session.agenda %}http://www.ietf.org/proceedings/{{ schedule.meeting.number }}/agenda/{{ item.session.agenda.external_url }}{% endif %}","{% if item.session.slides %}{% for slide in item.session.slides %}http://www.ietf.org/proceedings/{{ schedule.meeting.number }}/slides/{{ slide.external_url }}{% if not forloop.last %}|{% endif %}{% endfor %}{% endif %}" {% endif %}{% if item.timeslot.type.slug == "session" and item.session.group %}"{{ item.timeslot.time|date:"Y-m-d" }}","{{ item.timeslot.time_desc|slice:":4" }}","{{ item.timeslot.time_desc|slice:"5:9" }}","{{ item.timeslot.name }}","{{ item.timeslot.location.name }}","{{ item.session.group.parent.acronym|upper }}","{{ item.session.group.acronym }}","{{ item.session.type }}","{{ item.session.group.name }}","{{ item.session.pk}}","{% if item.session.agenda %}http://www.ietf.org/proceedings/{{ schedule.meeting.number }}/agenda/{{ item.session.agenda.external_url }}{% endif %}","{% if item.session.slides %}{% for slide in item.session.slides %}http://www.ietf.org/proceedings/{{ schedule.meeting.number }}/slides/{{ slide.external_url }}{% if not forloop.last %}|{% endif %}{% endfor %}{% endif %}" -{% endif %}{% endfor %}{% endautoescape %} \ No newline at end of file +{% endif %}{% endfor %}{% endautoescape %} diff --git a/ietf/templates/meeting/agenda.html b/ietf/templates/meeting/agenda.html index 1983ae1d0..95bb014a4 100644 --- a/ietf/templates/meeting/agenda.html +++ b/ietf/templates/meeting/agenda.html @@ -146,7 +146,7 @@ - {% for item in schedule.assignments.all %} + {% for item in filtered_assignments.all %} {% ifchanged item.timeslot.time|date:"Y-m-d" %} @@ -335,7 +335,7 @@
"+ this.visible_title()+ - " ("+this.requested_duration+")" + + "" + durationstring + "" + ""+pinned+"
"+ area_mark +""; };