From 8686fd2a4e9e390e02fd0fb2990d5c780d1dd9e9 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Fri, 23 Jan 2015 17:31:04 +0000
Subject: [PATCH 01/15] simple display fix, already in trunk  - Legacy-Id: 8902

---
 ietf/meeting/models.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index 1fdd1c238..1f209676b 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -240,7 +240,7 @@ class Room(models.Model):
     resources = models.ManyToManyField(ResourceAssociation, blank = True)
 
     def __unicode__(self):
-        return "%s size: %u" % (self.name, self.capacity)
+        return "%s size: %s" % (self.name, self.capacity)
 
     def delete_timeslots(self):
         for ts in self.timeslot_set.all():

From 47901e8555a796a0f89fe8959bebaab2c21e3d85 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Tue, 27 Jan 2015 19:15:25 +0000
Subject: [PATCH 02/15] Checkpoint: by-room view and basic leadership meetings
 support  - Legacy-Id: 8930

---
 ietf/meeting/helpers.py     |  2 ++
 ietf/meeting/models.py      |  6 +++++-
 ietf/meeting/test_data.py   | 12 ++++++++++++
 ietf/meeting/tests_views.py |  9 ++++++++-
 ietf/meeting/urls.py        |  1 +
 ietf/meeting/views.py       | 15 +++++++++++++++
 6 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py
index 12e82b857..5e25d12b0 100644
--- a/ietf/meeting/helpers.py
+++ b/ietf/meeting/helpers.py
@@ -67,6 +67,8 @@ 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'):
             ymd = ts.time.date()
 
             if ymd not in date_slices and ts.location != None:
diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index 1f209676b..bdde2ebfd 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -322,7 +322,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
@@ -330,6 +330,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
diff --git a/ietf/meeting/test_data.py b/ietf/meeting/test_data.py
index e7a877f76..c4eaa2fc1 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
@@ -41,6 +42,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_views.py b/ietf/meeting/tests_views.py
index 736c18ff4..afe82785e 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):
@@ -98,6 +98,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 f8cce53f7..56a35dd58 100644
--- a/ietf/meeting/urls.py
+++ b/ietf/meeting/urls.py
@@ -35,6 +35,7 @@ urlpatterns = patterns('',
     (r'^(?P<num>\d+)/agenda(?P<ext>.txt)$', views.agenda),
     (r'^(?P<num>\d+)/agenda.ics$', views.ical_agenda),
     (r'^(?P<num>\d+)/agenda(?P<ext>.csv)$', views.agenda),
+    (r'^(?P<num>\d+)/agenda/by-room$', views.agenda_by_room),
     (r'^(?P<num>\d+)/agendas/edit$',                       views.edit_agendas),
     (r'^(?P<num>\d+)/timeslots/edit$',                     views.edit_timeslots),
     (r'^(?P<num>\d+)/rooms$',                              ajax.timeslot_roomsurl),
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 4ea3c54cc..79452846c 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
 
@@ -376,6 +377,20 @@ def agenda(request, num=None, name=None, base=None, ext=None):
     return HttpResponse(render_to_string("meeting/"+base+ext,
         {"schedule":schedule, "updated": updated}, RequestContext(request)), 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
     # settings.py.  The *_PATH settings should be generalized to format()

From 3f6503722c4cddc31cb4a5f20ac39884438962fe Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Tue, 27 Jan 2015 21:22:45 +0000
Subject: [PATCH 03/15] Get the leadership timeslots to show in the secr pages 
 - Legacy-Id: 8931

---
 ietf/secr/meetings/forms.py |  1 +
 ietf/secr/meetings/views.py | 10 +++++-----
 2 files changed, 6 insertions(+), 5 deletions(-)

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/views.py b/ietf/secr/meetings/views.py
index 1b2e7eed9..371a95bb1 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,7 +128,7 @@ 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'))
     if not slots:
         build_nonsession(meeting,schedule)
         return None
@@ -435,7 +435,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 +458,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 +501,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:

From 61a0059d066fccbeadc8a03995af59a07f7074e1 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Wed, 4 Feb 2015 20:47:40 +0000
Subject: [PATCH 04/15] checkpoint before trying to fix the static agenda page 
 - Legacy-Id: 8972

---
 ietf/meeting/helpers.py            | 1 +
 static/js/agenda/agenda_objects.js | 6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py
index 5e25d12b0..1d3b2afc0 100644
--- a/ietf/meeting/helpers.py
+++ b/ietf/meeting/helpers.py
@@ -69,6 +69,7 @@ def build_all_agenda_slices(meeting):
     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/static/js/agenda/agenda_objects.js b/static/js/agenda/agenda_objects.js
index 1cc85af09..7f2f728b7 100644
--- a/static/js/agenda/agenda_objects.js
+++ b/static/js/agenda/agenda_objects.js
@@ -1172,6 +1172,10 @@ Session.prototype.event_template = function() {
     }
     //console.log("acronym", groupacronym, this.group.acronym, this.visible_title());
 
+    var durationstring="";
+    if (this.requested_duration!="0.0") {
+         durationstring = " ("+this.requested_duration+")"
+    }
     // see comment in ietf.ccs, and
     // http://stackoverflow.com/questions/5148041/does-firefox-support-position-relative-on-table-elements
     return "<div class='meeting_box_container' session_id=\""+this.session_id+"\"><div class=\"meeting_box "+bucket_list_style+"\" ><table class='meeting_event "+
@@ -1183,7 +1187,7 @@ Session.prototype.event_template = function() {
         this.wg_scheme()+" "+
         this.area_scheme() +" meeting_obj'>"+
         this.visible_title()+
-        "<span> ("+this.requested_duration+")</span>" +
+        "<span>" + durationstring + "</span>" +
         "</th><td class=\"ourconflicts\"></td>"+pinned+"</tr></table>"+ area_mark +"</div></div>";
 };
 

From 9421ea9b93329b686616930eadda42a13a6a5385 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Thu, 5 Feb 2015 21:16:56 +0000
Subject: [PATCH 05/15] Unbroke week-view, but only by compromising on whether
 to show things like the terminal room  - Legacy-Id: 9004

---
 ietf/meeting/models.py                | 2 +-
 ietf/meeting/views.py                 | 6 ++++--
 ietf/templates/meeting/agenda.csv     | 4 ++--
 ietf/templates/meeting/agenda.html    | 2 +-
 ietf/templates/meeting/agenda.txt     | 2 +-
 ietf/templates/meeting/week-view.html | 2 +-
 6 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index bdde2ebfd..1f4cd0756 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -582,7 +582,7 @@ class Schedule(models.Model):
                  .distinct() )
 
     def groups(self):
-        return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], session__scheduledsession__schedule=self).distinct().order_by('parent__acronym', 'acronym')
+        return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], 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/views.py b/ietf/meeting/views.py
index 79452846c..1f0967e6a 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -366,6 +366,7 @@ def agenda(request, num=None, name=None, base=None, ext=None):
     ext = ext if ext else '.html'
     if 'iPhone' in get_user_agent(request) and ext == ".html":
         base = 'm_agenda'
+    # This is misleading - urls.py doesn't send ics through here anymore
     mimetype = {".html":"text/html", ".txt": "text/plain", ".ics":"text/calendar", ".csv":"text/csv"}
     meeting = get_meeting(num)
     schedule = get_schedule(meeting, name)
@@ -374,8 +375,9 @@ def agenda(request, num=None, name=None, base=None, ext=None):
             {'meeting':meeting }, RequestContext(request)), content_type=mimetype[ext])
 
     updated = meeting_updated(meeting)
+    filtered_assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda'])
     return HttpResponse(render_to_string("meeting/"+base+ext,
-        {"schedule":schedule, "updated": updated}, RequestContext(request)), content_type=mimetype[ext])
+        {"schedule":schedule, "filtered_assignments":filtered_assignments, "updated": updated}, RequestContext(request)), content_type=mimetype[ext])
 
 #TODO - let the IAB in
 @role_required('Area Director','Secretariat')
@@ -619,7 +621,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/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 7d59a8384..1019d72dd 100644
--- a/ietf/templates/meeting/agenda.html
+++ b/ietf/templates/meeting/agenda.html
@@ -142,7 +142,7 @@ You can customize the agenda below to show only selected working group sessions.
 {% if schedule.meeting.agenda_note %}<h2 class="ietf-divider" style="background-color: #C00; margin-top: 2em; margin-bottom: 0;">{{ schedule.meeting.agenda_note|safe }}</h2>{% endif %}
 
 <table id="agenda" width="100%">
-{% for item in schedule.assignments.all %}
+{% for item in filtered_assignments.all %}
    {% ifchanged  %}
       <tr class="meeting-date">
          <td colspan="6">
diff --git a/ietf/templates/meeting/agenda.txt b/ietf/templates/meeting/agenda.txt
index fabc00145..2601c2de0 100644
--- a/ietf/templates/meeting/agenda.txt
+++ b/ietf/templates/meeting/agenda.txt
@@ -8,7 +8,7 @@
 {% filter center:72 %}Updated {{ updated|date:"Y-m-d H:i:s T" }}{% endfilter %}
 
 {% filter center:72 %}IETF agendas are subject to change, up to and during the meeting.{% endfilter %}
-{% for item in schedule.assignments.all.distinct %}{% ifchanged  %}
+{% for item in filtered_assignments.all.distinct %}{% ifchanged  %}
 
 
 {{ item.timeslot.time|date:"l"|upper }}, {{ item.timeslot.time|date:"F j, Y" }}
diff --git a/ietf/templates/meeting/week-view.html b/ietf/templates/meeting/week-view.html
index 28b9f65cd..4d79193f7 100644
--- a/ietf/templates/meeting/week-view.html
+++ b/ietf/templates/meeting/week-view.html
@@ -9,7 +9,7 @@ var items = new Array();
 {% autoescape off %}
 
 {% for slot in timeslots %} {% if slot.type.name in render_types %}
-items.push({key:"{{slot.pk}}",day:{{slot.time|date:"w"}}, time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", duration:{{slot.duration.seconds}}, time_id:"{{slot.time|date:"mdHi"}}", type:"{{slot.type}}", {% if slot.session.name %}name:"{{slot.session.name}}",{% if slot.session.group.acronym %} wg:"{{slot.session.group.acronym}}",{%endif%}{% else %}{% if slot.type.name == "Break" %}name:"{{slot.name}}", area:"break", wg:"break",{% else %}name:"{{slot.session.group.name}}{%if slot.session.group.state.name = "BOF"%} BOF{%endif%}",wg:"{{slot.session.group.acronym}}",state:"{{slot.session.group.state}}",area:"{{slot.session.group.parent.acronym}}",{% endif %}{% endif %} {% if slot.show_location %}room:"{{slot.get_location}}",{% endif %} dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}"{% if slot.session.agenda %}, agenda:"{{slot.session.agenda.get_absolute_url}}"{% endif %} });{% endif %}{% endfor %}
+items.push({key:"{{slot.pk}}",day:{{slot.time|date:"w"}}, time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", duration:{{slot.duration.seconds}}, time_id:"{{slot.time|date:"mdHi"}}", type:"{{slot.type}}", {% if slot.session.name %}name:"{{slot.session.name|escapejs}}",{% if slot.session.group.acronym %} wg:"{{slot.session.group.acronym}}",{%endif%}{% else %}{% if slot.type.name == "Break" %}name:"{{slot.name}}", area:"break", wg:"break",{% else %}name:"{{slot.session.group.name|escapejs}}{%if slot.session.group.state.name = "BOF"%} BOF{%endif%}",wg:"{{slot.session.group.acronym}}",state:"{{slot.session.group.state}}",area:"{{slot.session.group.parent.acronym}}",{% endif %}{% endif %} {% if slot.show_location %}room:"{{slot.get_location}}",{% endif %} dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}"{% if slot.session.agenda %}, agenda:"{{slot.session.agenda.get_absolute_url}}"{% endif %} });{% endif %}{% endfor %}
 {% endautoescape %}
 
 /* Saturday events need to be moved to the day -1 */

From 65f0fed7a770201c815c273e4dcb8100ae3dc275 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Wed, 29 Apr 2015 14:39:17 +0000
Subject: [PATCH 06/15] checkpointing some css/html noodling before tearing
 into models  - Legacy-Id: 9587

---
 ietf/meeting/helpers.py                    |  4 +++-
 ietf/meeting/views.py                      |  5 +++--
 ietf/templates/meeting/landscape_edit.html | 13 ++++++++++---
 static/css/agenda/agenda.css               |  2 ++
 4 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py
index d5b75bcf9..2f964c3ee 100644
--- a/ietf/meeting/helpers.py
+++ b/ietf/meeting/helpers.py
@@ -66,7 +66,9 @@ def build_all_agenda_slices(meeting):
     time_slices = []
     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']).order_by('time','name'):
+    #for ts in meeting.timeslot_set.exclude(type__in=['reg','break','lead','offagenda','other']).order_by('time','name'):
+    for ts in meeting.timeslot_set.filter(type__in=['session',]).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'):
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 05d450219..04d132422 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -259,8 +259,9 @@ def edit_agenda(request, num=None, owner=None, name=None):
     meeting_base_url = request.build_absolute_uri(meeting.base_url())
     site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash
 
-    rooms = meeting.room_set.order_by("capacity")
-    rooms = rooms.all()
+    #rooms = meeting.room_set.order_by("capacity")
+    #rooms = rooms.all()
+    rooms = meeting.room_set.filter(timeslot__type__slug='session').distinct().order_by("capacity")
     saveas = SaveAsForm()
     saveasurl=reverse(edit_agenda,
                       args=[meeting.number, schedule.owner_email(), schedule.name])
diff --git a/ietf/templates/meeting/landscape_edit.html b/ietf/templates/meeting/landscape_edit.html
index 916a602f9..4cfe34a58 100644
--- a/ietf/templates/meeting/landscape_edit.html
+++ b/ietf/templates/meeting/landscape_edit.html
@@ -110,6 +110,8 @@ promiselist.push(ss_promise);
   <p>Please save this agenda to your account first.</p>
 </div>
 
+<div class="content"> {% comment %} For preserving styling across the facelift {% endcomment %}
+
 <div class="wrapper custom_text_stuff">
 
 
@@ -206,10 +208,11 @@ promiselist.push(ss_promise);
 </div>
 
 
-<table id="meetings" class="ietf-navbar" style="width:100%">
+{%comment%}<table id="meetings" class="ietf-navbar" style="width:100%">{%endcomment%}
+<table id="meetings" class="ietf-navbar" >
 <tr>
   <th class="schedule_title"><div id="pageloaded" style="display:none">loaded</div><div id="spinner"><!-- spinney goes here --></div></th>
-  <th></th>
+  {% comment %}<th></th>{% endcomment %}
 {% for day in time_slices %}
   <th colspan="{{date_slices|colWidth:day}}" id="{{day|date:'Y-m-d'}}-btn" class=" day_{{day}} agenda_slot_title agenda_slot_unavailable">
     <div id="close_{{day|date:'Y-m-d'}}" class="close top_left very_small close_day">x</div>
@@ -226,7 +229,7 @@ promiselist.push(ss_promise);
 
 <tr>
       <th class="th_column"><button id="show_all_button" class="styled_button">show all</button></th>
-      <th><!-- resources --></th>
+      {% comment %}<th><!-- resources --></th>{% endcomment %}
     {% for day in time_slices %}
 	  {% for slot in date_slices|lookup:day %}
 	      <th class="day_{{day}}-{{slot.0|date:'Hi'}} day_{{day}} room_title ">{{slot.0|date:'Hi'}}-{{slot.1|date:'Hi'}} </th>
@@ -246,6 +249,7 @@ promiselist.push(ss_promise);
       <div class="close very_small close_room top_left small_button" id="close_{{r.name|to_acceptable_id}}">X</div>
       <div class="right room_name">{{r.name}} <span class="capacity">({{r.capacity}})</span></div>
     </th>
+{% comment 'The secretariat is not using these features' %}
     <th class="room_features">
       <div class="resource_list">
       {% for resource in r.resources.all %}
@@ -255,6 +259,7 @@ promiselist.push(ss_promise);
       {% endfor %}
       </div>
     </th>
+{% endcomment %}
     {% for day in time_slices %}
       {% for slot in date_slices|lookup:day %}
         <td id="{{r.dom_id}}_{{day}}_{{slot.0|date:'Hi'}}" class="day_{{day}} agenda-column-{{day}}-{{slot.0|date:'Hi'}} agenda_slot agenda_slot_unavailable" capacity="{{r.capacity}}" ></td>
@@ -372,4 +377,6 @@ promiselist.push(ss_promise);
 
 </div>
 
+</div> {% comment %} End of .content div {% endcomment %}
+
 {% endblock %}
diff --git a/static/css/agenda/agenda.css b/static/css/agenda/agenda.css
index 44d419395..56f7207bd 100644
--- a/static/css/agenda/agenda.css
+++ b/static/css/agenda/agenda.css
@@ -18,6 +18,8 @@
 
 .content table { border-collapse: separate; border-spacing: 2px; }
 
+.container-fluid {padding-right: 0; padding-left:0;}
+
 .ietf-navbar { background-color: #edf5ff; padding:0; border: 1px solid #89d; margin-top:4px; width: 130px; }
 .ietf-navbar ul { padding: 0; margin: 0; }
 .ietf-navbar ul li { list-style: none; padding: 0; margin: 0; font-size: 93%; padding: 2px 0px 2px 0px; }

From 1e301207106b7df740b952c630b6f4c0e9791a61 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Thu, 30 Apr 2015 15:57:48 +0000
Subject: [PATCH 07/15] checkpoint. Model changes done and UI tweaked to match.
  - Legacy-Id: 9588

---
 ietf/bin/create-break-sessions    |  4 ++--
 ietf/doc/tests.py                 |  1 +
 ietf/doc/tests_material.py        |  1 +
 ietf/meeting/ajax.py              |  2 ++
 ietf/meeting/helpers.py           | 13 ++++++++-----
 ietf/meeting/models.py            | 17 ++++++++++++++---
 ietf/meeting/test_data.py         |  8 +++++---
 ietf/meeting/tests_api.py         |  2 +-
 ietf/meeting/views.py             |  4 ++--
 ietf/secr/meetings/views.py       | 12 +++++++++---
 ietf/secr/proceedings/tests.py    |  2 +-
 ietf/secr/proceedings/views.py    |  4 +++-
 ietf/secr/sreq/views.py           | 12 +++++++++---
 ietf/templates/meeting/agenda.csv |  2 +-
 ietf/templates/meeting/agenda.txt |  2 +-
 static/css/agenda/agenda.css      |  3 ++-
 16 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/ietf/bin/create-break-sessions b/ietf/bin/create-break-sessions
index db12bf684..842c9c251 100755
--- a/ietf/bin/create-break-sessions
+++ b/ietf/bin/create-break-sessions
@@ -22,8 +22,8 @@ scheduled = SessionStatusName.objects.get(slug='sched')
 
 for meeting in Meeting.objects.filter(type="ietf").order_by("date"):
     print "Checking %s schedules ..." % meeting
-    brk, __ = Session.objects.get_or_create(meeting=meeting, group=secretariat, requested_by=system, status=scheduled, name='Break', )
-    reg, __ = Session.objects.get_or_create(meeting=meeting, group=secretariat, requested_by=system, status=scheduled, name='Registration', )
+    brk, __ = Session.objects.get_or_create(meeting=meeting, group=secretariat, requested_by=system, status=scheduled, name='Break', type_id='break',)
+    reg, __ = Session.objects.get_or_create(meeting=meeting, group=secretariat, requested_by=system, status=scheduled, name='Registration', type_id='reg',)
 
     for schedule in meeting.schedule_set.all():
         print "  Checking for missing Break and Reg sessions in %s" % schedule
diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py
index 7dd8b3b4d..e865b2066 100644
--- a/ietf/doc/tests.py
+++ b/ietf/doc/tests.py
@@ -527,6 +527,7 @@ class DocTestCase(TestCase):
             status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'),
             modified = datetime.datetime.now(),
             requested_by = Person.objects.get(user__username="marschairman"),
+            type_id = "session",
             )
         SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev)
 
diff --git a/ietf/doc/tests_material.py b/ietf/doc/tests_material.py
index ea88ba8c2..47569fa0a 100644
--- a/ietf/doc/tests_material.py
+++ b/ietf/doc/tests_material.py
@@ -148,6 +148,7 @@ class GroupMaterialTests(TestCase):
             status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'),
             modified = datetime.datetime.now(),
             requested_by = Person.objects.get(user__username="marschairman"),
+            type_id="session",
             )
         SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev)
 
diff --git a/ietf/meeting/ajax.py b/ietf/meeting/ajax.py
index 0465f3d23..27cd4d79e 100644
--- a/ietf/meeting/ajax.py
+++ b/ietf/meeting/ajax.py
@@ -158,6 +158,8 @@ AddSlotForm = modelform_factory(TimeSlot, exclude=('meeting','name','location','
 # no authorization required to list.
 def timeslot_slotlist(request, mtg):
     slots = mtg.timeslot_set.all()
+    # Restrict graphical editing to slots of type 'session' for now
+    slots = slots.filter(type__slug='session')
     json_array=[]
     for slot in slots:
         json_array.append(slot.json_dict(request.build_absolute_uri('/')))
diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py
index 2f964c3ee..24a697b17 100644
--- a/ietf/meeting/helpers.py
+++ b/ietf/meeting/helpers.py
@@ -85,13 +85,16 @@ def build_all_agenda_slices(meeting):
     time_slices.sort()
     return time_slices,date_slices
 
-def get_scheduledsessions_from_schedule(schedule):
-   ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False).exclude(session__isnull = True).order_by('timeslot__time','timeslot__name','session__group__group')
-
-   return ss
+# Not Used
+#def get_scheduledsessions_from_schedule(schedule):
+#   ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False).exclude(session__isnull = True).order_by('timeslot__time','timeslot__name','session__group__group')
+#
+#   return ss
 
 def get_all_scheduledsessions_from_schedule(schedule):
-   ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False).order_by('timeslot__time','timeslot__name')
+   ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False)
+   ss = ss.filter(session__type__slug='session')
+   ss = ss.order_by('timeslot__time','timeslot__name')
 
    return ss
 
diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index bfd3a2f78..680654c78 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -161,7 +161,10 @@ class Meeting(models.Model):
 
     @property
     def sessions_that_can_meet(self):
-        return self.session_set.exclude(status__slug='notmeet').exclude(status__slug='disappr').exclude(status__slug='deleted').exclude(status__slug='apprw')
+        qs = self.session_set.exclude(status__slug='notmeet').exclude(status__slug='disappr').exclude(status__slug='deleted').exclude(status__slug='apprw')
+        # Restrict graphical scheduling to meeting requests (Sessions) of type 'session' for now
+        qs = qs.filter(type__slug='session')
+        return qs
 
     def sessions_that_can_be_placed(self):
         from django.db.models import Q
@@ -286,6 +289,7 @@ class Room(models.Model):
     name = models.CharField(max_length=255)
     capacity = models.IntegerField(null=True, blank=True)
     resources = models.ManyToManyField(ResourceAssociation, blank = True)
+    session_types = models.ManyToManyField(TimeSlotTypeName, blank = True)
 
     def __unicode__(self):
         return "%s size: %s" % (self.name, self.capacity)
@@ -851,7 +855,8 @@ class Session(models.Model):
     meeting = models.ForeignKey(Meeting)
     name = models.CharField(blank=True, max_length=255, help_text="Name of session, in case the session has a purpose rather than just being a group meeting.")
     short = models.CharField(blank=True, max_length=32, help_text="Short version of 'name' above, for use in filenames.")
-    group = models.ForeignKey(Group)    # The group type determines the session type.  BOFs also need to be added as a group.
+    type = models.ForeignKey(TimeSlotTypeName)
+    group = models.ForeignKey(Group)    # The group type historically determined the session type.  BOFs also need to be added as a group. Note that not all meeting requests have a natural group to associate with.
     attendees = models.IntegerField(null=True, blank=True)
     agenda_note = models.CharField(blank=True, max_length=255)
     requested = models.DateTimeField(default=datetime.datetime.now)
@@ -1007,7 +1012,13 @@ class Session(models.Model):
         else:
             return "The agenda has not been uploaded yet."
 
-    def type(self):
+    # FIXME - This used to be called 'type'. It is only used in agenda.csv and agenda.txt.
+    # It will return the _wrong thing_ if you look back at an agenda of an earlier meeting
+    # where group X was a BOF at the time, but is now a WG.
+    # It also doesn't return anything useful for RG, area sessions, or anything that's not group type 'wg'.
+    # A better thing to do is find a way to note when a meeting was a BoF meeting and use that, removing this
+    # function altogether.
+    def lame_description(self):
         if self.group.type.slug in [ "wg" ]:
             return "BOF" if self.group.state.slug in ["bof", "bof-conc"] else "WG"
         else:
diff --git a/ietf/meeting/test_data.py b/ietf/meeting/test_data.py
index a3879fab8..0aa18d10f 100644
--- a/ietf/meeting/test_data.py
+++ b/ietf/meeting/test_data.py
@@ -21,6 +21,8 @@ def make_meeting_test_data():
     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.session_types.add("session")
+    breakfast_room.session_types.add("lead")
     room.resources = [projector]
 
     # mars WG
@@ -30,7 +32,7 @@ def make_meeting_test_data():
     mars_session = Session.objects.create(meeting=meeting, group=mars,
                                           attendees=10, requested_by=system_person,
                                           requested_duration=20, status_id="schedw",
-                                          scheduled=datetime.datetime.now())
+                                          scheduled=datetime.datetime.now(),type_id="session")
     mars_session.resources = [projector]
     ScheduledSession.objects.create(timeslot=slot, session=mars_session, schedule=schedule)
 
@@ -40,7 +42,7 @@ def make_meeting_test_data():
     ames_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="ames"),
                                           attendees=10, requested_by=system_person,
                                           requested_duration=20, status_id="schedw",
-                                          scheduled=datetime.datetime.now())
+                                          scheduled=datetime.datetime.now(),type_id="session")
     ScheduledSession.objects.create(timeslot=slot, session=ames_session, schedule=schedule)
 
     # IESG breakfast
@@ -51,7 +53,7 @@ def make_meeting_test_data():
                                           name="IESG Breakfast",
                                           attendees=25, requested_by=system_person,
                                           requested_duration=20, status_id="schedw",
-                                          scheduled=datetime.datetime.now())
+                                          scheduled=datetime.datetime.now(),type_id="lead")
     ScheduledSession.objects.create(timeslot=breakfast_slot, session=iesg_session, schedule=schedule)
 
     meeting.agenda = schedule
diff --git a/ietf/meeting/tests_api.py b/ietf/meeting/tests_api.py
index 6d6def084..5c3fe0fd8 100644
--- a/ietf/meeting/tests_api.py
+++ b/ietf/meeting/tests_api.py
@@ -204,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([s.session.short_name for s in meeting.agenda.scheduledsession_set.all()]))
+        self.assertEqual(set([x['short_name'] for x in info]),set([s.session.short_name for s in meeting.agenda.scheduledsession_set.filter(session__type_id='session')]))
 
         schedule = meeting.agenda
         url = urlreverse("ietf.meeting.ajax.scheduledsessions_json",
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 04d132422..bf198ae36 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -261,7 +261,7 @@ def edit_agenda(request, num=None, owner=None, name=None):
 
     #rooms = meeting.room_set.order_by("capacity")
     #rooms = rooms.all()
-    rooms = meeting.room_set.filter(timeslot__type__slug='session').distinct().order_by("capacity")
+    rooms = meeting.room_set.filter(session_types__slug='session').distinct().order_by("capacity")
     saveas = SaveAsForm()
     saveasurl=reverse(edit_agenda,
                       args=[meeting.number, schedule.owner_email(), schedule.name])
@@ -644,7 +644,7 @@ def ical_agenda(request, num=None, name=None, ext=None):
 
 def meeting_requests(request, num=None) :
     meeting = get_meeting(num)
-    sessions = Session.objects.filter(meeting__number=meeting.number,group__parent__isnull = False).exclude(requested_by=0).order_by("group__parent__acronym","status__slug","group__acronym")
+    sessions = Session.objects.filter(meeting__number=meeting.number, type__slug='session', group__parent__isnull = False).exclude(requested_by=0).order_by("group__parent__acronym","status__slug","group__acronym")
 
     groups_not_meeting = Group.objects.filter(state='Active',type__in=['WG','RG','BOF']).exclude(acronym__in = [session.group.acronym for session in sessions]).order_by("parent__acronym","acronym")
 
diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py
index 7985bfc23..e1b42e930 100644
--- a/ietf/secr/meetings/views.py
+++ b/ietf/secr/meetings/views.py
@@ -105,13 +105,17 @@ def build_nonsession(meeting,schedule):
                               short=get_session(slot).short,
                               group=get_session(slot).group,
                               requested_by=system,
-                              status_id='sched')
+                              status_id='sched',
+                              type=slot.type,
+                             )
         else:
             session, __ = Session.objects.get_or_create(meeting=meeting,
                               name=slot.name,
                               group=secretariat,
                               requested_by=system,
-                              status_id='sched')
+                              status_id='sched',
+                              type=slot.type,
+                             )
         session.save()
 
         ts = TimeSlot.objects.create(type=slot.type,
@@ -469,7 +473,9 @@ def non_session(request, meeting_id, schedule_name):
                                   short=short,
                                   group=group,
                                   requested_by=Person.objects.get(name='(system)'),
-                                  status_id='sched')
+                                  status_id='sched',
+                                  type=type,
+                             )
             session.save()
             
             # create association
diff --git a/ietf/secr/proceedings/tests.py b/ietf/secr/proceedings/tests.py
index e70258956..640d43188 100644
--- a/ietf/secr/proceedings/tests.py
+++ b/ietf/secr/proceedings/tests.py
@@ -75,7 +75,7 @@ class BluesheetTestCase(TestCase):
         make_test_data()
         meeting = Meeting.objects.filter(type='interim').first()
         group = Group.objects.get(acronym='mars')
-        Session.objects.create(meeting=meeting,group=group,requested_by_id=1,status_id='sched')
+        Session.objects.create(meeting=meeting,group=group,requested_by_id=1,status_id='sched',type_id='session')
         url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':'mars'})
         upfile = StringIO('dummy file')
         upfile.name = "scan1.pdf"
diff --git a/ietf/secr/proceedings/views.py b/ietf/secr/proceedings/views.py
index 9e38f0aff..aadc8253d 100644
--- a/ietf/secr/proceedings/views.py
+++ b/ietf/secr/proceedings/views.py
@@ -438,7 +438,9 @@ def interim(request, acronym):
             Session.objects.create(meeting=meeting,
                                    group=group,
                                    requested_by=request.user.person,
-                                   status_id='sched')
+                                   status_id='sched',
+                                   type_id='session',
+                                  )
 
             create_interim_directory()
             make_directories(meeting)
diff --git a/ietf/secr/sreq/views.py b/ietf/secr/sreq/views.py
index 92ce65e74..292fff87f 100644
--- a/ietf/secr/sreq/views.py
+++ b/ietf/secr/sreq/views.py
@@ -270,7 +270,9 @@ def confirm(request, acronym):
                                       requested_by=login,
                                       requested_duration=datetime.timedelta(0,int(duration)),
                                       comments=form['comments'],
-                                      status=SessionStatusName.objects.get(slug=slug))
+                                      status=SessionStatusName.objects.get(slug=slug),
+                                      type_id='session',
+                                     )
                 session_save(new_session)
                 if 'resources' in form:
                     new_session.resources = form['resources']
@@ -383,7 +385,9 @@ def edit_mtg(request, num, acronym):
                                               requested_by=login,
                                               requested_duration=duration,
                                               comments=form.cleaned_data['comments'],
-                                              status=SessionStatusName.objects.get(slug='schedw'))
+                                              status=SessionStatusName.objects.get(slug='schedw'),
+                                              type_id='session',
+                                             )
                         new_session.save()
                     else:
                         duration = datetime.timedelta(0,int(form.cleaned_data['length_session2']))
@@ -405,7 +409,9 @@ def edit_mtg(request, num, acronym):
                                               requested_by=login,
                                               requested_duration=duration,
                                               comments=form.cleaned_data['comments'],
-                                              status=SessionStatusName.objects.get(slug='apprw'))
+                                              status=SessionStatusName.objects.get(slug='apprw'),
+                                              type_id='session',
+                                             )
                         new_session.save()
                     else:
                         duration = datetime.timedelta(0,int(form.cleaned_data['length_session3']))
diff --git a/ietf/templates/meeting/agenda.csv b/ietf/templates/meeting/agenda.csv
index 537a97ace..93f78720a 100644
--- a/ietf/templates/meeting/agenda.csv
+++ b/ietf/templates/meeting/agenda.csv
@@ -3,5 +3,5 @@
 {% 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 %}{% 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.lame_description }}","{{ 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 %}
diff --git a/ietf/templates/meeting/agenda.txt b/ietf/templates/meeting/agenda.txt
index 2601c2de0..a7fd9119a 100644
--- a/ietf/templates/meeting/agenda.txt
+++ b/ietf/templates/meeting/agenda.txt
@@ -20,7 +20,7 @@
 {% endif %}{%          if item.timeslot.type.slug == "session" %}{% if item.session.group  %}{% ifchanged %}
 
 {{ item.timeslot.time_desc }}  {{ item.timeslot.name }}
-{% endifchanged %}{{ item.timeslot.location.name|ljust:14 }}  	{{ item.session.group.parent.acronym|upper|ljust:4 }}	{{ item.session.group.acronym|ljust:10 }}  	{{ item.session.group.name }} {{ item.session.type }}{% if item.session.agenda_note %} - {{ item.session.agenda_note }}{% endif %}
+{% endifchanged %}{{ item.timeslot.location.name|ljust:14 }}  	{{ item.session.group.parent.acronym|upper|ljust:4 }}	{{ item.session.group.acronym|ljust:10 }}  	{{ item.session.group.name }} {{ item.session.lame_description }}{% if item.session.agenda_note %} - {{ item.session.agenda_note }}{% endif %}
 {% endif %}{% endif %}{% if item.timeslot.type.slug == "break" %}
 {{ item.timeslot.time_desc }}  {{ item.timeslot.name }}{% if schedule.meeting.break_area and item.timeslot.show_location %} - {{ schedule.meeting.break_area }}{% endif %}{% endif %}{%            if item.timeslot.type.slug == "other" %}
 {{ item.timeslot.time_desc }}  {{ item.timeslot.name }} - {{ item.timeslot.location.name }}{% endif %}{% endfor %}
diff --git a/static/css/agenda/agenda.css b/static/css/agenda/agenda.css
index 56f7207bd..3b5f40959 100644
--- a/static/css/agenda/agenda.css
+++ b/static/css/agenda/agenda.css
@@ -71,6 +71,7 @@
     background-color:#2647A0;
     width:100px; /* otherwise we get overlap */
     min-width:100px;
+    min-height:40px;
     font-size:12px;
     position:absolute; /* makes it float independent of scroll */
     z-index:100; /* meeting events will be on top otherwise */
@@ -244,7 +245,7 @@ tr.agenda_slot{
 td.agenda_slot{
     /* overflow-y:auto; */
     /* height:20px; */
-    height: 40px;
+    height: 45px;
     /* min-height:20px; */
 }
 

From 72b85fc1c77dd27314e40364375d85adf1c3f98d Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Thu, 30 Apr 2015 21:44:45 +0000
Subject: [PATCH 08/15] checkpoint: views by type working  - Legacy-Id: 9592

---
 .../migrations/0005_auto_20150318_1116.py     |  2 +-
 .../migrations/0006_auto_20150429_1224.py     | 31 +++++++++++
 .../migrations/0007_auto_20150429_1346.py     | 30 +++++++++++
 ietf/meeting/urls.py                          |  3 ++
 ietf/meeting/views.py                         | 20 ++++++-
 ietf/secr/meetings/views.py                   |  7 ++-
 ietf/templates/meeting/agenda_by_type.html    | 54 +++++++++++++++++++
 7 files changed, 144 insertions(+), 3 deletions(-)
 create mode 100644 ietf/meeting/migrations/0006_auto_20150429_1224.py
 create mode 100644 ietf/meeting/migrations/0007_auto_20150429_1346.py
 create mode 100644 ietf/templates/meeting/agenda_by_type.html

diff --git a/ietf/meeting/migrations/0005_auto_20150318_1116.py b/ietf/meeting/migrations/0005_auto_20150318_1116.py
index 1068f49df..2d28d53d5 100644
--- a/ietf/meeting/migrations/0005_auto_20150318_1116.py
+++ b/ietf/meeting/migrations/0005_auto_20150318_1116.py
@@ -67,7 +67,7 @@ def backfill_91_other_meetings(apps, schema_editor):
                     (  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'),
+                    (  9, 21,  0,  180, 'lead',      [secr],     sea_pearl_12,    'Gathering', 'AMS/IESG/IAB/IAOC 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'),
diff --git a/ietf/meeting/migrations/0006_auto_20150429_1224.py b/ietf/meeting/migrations/0006_auto_20150429_1224.py
new file mode 100644
index 000000000..45e8f37b0
--- /dev/null
+++ b/ietf/meeting/migrations/0006_auto_20150429_1224.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+def extract_session_type_values(apps, schema_editor):
+
+    Session  = apps.get_model('meeting', 'Session')
+
+    for s in Session.objects.all():
+        t = s.scheduledsession_set.filter(schedule=models.F('schedule__meeting__agenda')).first()
+        if t and t.timeslot.type.slug != 'session':
+            s.type = t.timeslot.type
+            s.save()
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('name', '0004_auto_20150318_1140'),
+        ('meeting', '0005_auto_20150318_1116'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='session',
+            name='type',
+            field=models.ForeignKey(default='session', to='name.TimeSlotTypeName'),
+            preserve_default=False,
+        ),
+        migrations.RunPython(extract_session_type_values),
+    ]
diff --git a/ietf/meeting/migrations/0007_auto_20150429_1346.py b/ietf/meeting/migrations/0007_auto_20150429_1346.py
new file mode 100644
index 000000000..a68a68f4e
--- /dev/null
+++ b/ietf/meeting/migrations/0007_auto_20150429_1346.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+def extract_room_session_type_values(apps, schema_editor):
+
+    Room  = apps.get_model('meeting', 'Room')
+
+    for r in Room.objects.all():
+        for ts in r.timeslot_set.all():
+            if ts.scheduledsession_set.filter(schedule=models.F('schedule__meeting__agenda')):
+                r.session_types.add(ts.type)
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('name', '0004_auto_20150318_1140'),
+        ('meeting', '0006_auto_20150429_1224'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='room',
+            name='session_types',
+            field=models.ManyToManyField(to='name.TimeSlotTypeName', blank=True),
+            preserve_default=True,
+        ),
+        migrations.RunPython(extract_room_session_type_values),
+    ]
diff --git a/ietf/meeting/urls.py b/ietf/meeting/urls.py
index 429f8d723..351f3ab5b 100644
--- a/ietf/meeting/urls.py
+++ b/ietf/meeting/urls.py
@@ -34,6 +34,9 @@ urlpatterns = patterns('',
     (r'^(?P<num>\d+)/agenda.ics$', views.ical_agenda),
     (r'^(?P<num>\d+)/agenda(?P<ext>.csv)$', views.agenda),
     (r'^(?P<num>\d+)/agenda/by-room$', views.agenda_by_room),
+    (r'^(?P<num>\d+)/agenda/by-type$', views.agenda_by_type),
+    (r'^(?P<num>\d+)/agenda/by-type/(?P<type>[a-z]+)$', views.agenda_by_type),
+    (r'^(?P<num>\d+)/agenda/by-type/(?P<type>[a-z]+)/ics$', views.agenda_by_type_ics),
     (r'^(?P<num>\d+)/agendas/edit$',                       views.edit_agendas),
     (r'^(?P<num>\d+)/timeslots/edit$',                     views.edit_timeslots),
     (r'^(?P<num>\d+)/rooms$',                              ajax.timeslot_roomsurl),
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index bf198ae36..ca02fdc85 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -388,7 +388,6 @@ def agenda(request, num=None, name=None, base=None, ext=None):
 
 #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)
@@ -400,6 +399,25 @@ def agenda_by_room(request,num=None):
         ss_by_day[day].append(ss)
     return render(request,"meeting/agenda_by_room.html",{"meeting":meeting,"ss_by_day":ss_by_day})
 
+@role_required('Area Director','Secretariat')
+def agenda_by_type(request,num=None,type=None):
+    meeting = get_meeting(num) 
+    schedule = get_schedule(meeting)
+    scheduledsessions = schedule.scheduledsession_set.order_by('session__type__slug','timeslot__time')
+    if type:
+        scheduledsessions = scheduledsessions.filter(session__type__slug=type)
+    return render(request,"meeting/agenda_by_type.html",{"meeting":meeting,"scheduledsessions":scheduledsessions})
+
+@role_required('Area Director','Secretariat')
+def agenda_by_type_ics(request,num=None,type=None):
+    meeting = get_meeting(num) 
+    schedule = get_schedule(meeting)
+    scheduledsessions = schedule.scheduledsession_set.order_by('session__type__slug','timeslot__time')
+    if type:
+        scheduledsessions = scheduledsessions.filter(session__type__slug=type)
+    updated = meeting_updated(meeting)
+    return render(request,"meeting/agenda.ics",{"schedule":schedule,"updated":updated,"assignments":scheduledsessions},content_type="text/calendar")
+
 def read_agenda_file(num, doc):
     # XXXX FIXME: the path fragment in the code below should be moved to
     # settings.py.  The *_PATH settings should be generalized to format()
diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py
index e1b42e930..8b0ae1c98 100644
--- a/ietf/secr/meetings/views.py
+++ b/ietf/secr/meetings/views.py
@@ -53,10 +53,15 @@ def build_timeslots(meeting,room=None):
     or adding a room.
     '''
     slots = meeting.timeslot_set.filter(type='session')
+
+    # Don't do anything if the room is not capable of handling sessions
+    if not room.session_types.filter(slug='session'):
+        return
+
     if room:
         rooms = [room]
     else:
-        rooms = meeting.room_set.all()
+        rooms = meeting.room_set.filter(session_types__slug='session')
     if not slots or room:
         # if we are just building timeslots for a new room, the room argument was passed,
         # then we need to use current meeting times as a template, not the last meeting times
diff --git a/ietf/templates/meeting/agenda_by_type.html b/ietf/templates/meeting/agenda_by_type.html
new file mode 100644
index 000000000..046154d02
--- /dev/null
+++ b/ietf/templates/meeting/agenda_by_type.html
@@ -0,0 +1,54 @@
+{% extends "base.html" %}
+{% block morecss %}
+
+ul.typelist { list-style:none; padding-left:0; }
+li.typelistentry { font-size:162%; font-weight:700; }
+li.even { background-color:#EDF5FF; }
+li.odd { background-color:white; }
+ul.daylist {list-style:none; padding-left:0; margin-bottom:20px;}
+li.daylistentry { margin-left:2em; font-weight: 400; }
+
+.sessiontable {margin-left:2em; font-size:62%;}
+.sessiontable td {padding-right: 1em;}
+
+.typelabel { font-size:162%; font-weight:700; }
+.daylabel { font-size:162%;  font-weight:400; }
+.even { background-color:#EDF5FF; }
+.odd { background-color:white; }
+{% comment %}li.sessionlistentry { font-size:62%; }{% endcomment %}
+
+.type-lead:after { content: " (DO NOT POST)"; color:red; }
+.type-offagenda:after { content:" (not published on agenda)"; }
+
+{% endblock %}
+
+{% block title %}Agenda for {{meeting}} by Session Type{% endblock %}
+
+{% block content %}
+<h1>Agenda for {{meeting}} by Session Type</h1>
+{% regroup scheduledsessions by session.type.slug as type_list %}
+<ul class="typelist">
+{% for type in type_list %}
+  <li class="typelistentry {% cycle 'even' 'odd' %}">
+    {{type.grouper}} <a id="ical-link" class="btn btn-primary" href="{% url "ietf.meeting.views.agenda_by_type_ics" num=meeting.number type=type.grouper %}">Download to Calendar</a>
+    <ul class="daylist">
+    {% regroup type.list by timeslot.time|date:"l Y-M-d" as daylist %}
+    {% for day in daylist %}
+      <li class="daylistentry">
+        {{ day.grouper }}
+        <table class="sessiontable">
+        {% for ss in day.list %}
+          <tr>
+            <td>{{ss.timeslot.time|date:"H:i"}}-{{ss.timeslot.end_time|date:"H:i"}}</td>
+            <td>{{ss.timeslot.get_hidden_location}}</td>
+            <td class="type-{{ss.session.type.slug}}">{{ss.session.short_name}}</td>
+          </tr>
+        {% endfor %} 
+        </table>
+       </li>
+     {% endfor %}
+     </ul>
+   </li>
+{% endfor %}
+</ul>
+{% endblock %}

From 303e886ee5f85dd6b81e9015e311b9c8c4183106 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Thu, 30 Apr 2015 22:12:18 +0000
Subject: [PATCH 09/15] pulled several migrations from trunk and reordered the
 ones here to match  - Legacy-Id: 9594

---
 .../migrations/0004_auto_20150430_0847.py     | 62 ++++++++++++++++
 .../ipr/migrations/0003_auto_20150430_0847.py | 56 ++++++++++++++
 .../migrations/0005_auto_20150430_0847.py     | 74 +++++++++++++++++++
 ...318_1116.py => 0006_auto_20150318_1116.py} |  4 +-
 ...429_1224.py => 0007_auto_20150429_1224.py} |  2 +-
 ...429_1346.py => 0008_auto_20150429_1346.py} |  2 +-
 .../migrations/0002_auto_20150430_0909.py     | 26 +++++++
 ietf/nomcom/models.py                         |  6 +-
 .../migrations/0002_auto_20150430_0847.py     | 26 +++++++
 9 files changed, 251 insertions(+), 7 deletions(-)
 create mode 100644 ietf/group/migrations/0004_auto_20150430_0847.py
 create mode 100644 ietf/ipr/migrations/0003_auto_20150430_0847.py
 create mode 100644 ietf/meeting/migrations/0005_auto_20150430_0847.py
 rename ietf/meeting/migrations/{0005_auto_20150318_1116.py => 0006_auto_20150318_1116.py} (99%)
 rename ietf/meeting/migrations/{0006_auto_20150429_1224.py => 0007_auto_20150429_1224.py} (94%)
 rename ietf/meeting/migrations/{0007_auto_20150429_1346.py => 0008_auto_20150429_1346.py} (94%)
 create mode 100644 ietf/nomcom/migrations/0002_auto_20150430_0909.py
 create mode 100644 ietf/submit/migrations/0002_auto_20150430_0847.py

diff --git a/ietf/group/migrations/0004_auto_20150430_0847.py b/ietf/group/migrations/0004_auto_20150430_0847.py
new file mode 100644
index 000000000..71ce2d71b
--- /dev/null
+++ b/ietf/group/migrations/0004_auto_20150430_0847.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('group', '0003_auto_20150304_0743'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='group',
+            name='unused_states',
+            field=models.ManyToManyField(help_text=b'Document states that have been disabled for the group.', to='doc.State', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='group',
+            name='unused_tags',
+            field=models.ManyToManyField(help_text=b'Document tags that have been disabled for the group.', to='name.DocTagName', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='grouphistory',
+            name='unused_states',
+            field=models.ManyToManyField(help_text=b'Document states that have been disabled for the group.', to='doc.State', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='grouphistory',
+            name='unused_tags',
+            field=models.ManyToManyField(help_text=b'Document tags that have been disabled for the group.', to='name.DocTagName', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='groupmilestone',
+            name='resolved',
+            field=models.CharField(help_text=b'Explanation of why milestone is resolved (usually "Done"), or empty if still due.', max_length=50, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='groupmilestonehistory',
+            name='resolved',
+            field=models.CharField(help_text=b'Explanation of why milestone is resolved (usually "Done"), or empty if still due.', max_length=50, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='role',
+            name='email',
+            field=models.ForeignKey(help_text=b'Email address used by person for this role.', to='person.Email'),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='rolehistory',
+            name='email',
+            field=models.ForeignKey(help_text=b'Email address used by person for this role.', to='person.Email'),
+            preserve_default=True,
+        ),
+    ]
diff --git a/ietf/ipr/migrations/0003_auto_20150430_0847.py b/ietf/ipr/migrations/0003_auto_20150430_0847.py
new file mode 100644
index 000000000..01e987e4c
--- /dev/null
+++ b/ietf/ipr/migrations/0003_auto_20150430_0847.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('ipr', '0002_remove_legacy_models'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='genericiprdisclosure',
+            name='holder_contact_info',
+            field=models.TextField(help_text=b'Address, phone, etc.', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='holderiprdisclosure',
+            name='holder_contact_info',
+            field=models.TextField(help_text=b'Address, phone, etc.', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='iprdisclosurebase',
+            name='compliant',
+            field=models.BooleanField(default=True, verbose_name=b'Complies to RFC3979'),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='iprdisclosurebase',
+            name='notes',
+            field=models.TextField(verbose_name=b'Additional notes', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='iprdisclosurebase',
+            name='other_designations',
+            field=models.CharField(max_length=255, verbose_name=b'Designations for other contributions', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='nondocspecificiprdisclosure',
+            name='holder_contact_info',
+            field=models.TextField(help_text=b'Address, phone, etc.', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='thirdpartyiprdisclosure',
+            name='ietfer_contact_info',
+            field=models.TextField(help_text=b'Address, phone, etc.', blank=True),
+            preserve_default=True,
+        ),
+    ]
diff --git a/ietf/meeting/migrations/0005_auto_20150430_0847.py b/ietf/meeting/migrations/0005_auto_20150430_0847.py
new file mode 100644
index 000000000..06fbf34ba
--- /dev/null
+++ b/ietf/meeting/migrations/0005_auto_20150430_0847.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0004_auto_20150308_0446'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='meeting',
+            name='agenda_note',
+            field=models.TextField(help_text=b'Text in this field will be placed at the top of the html agenda page for the meeting.  HTML can be used, but will not be validated.', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='schedule',
+            name='public',
+            field=models.BooleanField(default=True, help_text='Make this agenda publically available.'),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='schedule',
+            name='visible',
+            field=models.BooleanField(default=True, help_text='Make this agenda available to those who know about it.'),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='scheduledsession',
+            name='extendedfrom',
+            field=models.ForeignKey(default=None, to='meeting.ScheduledSession', help_text='Timeslot this session is an extension of.', null=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='scheduledsession',
+            name='pinned',
+            field=models.BooleanField(default=False, help_text=b'Do not move session during automatic placement.'),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='scheduledsession',
+            name='session',
+            field=models.ForeignKey(default=None, to='meeting.Session', help_text='Scheduled session.', null=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='session',
+            name='name',
+            field=models.CharField(help_text=b'Name of session, in case the session has a purpose rather than just being a group meeting.', max_length=255, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='session',
+            name='short',
+            field=models.CharField(help_text=b"Short version of 'name' above, for use in filenames.", max_length=32, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='timeslot',
+            name='sessions',
+            field=models.ManyToManyField(related_name='slots', to='meeting.Session', through='meeting.ScheduledSession', blank=True, help_text='Scheduled session, if any.', null=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='timeslot',
+            name='show_location',
+            field=models.BooleanField(default=True, help_text=b'Show location in agenda.'),
+            preserve_default=True,
+        ),
+    ]
diff --git a/ietf/meeting/migrations/0005_auto_20150318_1116.py b/ietf/meeting/migrations/0006_auto_20150318_1116.py
similarity index 99%
rename from ietf/meeting/migrations/0005_auto_20150318_1116.py
rename to ietf/meeting/migrations/0006_auto_20150318_1116.py
index 2d28d53d5..b61bb3c8c 100644
--- a/ietf/meeting/migrations/0005_auto_20150318_1116.py
+++ b/ietf/meeting/migrations/0006_auto_20150318_1116.py
@@ -130,9 +130,9 @@ def backfill_91_other_meetings(apps, schema_editor):
 class Migration(migrations.Migration):
 
     dependencies = [
-        ('meeting', '0004_auto_20150308_0446'),
+        ('meeting', '0005_auto_20150430_0847'),
         ('name',    '0004_auto_20150318_1140'),
-        ('group',   '0003_auto_20150304_0743'),
+        ('group',   '0004_auto_20150430_0847'),
         ('person',  '0004_auto_20150308_0440'),
     ]
 
diff --git a/ietf/meeting/migrations/0006_auto_20150429_1224.py b/ietf/meeting/migrations/0007_auto_20150429_1224.py
similarity index 94%
rename from ietf/meeting/migrations/0006_auto_20150429_1224.py
rename to ietf/meeting/migrations/0007_auto_20150429_1224.py
index 45e8f37b0..43717f149 100644
--- a/ietf/meeting/migrations/0006_auto_20150429_1224.py
+++ b/ietf/meeting/migrations/0007_auto_20150429_1224.py
@@ -17,7 +17,7 @@ class Migration(migrations.Migration):
 
     dependencies = [
         ('name', '0004_auto_20150318_1140'),
-        ('meeting', '0005_auto_20150318_1116'),
+        ('meeting', '0006_auto_20150318_1116'),
     ]
 
     operations = [
diff --git a/ietf/meeting/migrations/0007_auto_20150429_1346.py b/ietf/meeting/migrations/0008_auto_20150429_1346.py
similarity index 94%
rename from ietf/meeting/migrations/0007_auto_20150429_1346.py
rename to ietf/meeting/migrations/0008_auto_20150429_1346.py
index a68a68f4e..24485e2fd 100644
--- a/ietf/meeting/migrations/0007_auto_20150429_1346.py
+++ b/ietf/meeting/migrations/0008_auto_20150429_1346.py
@@ -16,7 +16,7 @@ class Migration(migrations.Migration):
 
     dependencies = [
         ('name', '0004_auto_20150318_1140'),
-        ('meeting', '0006_auto_20150429_1224'),
+        ('meeting', '0007_auto_20150429_1224'),
     ]
 
     operations = [
diff --git a/ietf/nomcom/migrations/0002_auto_20150430_0909.py b/ietf/nomcom/migrations/0002_auto_20150430_0909.py
new file mode 100644
index 000000000..7a15833ac
--- /dev/null
+++ b/ietf/nomcom/migrations/0002_auto_20150430_0909.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('nomcom', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='nomcom',
+            name='reminder_interval',
+            field=models.PositiveIntegerField(help_text=b'If the nomcom user sets the interval field then a cron command will send reminders to the nominees who have not responded using the following formula: (today - nomination_date) % interval == 0.', null=True, blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='nomcom',
+            name='send_questionnaire',
+            field=models.BooleanField(default=False, help_text=b'If you check this box, questionnaires are sent automatically after nominations.', verbose_name=b'Send questionnaires automatically'),
+            preserve_default=True,
+        ),
+    ]
diff --git a/ietf/nomcom/models.py b/ietf/nomcom/models.py
index 712230635..bece016f7 100644
--- a/ietf/nomcom/models.py
+++ b/ietf/nomcom/models.py
@@ -38,9 +38,9 @@ class NomCom(models.Model):
     group = models.ForeignKey(Group)
     send_questionnaire = models.BooleanField(verbose_name='Send questionnaires automatically', default=False,
                                              help_text='If you check this box, questionnaires are sent automatically after nominations.')
-    reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user sets the interval field then a cron command will \
-                                                               send reminders to the nominees who have not responded using \
-                                                               the following formula: (today - nomination_date) % interval == 0.',
+    reminder_interval = models.PositiveIntegerField(help_text='If the nomcom user sets the interval field then a cron command will '
+                                                              'send reminders to the nominees who have not responded using '
+                                                              'the following formula: (today - nomination_date) % interval == 0.',
                                                                blank=True, null=True)
     initial_text = models.TextField(verbose_name='Help text for nomination form',
                                     blank=True)
diff --git a/ietf/submit/migrations/0002_auto_20150430_0847.py b/ietf/submit/migrations/0002_auto_20150430_0847.py
new file mode 100644
index 000000000..9fa60bc2d
--- /dev/null
+++ b/ietf/submit/migrations/0002_auto_20150430_0847.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submit', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='submission',
+            name='authors',
+            field=models.TextField(help_text=b'List of author names and emails, one author per line, e.g. "John Doe &lt;john@example.org&gt;".', blank=True),
+            preserve_default=True,
+        ),
+        migrations.AlterField(
+            model_name='submission',
+            name='submitter',
+            field=models.CharField(help_text=b'Name and email of submitter, e.g. "John Doe &lt;john@example.org&gt;".', max_length=255, blank=True),
+            preserve_default=True,
+        ),
+    ]

From 17b928b94bca46b3f0ec1742be5c9190be25d1ca Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Fri, 1 May 2015 22:31:30 +0000
Subject: [PATCH 10/15] checkpoint: added room functional description,
 backfilled ietf92 meeting data, repaired session material views, added tests 
 - Legacy-Id: 9596

---
 .../migrations/0009_room_functional_name.py   |  20 ++
 .../migrations/0010_auto_20150501_0732.py     |  49 +++++
 .../migrations/0011_ietf92_meetings.py        | 191 ++++++++++++++++++
 ietf/meeting/models.py                        |  12 ++
 ietf/meeting/test_data.py                     |   8 +-
 ietf/meeting/tests_api.py                     |   2 +-
 ietf/meeting/tests_views.py                   |  27 ++-
 ietf/meeting/views.py                         |   7 +-
 ietf/secr/meetings/tests.py                   |   2 +-
 ietf/templates/meeting/agenda_by_room.html    |   8 +-
 ietf/templates/meeting/session_details.html   |   4 +-
 11 files changed, 315 insertions(+), 15 deletions(-)
 create mode 100644 ietf/meeting/migrations/0009_room_functional_name.py
 create mode 100644 ietf/meeting/migrations/0010_auto_20150501_0732.py
 create mode 100644 ietf/meeting/migrations/0011_ietf92_meetings.py

diff --git a/ietf/meeting/migrations/0009_room_functional_name.py b/ietf/meeting/migrations/0009_room_functional_name.py
new file mode 100644
index 000000000..4170f3b59
--- /dev/null
+++ b/ietf/meeting/migrations/0009_room_functional_name.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0008_auto_20150429_1346'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='room',
+            name='functional_name',
+            field=models.CharField(default='', max_length=255, blank=True),
+            preserve_default=False,
+        ),
+    ]
diff --git a/ietf/meeting/migrations/0010_auto_20150501_0732.py b/ietf/meeting/migrations/0010_auto_20150501_0732.py
new file mode 100644
index 000000000..7c52f7634
--- /dev/null
+++ b/ietf/meeting/migrations/0010_auto_20150501_0732.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+def add_91_room_functional_names(apps, schema_editor):
+
+    map = { 
+           'Hibiscus':          'Breakout 3',
+           'South Pacific 2':   'Meeting Room #6',
+           'South Pacific 1':   'Terminal Room',
+           'Coral 1':           'Breakout 4',
+           'Coral 2':           'Breakout 5',
+           'Coral 5':           'Breakout 6',
+           'Coral 4':           'Breakout 7',
+           'Coral 3':           'Breakout 8',
+           'Great Lawn':        'Welcome Reception',
+           'Rainbow Suite':     'Not Used',
+           'Lehua Suite':       'Breakout 1',
+           'Kahili':            'Breakout 2',
+           'Rainbow Suite 1/2': 'Meeting Room #2 (IESG Meeting Room)',
+           'Village Green':     'Meet and Greet',
+           'South Pacific 3':   'Meeting Room #4 (IAOC/IAD Office)',
+           'Rainbow Suite 3':   'Meeting Room #7',
+           'Rainbow Suite 2/3': 'ISOC Dinner',
+           'South Pacific 3/4': 'ISOC AC Meeting',
+           'Iolani 6/7':        'Meeting Room #5 (NomCom Office)',
+           'Sea Pearl 1/2':     'Reception',
+           'Sea Pearl 2':       'Meeting Room #1 (IAB Meeting Room)',
+           'Coral Lounge':      'Registration Area and Breaks',
+           'Tiare Suite':       'Meeting Room #8 (RFC Office)',
+          }
+
+    Room  = apps.get_model('meeting', 'Room')
+
+    for name,functional_name in map.items():
+        Room.objects.filter(meeting__number=91,name=name).update(functional_name=functional_name)
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0009_room_functional_name'),
+    ]
+
+    operations = [
+        migrations.RunPython(add_91_room_functional_names),
+    ]
+
diff --git a/ietf/meeting/migrations/0011_ietf92_meetings.py b/ietf/meeting/migrations/0011_ietf92_meetings.py
new file mode 100644
index 000000000..7d61d205a
--- /dev/null
+++ b/ietf/meeting/migrations/0011_ietf92_meetings.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations
+
+
+def backfill_92_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')
+        Session          = apps.get_model('meeting', 'Session')
+        Group            = apps.get_model('group',   'Group')
+        Person           = apps.get_model('person',  'Person')
+
+        ietf92 = Meeting.objects.filter(number=92).first()
+
+        if not ietf92:
+            print "IETF92 not found, no data changed"
+        else:
+
+            # Clear out one orphaned ill-configured Session object
+            qs = Session.objects.filter(meeting__number=92,name__icontains='beverage break').exclude(type_id='break') 
+            if qs.count()==1:
+                qs.delete()
+
+            agenda92 = Schedule.objects.get(meeting=ietf92,pk=ietf92.agenda.pk)
+
+            map_existing = {
+                            'Regency Ballroom':     'Lounge',
+                            'Garden Terrace Level': 'Meet and Greet',
+                            'Royal':                'Breakout 1',
+                            'Continental':          'Breakout 2',
+                            'Far East':             'Breakout 3',
+                            'Oak ':                 'Breakout 4',
+                            'Parisian':             'Breakout 5',
+                            'Venetian':             'Breakout 6',
+                            'Gold':                 'Breakout 7',
+                            'International':        'Breakout 8',
+                            'Brasserie':            'Terminal Room',
+                            'State':                'Office #3 (Secretariat Office)',
+                            'French':               'Meeting Room #2 (IESG Meeting Room)',
+                           }
+
+            for name,functional_name in map_existing.items():
+                Room.objects.filter(meeting__number=92,name=name).update(functional_name=functional_name)
+
+            regency       = Room.objects.get(meeting=ietf92,name='Regency Ballroom')
+            garden        = Room.objects.get(meeting=ietf92,name='Garden Terrace Level')
+            royal         = Room.objects.get(meeting=ietf92,name='Royal')
+            continental   = Room.objects.get(meeting=ietf92,name='Continental')
+            far_east      = Room.objects.get(meeting=ietf92,name='Far East')
+            oak           = Room.objects.get(meeting=ietf92,name='Oak ')
+            #parisian      = Room.objects.get(meeting=ietf92,name='Parisian')
+            #venetian      = Room.objects.get(meeting=ietf92,name='Venetian')
+            #gold          = Room.objects.get(meeting=ietf92,name='Gold')
+            #international = Room.objects.get(meeting=ietf92,name='International')
+            brasserie     = Room.objects.get(meeting=ietf92,name='Brasserie')
+            state         = Room.objects.get(meeting=ietf92,name='State')
+            #french        = Room.objects.get(meeting=ietf92,name='French')
+
+            executive     = Room.objects.create(meeting=ietf92,name='Executive',functional_name='Meeting Room #4 (IAOC/IAD)',capacity=20)
+            regency_foyer = Room.objects.create(meeting=ietf92,name='Regency Foyer',functional_name='Registration',capacity=1200)
+            florentine    = Room.objects.create(meeting=ietf92,name='Florentine',functional_name='Meeting Room #1 (IAB)', capacity=40)
+            pavilion      = Room.objects.create(meeting=ietf92,name='Pavilion',functional_name='Meeting Room #6', capacity=80)
+            terrace       = Room.objects.create(meeting=ietf92,name='Terrace',functional_name='Meeting Room #7', capacity=80)
+            panorama      = Room.objects.create(meeting=ietf92,name='Panorama',functional_name='Companion Reception', capacity=200)
+
+            regency.session_types.add('offagenda')
+            pavilion.session_types.add('offagenda')
+            pavilion.session_types.add('lead')
+            garden.session_types.add('lead')
+            panorama.session_types.add('offagenda')
+            executive.session_types.add('lead')
+            executive.session_types.add('offagenda')
+            regency_foyer.session_types.add('offagenda')
+            oak.session_types.add('offagenda')
+            continental.session_types.add('offagenda')
+            state.session_types.add('offagenda')
+            florentine.session_types.add('offagenda')
+            terrace.session_types.add('lead')
+            terrace.session_types.add('offagenda')
+            far_east.session_types.add('offagenda')
+            brasserie.session_types.add('offagenda')
+            royal.session_types.add('offagenda') 
+            
+            iesg = Group.objects.get(acronym='iesg')
+            iab = Group.objects.get(acronym='iab')
+            iaoc = Group.objects.get(acronym='iaoc')
+            secr = Group.objects.get(acronym='secretariat')
+    
+            system = Person.objects.get(name='(System)')
+    
+            for d, h, m, duration, type_id,  groups, room, slotname, label in [
+                    ( 20, 13,  0,  480, 'offagenda', [secr],     brasserie,       'Setup', 'Hackathon: Setup'),
+                    ( 20,  8,  0,  540, 'offagenda', [secr],     executive,       'Meeting', 'DNS OARC Meeting'),
+                    ( 21,  8,  0,  540, 'offagenda', [secr],     executive,       'Meeting', 'DNS OARC Meeting'),
+                    ( 22, 12,  0,  720, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 22, 11,  0,  480, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
+                    ( 22, 19,  0,  120, 'offagenda', [secr],     state,           'Meeting', 'CJK Generation Panel coordination informal meeting'),
+                    ( 22, 19,  0,  120, 'offagenda', [iab],      florentine,      'Meeting', 'IAB PrivSec program'),
+                    ( 22,  8, 30,   90, 'lead',      [iesg],     pavilion,        'Breakfast', None),
+                    ( 22,  9,  0,  150, 'lead',      [iesg],     pavilion,        'Meeting', None),
+                    ( 22, 11, 30,  150, 'lead',      [iab,iesg], pavilion,        'Lunch', 'IESG/IAB Lunch'),
+                    ( 22, 14,  0,  180, 'lead',      [iab],      pavilion,        'Meeting', None),
+                    ( 22,  9,  0,  480, 'offagenda', [secr],     terrace,         'Meeting', 'RootOPS'),
+                    ( 22, 16, 30,   60, 'offagenda', [secr],     panorama,        'Reception', "Companion's Reception"), # Should this appear on agenda?
+                    ( 22, 21,  0,  180, 'lead',      [secr],     garden,          'Gathering', 'AMS/IESG/IAB/IAOC Gathering'),
+                    ( 22,  9,  0,  480, 'offagenda', [secr],     royal,           'ICNRG', 'ICNRG'),
+                    ( 22, 19,  0,  180, 'offagenda', [secr],     royal,           'Meeting', 'Huawei'),
+                    ( 22, 12, 30,  240, 'offagenda', [secr],     continental,     'Meeting', 'Verisign ROA Workshop'),
+                    ( 22, 15, 15,  165, 'offagenda', [secr],     far_east,        'Meeting', 'RSSAC'),
+                    ( 22,  9,  0,  150, 'offagenda', [secr],     oak,             'Meeting', 'Ericsson'),
+                    ( 23,  0,  0, 1440, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 23,  8,  0,  600, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
+                    ( 23,  0,  0, 1440, 'offagenda', [secr],     regency,         'Lounge', 'Lounge'),
+                    ( 23, 11, 30,  180, 'offagenda', [secr],     executive,       'Lunch', 'ICANN Lunch'),
+                    ( 23,  7,  0,  120, 'lead',      [iab,iesg], pavilion,        'Breakfast', 'IESG/IAB Breakfast'),
+                    ( 23, 11, 30,   90, 'offagenda', [secr],     pavilion,        'Meeting', 'OPS Directorate Meeting'),
+                    ( 23, 19,  0,  120, 'offagenda', [secr],     pavilion,        'Meeting', 'ACE'),
+                    ( 23,  7, 30,   90, 'offagenda', [secr],     terrace,         'Meeting', 'NRO ECG'),
+                    ( 23, 11, 30,   90, 'offagenda', [secr],     terrace,         'Meeting', 'IETF/3GPP Meeting'),
+                    ( 23, 19,  0,  120, 'offagenda', [secr],     terrace,         'Meeting', 'I2NSF'),
+                    ( 23, 18, 50,   60, 'offagenda', [secr],     royal,           'Meeting', 'Captive Portal Bar BOF'),
+                    ( 24,  0,  0, 1440, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 24,  8,  0,  600, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
+                    ( 24,  0,  0, 1440, 'offagenda', [secr],     regency,         'Lounge', 'Lounge'),
+                    ( 24, 11, 30,   90, 'offagenda', [secr],     state,           'Meeting', 'HIAPS'),
+                    ( 24, 16, 30,  120, 'offagenda', [secr],     state,           'Meeting', 'PDF Draft Review'),
+                    ( 24,  7,  0,  120, 'lead',      [iesg],     pavilion,        'Breakfast', None),
+                    ( 24, 11, 30,   90, 'offagenda', [secr],     pavilion,        'Meeting', 'SECdir Meeting'),
+                    ( 24,  7,  0,  120, 'lead',      [iab],      terrace,         'Breakfast', None),
+                    ( 24,  9,  0,  120, 'offagenda', [secr],     terrace,         'Meeting', 'ICNN DRZK Design Team'),
+                    ( 24, 11, 30,   90, 'offagenda', [secr],     terrace,         'Lunch', 'RSAG/ISEB Lunch'),
+                    ( 24, 13,  0,  120, 'offagenda', [secr],     terrace,         'Meeting', 'SACM'),
+                    ( 24, 15,  0,   90, 'offagenda', [secr],     terrace,         'Meeting', 'RSOC Meeting'),
+                    ( 24, 17, 30,   60, 'offagenda', [secr],     terrace,         'Meeting', 'SACM'),
+                    ( 24, 11, 30,   90, 'offagenda', [secr],     royal,           'Meeting', 'IoT Directorate'),
+                    ( 25,  0,  0, 1440, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 25,  8,  0,  600, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
+                    ( 25,  0,  0, 1440, 'offagenda', [secr],     regency,         'Lounge', 'Lounge'),
+                    ( 25,  8,  0,   60, 'offagenda', [secr],     state,           'Meeting', 'SFC Control Plane Offline Discussion'),
+                    ( 25, 19,  0,  240, 'offagenda', [secr],     state,           'Meeting', 'WWG'),
+                    ( 25,  8,  0,   60, 'offagenda', [secr],     florentine,      'Meeting', 'IAB Name Resolution'),
+                    ( 25,  6, 45,  135, 'lead',      [iaoc],     executive,       'Breakfast', None),
+                    ( 25, 11, 30,   90, 'offagenda', [secr],     pavilion,        'Meeting', 'RMCAT'),
+                    ( 25, 19,  0,  120, 'offagenda', [secr],     pavilion,        'Meeting', 'I2NSF'),
+                    ( 25,  8,  0,   60, 'offagenda', [secr],     terrace,         'Meeting', 'IETF/IEEE 802 Coordination'),
+                    ( 25, 11, 30,   90, 'offagenda', [secr],     terrace,         'Lunch',   'RFC Editor Lunch'),
+                    ( 25, 19, 30,  120, 'offagenda', [secr],     terrace,         'Dinner',  'SSAC Dinner'),
+                    ( 26,  0,  0, 1440, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 26,  8,  0,  600, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
+                    ( 26,  0,  0, 1440, 'offagenda', [secr],     regency,         'Lounge', 'Lounge'),
+                    ( 26,  7, 30,   90, 'offagenda', [secr],     state,           'Breakfast', 'EDU Team Breakfast'),
+                    ( 26, 14,  0,  120, 'offagenda', [secr],     state,           'Meeting',   'JJB'),
+                    ( 26, 11, 30,   90, 'offagenda', [secr],     florentine,      'Meeting',   'IAB Liaison Oversight'),
+                    ( 26, 18,  0,  150, 'offagenda', [secr],     pavilion,        'Meeting',   '6LO Security Discussion'),
+                    ( 26,  7,  0,  120, 'lead',      [iab],      terrace,         'Breakfast', None),
+                    ( 26, 17, 40,   60, 'offagenda', [secr],     terrace,         'Meeting', 'SACM'),
+                    ( 26, 19, 30,  150, 'offagenda', [secr],     royal,           'Meeting', 'Lavabit'),
+                    ( 27,  0,  0,  900, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
+                    ( 27,  7, 30,   90, 'offagenda', [secr],     executive,       'Meeting', 'Post-Con with Ray'),
+                    ( 27, 13, 30,   90, 'lead',      [iab,iesg], pavilion,        'Lunch', 'IESG/IAB Lunch'),
+                   ]:
+
+                ts = ietf92.timeslot_set.create(type_id=type_id, name=slotname, 
+                                                time=datetime.datetime(2015,3,d,h,m,0),
+                                                duration=datetime.timedelta(minutes=duration), 
+                                                location=room,show_location=(type_id not in ['lead','offagenda']))
+                for group in groups:
+                    session = ietf92.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',type_id=type_id)
+                    ScheduledSession.objects.create(schedule=agenda92, timeslot=ts, session=session)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('meeting', '0010_auto_20150501_0732'),
+        ('name',    '0004_auto_20150318_1140'),
+        ('group',   '0004_auto_20150430_0847'),
+        ('person',  '0004_auto_20150308_0440'),
+    ]
+
+    operations = [
+        migrations.RunPython(backfill_92_other_meetings)
+    ]
diff --git a/ietf/meeting/models.py b/ietf/meeting/models.py
index 680654c78..bcecac490 100644
--- a/ietf/meeting/models.py
+++ b/ietf/meeting/models.py
@@ -287,6 +287,7 @@ class ResourceAssociation(models.Model):
 class Room(models.Model):
     meeting = models.ForeignKey(Meeting)
     name = models.CharField(max_length=255)
+    functional_name = models.CharField(max_length=255, blank = True)
     capacity = models.IntegerField(null=True, blank=True)
     resources = models.ManyToManyField(ResourceAssociation, blank = True)
     session_types = models.ManyToManyField(TimeSlotTypeName, blank = True)
@@ -374,6 +375,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_hidden_location(self):
         location = self.location
         if location:
@@ -390,6 +392,16 @@ class TimeSlot(models.Model):
             location = ""
         return location
 
+    def get_functional_location(self):
+        name_parts = []
+        room = self.location
+        if room and room.functional_name:
+            name_parts.append(room.functional_name)
+        location = self.get_hidden_location()
+        if location:
+            name_parts.append(location)
+        return ' - '.join(name_parts)
+
     @property
     def tz(self):
         if self.meeting.time_zone:
diff --git a/ietf/meeting/test_data.py b/ietf/meeting/test_data.py
index 0aa18d10f..0053eb558 100644
--- a/ietf/meeting/test_data.py
+++ b/ietf/meeting/test_data.py
@@ -59,20 +59,20 @@ def make_meeting_test_data():
     meeting.agenda = schedule
     meeting.save()
 
-    doc = Document.objects.create(name='agenda-mars-ietf-42', type_id='agenda', title="Agenda", external_url="agenda-mars.txt",group=mars)
+    doc = Document.objects.create(name='agenda-mars-ietf-42', type_id='agenda', title="Agenda", external_url="agenda-mars.txt",group=mars,rev='00')
     doc.set_state(State.objects.get(type=doc.type_id, slug="active"))
     mars_session.sessionpresentation_set.add(SessionPresentation(session=mars_session,document=doc,rev=doc.rev))
 
-    doc = Document.objects.create(name='minutes-mars-ietf-42', type_id='minutes', title="Minutes", external_url="minutes-mars.txt",group=mars)
+    doc = Document.objects.create(name='minutes-mars-ietf-42', type_id='minutes', title="Minutes", external_url="minutes-mars.txt",group=mars,rev='00')
     doc.set_state(State.objects.get(type=doc.type_id, slug="active"))
     mars_session.sessionpresentation_set.add(SessionPresentation(session=mars_session,document=doc,rev=doc.rev))
 
-    doc = Document.objects.create(name='slides-mars-ietf-42', type_id='slides', title="Slideshow", external_url="slides-mars.txt",group=mars)
+    doc = Document.objects.create(name='slides-mars-ietf-42', type_id='slides', title="Slideshow", external_url="slides-mars.txt",group=mars,rev='00')
     doc.set_state(State.objects.get(type=doc.type_id, slug="active"))
     doc.set_state(State.objects.get(type='reuse_policy',slug='single'))
     mars_session.sessionpresentation_set.add(SessionPresentation(session=mars_session,document=doc,rev=doc.rev))
 
-    doc = Document.objects.create(name='slides-mars-ietf-42-deleted', type_id='slides', title="Bad Slideshow", external_url="slides-mars-deleted.txt",group=mars)
+    doc = Document.objects.create(name='slides-mars-ietf-42-deleted', type_id='slides', title="Bad Slideshow", external_url="slides-mars-deleted.txt",group=mars,rev='00')
     doc.set_state(State.objects.get(type=doc.type_id, slug="deleted"))
     doc.set_state(State.objects.get(type='reuse_policy',slug='single'))
     mars_session.sessionpresentation_set.add(SessionPresentation(session=mars_session,document=doc,rev=doc.rev))
diff --git a/ietf/meeting/tests_api.py b/ietf/meeting/tests_api.py
index 5c3fe0fd8..5953c928b 100644
--- a/ietf/meeting/tests_api.py
+++ b/ietf/meeting/tests_api.py
@@ -138,7 +138,7 @@ class ApiTests(TestCase):
         timeslots_before = meeting.timeslot_set.count()
         url = urlreverse("ietf.meeting.ajax.timeslot_roomsurl", kwargs=dict(num=meeting.number))
 
-        post_data = { "name": "new room", "capacity": "50" , "resources": []}
+        post_data = { "name": "new room", "capacity": "50" , "resources": [], "session_types":["session"]}
 
         # unauthorized post
         r = self.client.post(url, post_data)
diff --git a/ietf/meeting/tests_views.py b/ietf/meeting/tests_views.py
index a1db83d9a..1e48885b3 100644
--- a/ietf/meeting/tests_views.py
+++ b/ietf/meeting/tests_views.py
@@ -128,9 +128,34 @@ class MeetingTests(TestCase):
         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))
+        r = self.client.get(url)
         self.assertTrue(all([x in r.content for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']]))
 
+    def test_agenda_by_type(self):
+        meeting = make_meeting_test_data()
+
+        url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number))
+        login_testing_unauthorized(self,"secretary",url)
+        r = self.client.get(url)
+        self.assertTrue(all([x in r.content for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']]))
+
+        url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,type='session'))
+        r = self.client.get(url)
+        self.assertTrue(all([x in r.content for x in ['mars','Test Room']]))
+        self.assertFalse(any([x in r.content for x in ['IESG Breakfast','Breakfast Room']]))
+
+        url = urlreverse("ietf.meeting.views.agenda_by_type",kwargs=dict(num=meeting.number,type='lead'))
+        r = self.client.get(url)
+        self.assertFalse(any([x in r.content for x in ['mars','Test Room']]))
+        self.assertTrue(all([x in r.content for x in ['IESG Breakfast','Breakfast Room']]))
+
+    def test_session_details(self):
+        meeting = make_meeting_test_data()
+        url = urlreverse("ietf.meeting.views.session_details", kwargs=dict(num=meeting.number, acronym="mars"))
+        r = self.client.get(url)
+        self.assertTrue(all([x in r.content for x in ('slides','agenda','minutes')]))
+        self.assertFalse('deleted' in r.content)
+
     def test_materials(self):
         meeting = make_meeting_test_data()
         session = Session.objects.filter(meeting=meeting, group__acronym="mars").first()
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index ca02fdc85..a5c202599 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -394,7 +394,7 @@ def agenda_by_room(request,num=None):
     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'):
+    for ss in schedule.scheduledsession_set.order_by('timeslot__location__functional_name','timeslot__location__name','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})
@@ -673,7 +673,7 @@ def meeting_requests(request, num=None) :
 
 def session_details(request, num, acronym, date=None, week_day=None, seq=None) :
     meeting = get_meeting(num)
-    sessions = Session.objects.filter(meeting=meeting,group__acronym=acronym)
+    sessions = Session.objects.filter(meeting=meeting,group__acronym=acronym,type__in=['session','plenary','other'])
 
     if not sessions:
         sessions = Session.objects.filter(meeting=meeting,short=acronym) 
@@ -720,11 +720,14 @@ def session_details(request, num, acronym, date=None, week_day=None, seq=None) :
         ss = session.scheduledsession_set.filter(schedule=meeting.agenda).order_by('timeslot__time')
         if ss:
             scheduled_time = ','.join([x.timeslot.time.strftime("%A %b-%d %H%M") for x in ss])
+        # TODO FIXME Deleted materials shouldn't be in the sessionpresentation_set
+        filtered_sessionpresentation_set = [p for p in session.sessionpresentation_set.all() if p.document.get_state_slug(p.document.type_id)!='deleted']
         return render(request, "meeting/session_details.html",
                       { 'session':sessions[0] ,
                         'meeting' :meeting ,
                         'acronym' :acronym,
                         'time': scheduled_time,
+                        'filtered_sessionpresentation_set': filtered_sessionpresentation_set
                       })
     else:
         return render(request, "meeting/session_list.html",
diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py
index ad9a1eb3f..5e8eb6bbe 100644
--- a/ietf/secr/meetings/tests.py
+++ b/ietf/secr/meetings/tests.py
@@ -147,7 +147,7 @@ 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 input[type='text']")),meeting.room_set.count())
+        self.assertEqual(len(q("#id_rooms_table tr input[type='checkbox']")),meeting.room_set.count())
         
         # test delete
         # first unschedule sessions so we can delete
diff --git a/ietf/templates/meeting/agenda_by_room.html b/ietf/templates/meeting/agenda_by_room.html
index 399c6f841..7871af1ab 100644
--- a/ietf/templates/meeting/agenda_by_room.html
+++ b/ietf/templates/meeting/agenda_by_room.html
@@ -9,8 +9,8 @@ li.roomlistentry { font-weight: 400; }
 ul.sessionlist { list-style:none; padding-left:2em; margin-bottom:10px;}
 li.sessionlistentry { font-size:62%; }
 
-.lead:after { content: " (DO NOT POST)"; color:red; }
-.offagenda:after { content:" (not published on agenda)"; }
+.type-lead:after { content: " (DO NOT POST)"; color:red; }
+.type-offagenda:after { content:" (not published on agenda)"; }
 
 {% endblock %}
 
@@ -21,13 +21,13 @@ li.sessionlistentry { font-size:62%; }
 <ul class="daylist">
 {% for day,sessions in ss_by_day.items %}
 <li class="daylistentry {% cycle 'even' 'odd' %}">{{day|date:'l, j F Y'}}
-{% regroup sessions by timeslot.get_hidden_location as room_list %}
+{% regroup sessions by timeslot.get_functional_location as room_list %}
 <ul class="roomlist">
 {% for room in room_list %}
 <li class="roomlistentry">{{room.grouper|default:"Location Unavailable"}}
 <ul class="sessionlist">
 {% for ss in room.list %}
-<li class="sessionlistentry {{ss.timeslot.type.slug}}">{{ss.timeslot.time|date:"H:i"}}-{{ss.timeslot.end_time|date:"H:i"}} {{ss.session.short_name}}</li>
+<li class="sessionlistentry type-{{ss.timeslot.type.slug}}">{{ss.timeslot.time|date:"H:i"}}-{{ss.timeslot.end_time|date:"H:i"}} {{ss.session.short_name}}</li>
 {% endfor %}
 </ul>
 </li>
diff --git a/ietf/templates/meeting/session_details.html b/ietf/templates/meeting/session_details.html
index 68cc580b9..fe86627c6 100644
--- a/ietf/templates/meeting/session_details.html
+++ b/ietf/templates/meeting/session_details.html
@@ -12,11 +12,11 @@
     <h2>{{ session.name }}</h2>
   {% endif %}
 
-  {% if session.sessionpresentation_set.all.count %}
+  {% if filtered_sessionpresentation_set %}
     <p>Materials:</p>
 
     <ul>
-      {% for pres in session.sessionpresentation_set.all %}
+      {% for pres in filtered_sessionpresentation_set %}
         <li><a href="{% url 'doc_view' name=pres.document.name rev=pres.rev%}">{{ pres.document.name }}-{{ pres.rev }}</a></li>
       {% endfor %}
     </ul>

From 525ad030abb5ebd153447dd20c89ffc02071cfed Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 4 May 2015 13:09:41 +0000
Subject: [PATCH 11/15] some tweaks to the history  - Legacy-Id: 9597

---
 ietf/meeting/migrations/0006_auto_20150318_1116.py |  9 ++++++---
 ietf/meeting/migrations/0011_ietf92_meetings.py    | 10 +++++++---
 2 files changed, 13 insertions(+), 6 deletions(-)

diff --git a/ietf/meeting/migrations/0006_auto_20150318_1116.py b/ietf/meeting/migrations/0006_auto_20150318_1116.py
index b61bb3c8c..1049d26d9 100644
--- a/ietf/meeting/migrations/0006_auto_20150318_1116.py
+++ b/ietf/meeting/migrations/0006_auto_20150318_1116.py
@@ -60,7 +60,8 @@ def backfill_91_other_meetings(apps, schema_editor):
                     (  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, 11, 30,  150, 'lead',      [iesg],     south_pacific_2, 'Lunch', 'IESG Lunch with the IAB'),
+                    (  9, 11, 30,  150, 'lead',      [iab],      south_pacific_2, 'Lunch', 'IAB Lunch with the IESG'),
                     (  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'),
@@ -69,7 +70,8 @@ def backfill_91_other_meetings(apps, schema_editor):
                     (  9, 19,  0,  180, 'offagenda', [secr],     lehua_suite,     'Meeting', 'Huawei'),
                     (  9, 21,  0,  180, 'lead',      [secr],     sea_pearl_12,    'Gathering', 'AMS/IESG/IAB/IAOC 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',      [iesg],     south_pacific_2, 'Breakfast', 'IESG Breakfast with the IAB'),
+                    ( 10,  7,  0,  120, 'lead',      [iab],      south_pacific_2, 'Breakfast', 'IAB Breakfast with the IESG'),
                     ( 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'),
@@ -103,7 +105,8 @@ def backfill_91_other_meetings(apps, schema_editor):
                     ( 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, 13, 30,   90, 'lead',      [iesg],     south_pacific_2, 'Lunch', 'IESG Lunch with the IAB'),
+                    ( 14, 13, 30,   90, 'lead',      [iab],      south_pacific_2, 'Lunch', 'IAB Lunch with the IESG'),
                     ( 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'),
diff --git a/ietf/meeting/migrations/0011_ietf92_meetings.py b/ietf/meeting/migrations/0011_ietf92_meetings.py
index 7d61d205a..20b20caa6 100644
--- a/ietf/meeting/migrations/0011_ietf92_meetings.py
+++ b/ietf/meeting/migrations/0011_ietf92_meetings.py
@@ -103,7 +103,8 @@ def backfill_92_other_meetings(apps, schema_editor):
                     ( 22, 19,  0,  120, 'offagenda', [iab],      florentine,      'Meeting', 'IAB PrivSec program'),
                     ( 22,  8, 30,   90, 'lead',      [iesg],     pavilion,        'Breakfast', None),
                     ( 22,  9,  0,  150, 'lead',      [iesg],     pavilion,        'Meeting', None),
-                    ( 22, 11, 30,  150, 'lead',      [iab,iesg], pavilion,        'Lunch', 'IESG/IAB Lunch'),
+                    ( 22, 11, 30,  150, 'lead',      [iab],      pavilion,        'Lunch', 'IAB Lunch with the IESG'),
+                    ( 22, 11, 30,  150, 'lead',      [iesg],     pavilion,        'Lunch', 'IESG Lunch with the IAB'),
                     ( 22, 14,  0,  180, 'lead',      [iab],      pavilion,        'Meeting', None),
                     ( 22,  9,  0,  480, 'offagenda', [secr],     terrace,         'Meeting', 'RootOPS'),
                     ( 22, 16, 30,   60, 'offagenda', [secr],     panorama,        'Reception', "Companion's Reception"), # Should this appear on agenda?
@@ -117,7 +118,8 @@ def backfill_92_other_meetings(apps, schema_editor):
                     ( 23,  8,  0,  600, 'offagenda', [secr],     regency_foyer,   'T-Shirt Distribution', 'T-shirt Distribution'),
                     ( 23,  0,  0, 1440, 'offagenda', [secr],     regency,         'Lounge', 'Lounge'),
                     ( 23, 11, 30,  180, 'offagenda', [secr],     executive,       'Lunch', 'ICANN Lunch'),
-                    ( 23,  7,  0,  120, 'lead',      [iab,iesg], pavilion,        'Breakfast', 'IESG/IAB Breakfast'),
+                    ( 23,  7,  0,  120, 'lead',      [iesg],     pavilion,        'Breakfast', 'IESG Breakfast with the IAB'),
+                    ( 23,  7,  0,  120, 'lead',      [iab],      pavilion,        'Breakfast', 'IAB Breakfast with the IESG'),
                     ( 23, 11, 30,   90, 'offagenda', [secr],     pavilion,        'Meeting', 'OPS Directorate Meeting'),
                     ( 23, 19,  0,  120, 'offagenda', [secr],     pavilion,        'Meeting', 'ACE'),
                     ( 23,  7, 30,   90, 'offagenda', [secr],     terrace,         'Meeting', 'NRO ECG'),
@@ -162,7 +164,9 @@ def backfill_92_other_meetings(apps, schema_editor):
                     ( 26, 19, 30,  150, 'offagenda', [secr],     royal,           'Meeting', 'Lavabit'),
                     ( 27,  0,  0,  900, 'offagenda', [secr],     brasserie,       'Terminal Room', 'Terminal Room Open to Attendees'),
                     ( 27,  7, 30,   90, 'offagenda', [secr],     executive,       'Meeting', 'Post-Con with Ray'),
-                    ( 27, 13, 30,   90, 'lead',      [iab,iesg], pavilion,        'Lunch', 'IESG/IAB Lunch'),
+                    ( 27,  7, 30,   75, 'offagenda', [secr],     state,           'Breakfast', 'Gen-art'),
+                    ( 27, 13, 30,   90, 'lead',      [iab],      pavilion,        'Lunch', 'IAB Lunch with the IESG'),
+                    ( 27, 13, 30,   90, 'lead',      [iesg],     pavilion,        'Lunch', 'IESG Lunch with the IAB'),
                    ]:
 
                 ts = ietf92.timeslot_set.create(type_id=type_id, name=slotname, 

From 0ba095e229f8667f34ab3f8188c3e2c9c1ef87e5 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 4 May 2015 13:25:57 +0000
Subject: [PATCH 12/15] remove some dead code  - Legacy-Id: 9598

---
 ietf/meeting/helpers.py | 11 -----------
 ietf/meeting/views.py   |  2 --
 2 files changed, 13 deletions(-)

diff --git a/ietf/meeting/helpers.py b/ietf/meeting/helpers.py
index 24a697b17..bac9695b3 100644
--- a/ietf/meeting/helpers.py
+++ b/ietf/meeting/helpers.py
@@ -66,12 +66,7 @@ def build_all_agenda_slices(meeting):
     time_slices = []
     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','lead','offagenda','other']).order_by('time','name'):
     for ts in meeting.timeslot_set.filter(type__in=['session',]).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:
@@ -85,12 +80,6 @@ def build_all_agenda_slices(meeting):
     time_slices.sort()
     return time_slices,date_slices
 
-# Not Used
-#def get_scheduledsessions_from_schedule(schedule):
-#   ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False).exclude(session__isnull = True).order_by('timeslot__time','timeslot__name','session__group__group')
-#
-#   return ss
-
 def get_all_scheduledsessions_from_schedule(schedule):
    ss = schedule.scheduledsession_set.filter(timeslot__location__isnull = False)
    ss = ss.filter(session__type__slug='session')
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index a5c202599..5da690c45 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -259,8 +259,6 @@ def edit_agenda(request, num=None, owner=None, name=None):
     meeting_base_url = request.build_absolute_uri(meeting.base_url())
     site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash
 
-    #rooms = meeting.room_set.order_by("capacity")
-    #rooms = rooms.all()
     rooms = meeting.room_set.filter(session_types__slug='session').distinct().order_by("capacity")
     saveas = SaveAsForm()
     saveasurl=reverse(edit_agenda,

From 3bf1beb0300a70b0247708a265a14520d3656600 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 4 May 2015 15:10:18 +0000
Subject: [PATCH 13/15] fix a bug discovered with adhoc testing  - Legacy-Id:
 9599

---
 ietf/secr/meetings/views.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py
index 8b0ae1c98..7a66eb622 100644
--- a/ietf/secr/meetings/views.py
+++ b/ietf/secr/meetings/views.py
@@ -55,7 +55,7 @@ def build_timeslots(meeting,room=None):
     slots = meeting.timeslot_set.filter(type='session')
 
     # Don't do anything if the room is not capable of handling sessions
-    if not room.session_types.filter(slug='session'):
+    if room and not room.session_types.filter(slug='session'):
         return
 
     if room:

From 4e1b3b2888a8c5a723f64d323403a5095809ae47 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 4 May 2015 15:10:34 +0000
Subject: [PATCH 14/15] let the IAB see the new pages  - Legacy-Id: 9600

---
 .../migrations/0005_auto_20150504_0726.py     | 42 +++++++++++++++++++
 ietf/ietfauth/utils.py                        |  1 +
 ietf/meeting/views.py                         |  7 ++--
 3 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 ietf/group/migrations/0005_auto_20150504_0726.py

diff --git a/ietf/group/migrations/0005_auto_20150504_0726.py b/ietf/group/migrations/0005_auto_20150504_0726.py
new file mode 100644
index 000000000..ce53f1bc0
--- /dev/null
+++ b/ietf/group/migrations/0005_auto_20150504_0726.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+def create_iab_roles(apps, schema_editor):
+    Role = apps.get_model('group','Role')
+    Group = apps.get_model('group','Group')
+    Person = apps.get_model('person','Person')
+
+    iab = Group.objects.get(acronym='iab')
+
+    iab_names = [
+                  'Jari Arkko',
+                  'Mary Barnes',
+                  'Marc Blanchet',
+                  'Ralph Droms',
+                  'Ted Hardie',
+                  'Joe Hildebrand',
+                  'Russ Housley',
+                  'Erik Nordmark',
+                  'Robert Sparks',
+                  'Andrew Sullivan',
+                  'Dave Thaler',
+                  'Brian Trammell',
+                  'Suzanne Woolf',
+                ]
+   
+    for name in iab_names:
+        person = Person.objects.get(name=name)
+        person.role_set.add(Role(name_id='member',group=iab,person=person,email_id=person.email_set.filter(active=True).order_by('-time').first().address))
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('group', '0004_auto_20150430_0847'),
+    ]
+
+    operations = [
+        migrations.RunPython(create_iab_roles),
+    ]
diff --git a/ietf/ietfauth/utils.py b/ietf/ietfauth/utils.py
index f871bc006..fc9647093 100644
--- a/ietf/ietfauth/utils.py
+++ b/ietf/ietfauth/utils.py
@@ -46,6 +46,7 @@ def has_role(user, role_names, *args, **kwargs):
         role_qs = {
 	    "Area Director": Q(person=person, name__in=("pre-ad", "ad"), group__type="area", group__state="active"),
 	    "Secretariat": Q(person=person, name="secr", group__acronym="secretariat"),
+            "IAB" : Q(person=person, name="member", group__acronym="iab"),
 	    "IANA": Q(person=person, name="auth", group__acronym="iana"),
             "RFC Editor": Q(person=person, name="auth", group__acronym="rfceditor"),
             "ISE" : Q(person=person, name="chair", group__acronym="ise"),
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 5da690c45..52c8d7562 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -384,8 +384,7 @@ def agenda(request, num=None, name=None, base=None, ext=None):
     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')
+@role_required('Area Director','Secretariat','IAB')
 def agenda_by_room(request,num=None):
     meeting = get_meeting(num) 
     schedule = get_schedule(meeting)
@@ -397,7 +396,7 @@ def agenda_by_room(request,num=None):
         ss_by_day[day].append(ss)
     return render(request,"meeting/agenda_by_room.html",{"meeting":meeting,"ss_by_day":ss_by_day})
 
-@role_required('Area Director','Secretariat')
+@role_required('Area Director','Secretariat','IAB')
 def agenda_by_type(request,num=None,type=None):
     meeting = get_meeting(num) 
     schedule = get_schedule(meeting)
@@ -406,7 +405,7 @@ def agenda_by_type(request,num=None,type=None):
         scheduledsessions = scheduledsessions.filter(session__type__slug=type)
     return render(request,"meeting/agenda_by_type.html",{"meeting":meeting,"scheduledsessions":scheduledsessions})
 
-@role_required('Area Director','Secretariat')
+@role_required('Area Director','Secretariat','IAB')
 def agenda_by_type_ics(request,num=None,type=None):
     meeting = get_meeting(num) 
     schedule = get_schedule(meeting)

From 547a1ae7a81fd09763c043f17844caf1ccbda149 Mon Sep 17 00:00:00 2001
From: Robert Sparks <rjsparks@nostrum.com>
Date: Mon, 4 May 2015 15:36:00 +0000
Subject: [PATCH 15/15] deflake  - Legacy-Id: 9601

---
 ietf/group/migrations/0005_auto_20150504_0726.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ietf/group/migrations/0005_auto_20150504_0726.py b/ietf/group/migrations/0005_auto_20150504_0726.py
index ce53f1bc0..5690ad9f4 100644
--- a/ietf/group/migrations/0005_auto_20150504_0726.py
+++ b/ietf/group/migrations/0005_auto_20150504_0726.py
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 from __future__ import unicode_literals
 
-from django.db import models, migrations
+from django.db import migrations
 
 def create_iab_roles(apps, schema_editor):
     Role = apps.get_model('group','Role')