Merged in [9603] from rjsparks@nostrum.com:

Added functionality which allows the secretariat to manage more meeting types, including leadership meetings.
Backfilled those types of meetings from IETF91 and IETF92.
Addressed several facelift issues in the meeting application.
 - Legacy-Id: 9606
Note: SVN reference [9603] has been migrated to Git commit a85424ad23
This commit is contained in:
Henrik Levkowetz 2015-05-06 18:07:18 +00:00
commit 1ba8996fd2
36 changed files with 876 additions and 75 deletions

View file

@ -22,8 +22,8 @@ scheduled = SessionStatusName.objects.get(slug='sched')
for meeting in Meeting.objects.filter(type="ietf").order_by("date"): for meeting in Meeting.objects.filter(type="ietf").order_by("date"):
print "Checking %s schedules ..." % meeting print "Checking %s schedules ..." % meeting
brk, __ = Session.objects.get_or_create(meeting=meeting, group=secretariat, requested_by=system, status=scheduled, name='Break', ) 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', ) 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(): for schedule in meeting.schedule_set.all():
print " Checking for missing Break and Reg sessions in %s" % schedule print " Checking for missing Break and Reg sessions in %s" % schedule

View file

@ -527,6 +527,7 @@ class DocTestCase(TestCase):
status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'), status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'),
modified = datetime.datetime.now(), modified = datetime.datetime.now(),
requested_by = Person.objects.get(user__username="marschairman"), requested_by = Person.objects.get(user__username="marschairman"),
type_id = "session",
) )
SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev) SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev)

View file

@ -148,6 +148,7 @@ class GroupMaterialTests(TestCase):
status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'), status = SessionStatusName.objects.create(slug='scheduled', name='Scheduled'),
modified = datetime.datetime.now(), modified = datetime.datetime.now(),
requested_by = Person.objects.get(user__username="marschairman"), requested_by = Person.objects.get(user__username="marschairman"),
type_id="session",
) )
SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev) SessionPresentation.objects.create(session=session, document=doc, rev=doc.rev)

View file

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import 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),
]

View file

@ -46,6 +46,7 @@ def has_role(user, role_names, *args, **kwargs):
role_qs = { role_qs = {
"Area Director": Q(person=person, name__in=("pre-ad", "ad"), group__type="area", group__state="active"), "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"), "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"), "IANA": Q(person=person, name="auth", group__acronym="iana"),
"RFC Editor": Q(person=person, name="auth", group__acronym="rfceditor"), "RFC Editor": Q(person=person, name="auth", group__acronym="rfceditor"),
"ISE" : Q(person=person, name="chair", group__acronym="ise"), "ISE" : Q(person=person, name="chair", group__acronym="ise"),

View file

@ -158,6 +158,8 @@ AddSlotForm = modelform_factory(TimeSlot, exclude=('meeting','name','location','
# no authorization required to list. # no authorization required to list.
def timeslot_slotlist(request, mtg): def timeslot_slotlist(request, mtg):
slots = mtg.timeslot_set.all() slots = mtg.timeslot_set.all()
# Restrict graphical editing to slots of type 'session' for now
slots = slots.filter(type__slug='session')
json_array=[] json_array=[]
for slot in slots: for slot in slots:
json_array.append(slot.json_dict(request.build_absolute_uri('/'))) json_array.append(slot.json_dict(request.build_absolute_uri('/')))

View file

@ -66,7 +66,7 @@ def build_all_agenda_slices(meeting):
time_slices = [] time_slices = []
date_slices = {} date_slices = {}
for ts in meeting.timeslot_set.exclude(type__in=['reg','break']).order_by('time','name'): for ts in meeting.timeslot_set.filter(type__in=['session',]).order_by('time','name'):
ymd = ts.time.date() ymd = ts.time.date()
if ymd not in date_slices and ts.location != None: if ymd not in date_slices and ts.location != None:
@ -80,13 +80,10 @@ def build_all_agenda_slices(meeting):
time_slices.sort() time_slices.sort()
return time_slices,date_slices 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
def get_all_scheduledsessions_from_schedule(schedule): 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 return ss

View file

@ -0,0 +1,144 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import datetime
from django.db import migrations
def backfill_91_other_meetings(apps, schema_editor):
Meeting = apps.get_model('meeting', 'Meeting')
Schedule = apps.get_model('meeting', 'Schedule')
ScheduledSession = apps.get_model('meeting', 'ScheduledSession')
Room = apps.get_model('meeting', 'Room')
Group = apps.get_model('group', 'Group')
Person = apps.get_model('person', 'Person')
ietf91 = Meeting.objects.filter(number=91).first()
if not ietf91:
print "IETF91 not found, no data changed"
else:
agenda91 = Schedule.objects.get(meeting=ietf91,pk=ietf91.agenda.pk)
south_pacific_1 = Room.objects.get(meeting=ietf91,name="South Pacific 1")
south_pacific_2 = Room.objects.get(meeting=ietf91,name="South Pacific 2")
rainbow_12 = Room.objects.get(meeting=ietf91,name="Rainbow Suite 1/2")
lehua_suite = Room.objects.get(meeting=ietf91,name="Lehua Suite")
kahili = Room.objects.get(meeting=ietf91,name="Kahili")
coral_2 = Room.objects.get(meeting=ietf91,name="Coral 2")
south_pacific_3 = Room.objects.create(meeting=ietf91,name="South Pacific 3",capacity=20)
rainbow_suite_3 = Room.objects.create(meeting=ietf91,name="Rainbow Suite 3",capacity=20)
rainbow_23 = Room.objects.create(meeting=ietf91,name="Rainbow Suite 2/3",capacity=210)
south_pacific_34 = Room.objects.create(meeting=ietf91,name="South Pacific 3/4",capacity=210)
iolani_67 = Room.objects.create(meeting=ietf91,name="Iolani 6/7",capacity=40)
sea_pearl_12 = Room.objects.create(meeting=ietf91,name="Sea Pearl 1/2",capacity=40)
sea_pearl_2 = Room.objects.create(meeting=ietf91,name="Sea Pearl 2",capacity=20)
coral_lounge = Room.objects.create(meeting=ietf91,name="Coral Lounge", capacity=1200)
hibiscus = Room.objects.create(meeting=ietf91,name="Hibiscus", capacity=20)
tiare = Room.objects.create(meeting=ietf91,name="Tiare Suite", capacity=20)
iesg = Group.objects.get(acronym='iesg')
iab = Group.objects.get(acronym='iab')
rsoc = Group.objects.get(acronym='rsoc')
iaoc = Group.objects.get(acronym='iaoc')
nomcom = Group.objects.get(acronym='nomcom2014')
isoc = Group.objects.get(acronym='isoc')
secr = Group.objects.get(acronym='secretariat')
isocbot = Group.objects.create(acronym='isocbot',name="Internet Society Board of Trustees",state_id='active',type_id='isoc',parent=isoc)
isocfell = Group.objects.create(acronym='isocfell',name="Internet Society Fellows",state_id='active',type_id='isoc',parent=isoc)
system = Person.objects.get(name='(System)')
for d, h, m, duration, type_id, groups, room, slotname, label in [
( 9, 8, 0, 120, 'offagenda', [secr], rainbow_suite_3, 'WEIRDS Interop', 'WEIRDS Interop'),
( 9, 8, 30, 90, 'lead', [iesg], south_pacific_2, 'Breakfast', None),
( 9, 9, 0, 240, 'offagenda', [secr], lehua_suite, 'RMCAT Interim', 'RMCAT Interim Meeting'),
( 9, 9, 0, 60, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'),
( 9, 9, 0, 150, 'lead', [iesg], south_pacific_2, 'Meeting', None),
( 9, 9, 0, 360, 'offagenda', [secr], hibiscus, 'Meeting', 'RootOPS'),
( 9, 9, 30, 360, 'offagenda', [secr], kahili, 'TLS Interim', 'TLS WG Interim'),
( 9, 11, 0, 480, 'offagenda', [secr], coral_lounge, 'T-Shirt Distribution', 'T-shirt Distribution'),
( 9, 11, 30, 150, 'lead', [iesg], 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'),
( 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/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], 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'),
( 10, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Meeting', 'IETF/3GPP Meeting'),
( 10, 11, 30, 90, 'offagenda', [secr], lehua_suite, 'Meeting', 'RTG Area Meeting'),
( 10, 19, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'Huawei'),
( 11, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'),
( 11, 7, 0, 120, 'lead', [iesg], south_pacific_2, 'Breakfast', None),
( 11, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'),
( 11, 7, 0, 120, 'lead', [iab], rainbow_suite_3, 'Breakfast', None),
( 11, 7, 0, 60, 'lead', [iab], tiare, 'Meeting', 'Vendor Selection Committee Meeting'),
( 11, 8, 0, 600, 'offagenda', [secr], coral_lounge, 'T-shirt Distribution', 'T-shirt Distribution'),
( 11, 9, 0, 90, 'offagenda', [secr], south_pacific_2, 'Meeting', 'DHCPv6bis Team Meeting'),
( 11, 11, 30, 90, 'offagenda', [secr], south_pacific_2, 'Meeting', 'SECdir Meeting'),
( 11, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Lunch', 'RSAG/ISEB Lunch'),
( 11, 16, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'Verisign Corporate Meeting'),
( 12, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'),
( 12, 7, 30, 90, 'lead', [iaoc], south_pacific_3, 'Breakfast', None),
( 12, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'),
( 12, 8, 0, 540, 'offagenda', [secr], coral_lounge, 'T-shirt Distribution', 'T-shirt Distribution'),
( 12, 8, 0, 240, 'offagenda', [secr], south_pacific_2, 'Meeting', 'DIME WG'),
( 12, 11, 30, 90, 'offagenda', [secr], rainbow_suite_3, 'Lunch', 'RFC Editor Lunch'),
( 12, 15, 0, 120, 'offagenda', [secr], south_pacific_2, 'Meeting', 'YANG Advice'),
( 12, 17, 0, 240, 'offagenda', [secr], rainbow_suite_3, 'Meeting', 'Huawei (POC Wil Liu)'),
( 12, 20, 0, 150, 'offagenda', [secr], south_pacific_2, 'Meeting', 'ICANN SSAC'),
( 13, 0, 0, 1440, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'),
( 13, 7, 0, 120, 'lead', [iab], rainbow_suite_3, 'Breakfast', None),
( 13, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'),
( 13, 11, 30, 90, 'lead', [iab], sea_pearl_2, 'Meeting', 'IAB Liaison Oversight'),
( 13, 11, 30, 90, 'lead', [rsoc], rainbow_suite_3, 'Lunch', None),
( 14, 0, 0, 900, 'offagenda', [secr], south_pacific_1, 'Terminal Room', 'Terminal Room Open to Attendees'),
( 14, 7, 0, 120, 'lead', [nomcom], iolani_67, 'Breakfast', 'Nomcom Breakfast'),
( 14, 11, 0, 360, 'offagenda', [isoc], south_pacific_34,'Meeeting', 'ISOC AC Meeting'),
( 14, 13, 30, 90, 'lead', [iesg], 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'),
( 15, 8, 0, 540, 'offagenda', [isocbot], south_pacific_34,'Meeting', 'ISOC Board of Trustees Meeting'),
( 15, 12, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Lunch', 'ISOC Board of Trustees Lunch'),
( 16, 8, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Breakfast', 'ISOC Board of Trustees Breakfast'),
( 16, 8, 0, 540, 'offagenda', [isocbot], south_pacific_34,'Meeting', 'ISOC Board of Trustees Meeting'),
( 16, 12, 0, 60, 'offagenda', [isocbot], rainbow_12, 'Lunch', 'ISOC Board of Trustees Lunch'),
]:
ts = ietf91.timeslot_set.create(type_id=type_id, name=slotname,
time=datetime.datetime(2014,11,d,h,m,0),
duration=datetime.timedelta(minutes=duration),
location=room,show_location=(type_id not in ['lead','offagenda']))
for group in groups:
session = ietf91.session_set.create(name= label or "%s %s"%(group.acronym.upper(),slotname),
group=group, attendees=25,
requested=datetime.datetime(2014,11,1,0,0,0),
requested_by=system, status_id='sched')
ScheduledSession.objects.create(schedule=agenda91, timeslot=ts, session=session)
class Migration(migrations.Migration):
dependencies = [
('meeting', '0005_auto_20150430_0847'),
('name', '0004_auto_20150318_1140'),
('group', '0004_auto_20150430_0847'),
('person', '0004_auto_20150308_0440'),
]
operations = [
migrations.RunPython(backfill_91_other_meetings)
]

View file

@ -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', '0006_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),
]

View file

@ -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', '0007_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),
]

View file

@ -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,
),
]

View file

@ -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),
]

View file

@ -0,0 +1,195 @@
# -*- 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], 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?
( 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', [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'),
( 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, 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,
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)
]

View file

@ -161,7 +161,10 @@ class Meeting(models.Model):
@property @property
def sessions_that_can_meet(self): 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): def sessions_that_can_be_placed(self):
from django.db.models import Q from django.db.models import Q
@ -284,8 +287,10 @@ class ResourceAssociation(models.Model):
class Room(models.Model): class Room(models.Model):
meeting = models.ForeignKey(Meeting) meeting = models.ForeignKey(Meeting)
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
functional_name = models.CharField(max_length=255, blank = True)
capacity = models.IntegerField(null=True, blank=True) capacity = models.IntegerField(null=True, blank=True)
resources = models.ManyToManyField(ResourceAssociation, blank = True) resources = models.ManyToManyField(ResourceAssociation, blank = True)
session_types = models.ManyToManyField(TimeSlotTypeName, blank = True)
def __unicode__(self): def __unicode__(self):
return "%s size: %s" % (self.name, self.capacity) return "%s size: %s" % (self.name, self.capacity)
@ -370,7 +375,8 @@ 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) 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): def end_time(self):
return self.time + self.duration return self.time + self.duration
def get_location(self):
def get_hidden_location(self):
location = self.location location = self.location
if location: if location:
location = location.name location = location.name
@ -378,10 +384,24 @@ class TimeSlot(models.Model):
location = self.meeting.reg_area location = self.meeting.reg_area
elif self.type_id == "break": elif self.type_id == "break":
location = self.meeting.break_area location = self.meeting.break_area
return location
def get_location(self):
location = self.get_hidden_location()
if not self.show_location: if not self.show_location:
location = "" location = ""
return 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 @property
def tz(self): def tz(self):
if self.meeting.time_zone: if self.meeting.time_zone:
@ -626,8 +646,7 @@ class Schedule(models.Model):
.distinct() ) .distinct() )
def groups(self): def groups(self):
return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], parent__isnull=False, return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], parent__isnull=False, session__scheduledsession__schedule=self).exclude(session__scheduledsession__timeslot__type__in=['lead','offagenda']).distinct().order_by('parent__acronym', 'acronym')
session__scheduledsession__schedule=self).distinct().order_by('parent__acronym', 'acronym')
# calculate badness of entire schedule # calculate badness of entire schedule
def calc_badness(self): def calc_badness(self):
@ -848,7 +867,8 @@ class Session(models.Model):
meeting = models.ForeignKey(Meeting) 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.") 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.") 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) attendees = models.IntegerField(null=True, blank=True)
agenda_note = models.CharField(blank=True, max_length=255) agenda_note = models.CharField(blank=True, max_length=255)
requested = models.DateTimeField(default=datetime.datetime.now) requested = models.DateTimeField(default=datetime.datetime.now)
@ -1004,7 +1024,13 @@ class Session(models.Model):
else: else:
return "The agenda has not been uploaded yet." 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" ]: if self.group.type.slug in [ "wg" ]:
return "BOF" if self.group.state.slug in ["bof", "bof-conc"] else "WG" return "BOF" if self.group.state.slug in ["bof", "bof-conc"] else "WG"
else: else:

View file

@ -20,6 +20,9 @@ def make_meeting_test_data():
pname = RoomResourceName.objects.create(name='projector',slug='proj') pname = RoomResourceName.objects.create(name='projector',slug='proj')
projector = ResourceAssociation.objects.create(name=pname,icon="notfound.png",desc="Basic projector") projector = ResourceAssociation.objects.create(name=pname,icon="notfound.png",desc="Basic projector")
room = Room.objects.create(meeting=meeting, name="Test Room", capacity=123) 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] room.resources = [projector]
# mars WG # mars WG
@ -29,7 +32,7 @@ def make_meeting_test_data():
mars_session = Session.objects.create(meeting=meeting, group=mars, mars_session = Session.objects.create(meeting=meeting, group=mars,
attendees=10, requested_by=system_person, attendees=10, requested_by=system_person,
requested_duration=20, status_id="schedw", requested_duration=20, status_id="schedw",
scheduled=datetime.datetime.now()) scheduled=datetime.datetime.now(),type_id="session")
mars_session.resources = [projector] mars_session.resources = [projector]
ScheduledSession.objects.create(timeslot=slot, session=mars_session, schedule=schedule) ScheduledSession.objects.create(timeslot=slot, session=mars_session, schedule=schedule)
@ -39,26 +42,37 @@ def make_meeting_test_data():
ames_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="ames"), ames_session = Session.objects.create(meeting=meeting, group=Group.objects.get(acronym="ames"),
attendees=10, requested_by=system_person, attendees=10, requested_by=system_person,
requested_duration=20, status_id="schedw", 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) 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(),type_id="lead")
ScheduledSession.objects.create(timeslot=breakfast_slot, session=iesg_session, schedule=schedule)
meeting.agenda = schedule meeting.agenda = schedule
meeting.save() 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")) 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)) 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")) 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)) 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=doc.type_id, slug="active"))
doc.set_state(State.objects.get(type='reuse_policy',slug='single')) 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)) 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=doc.type_id, slug="deleted"))
doc.set_state(State.objects.get(type='reuse_policy',slug='single')) 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)) mars_session.sessionpresentation_set.add(SessionPresentation(session=mars_session,document=doc,rev=doc.rev))

View file

@ -138,7 +138,7 @@ class ApiTests(TestCase):
timeslots_before = meeting.timeslot_set.count() timeslots_before = meeting.timeslot_set.count()
url = urlreverse("ietf.meeting.ajax.timeslot_roomsurl", kwargs=dict(num=meeting.number)) 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 # unauthorized post
r = self.client.post(url, post_data) r = self.client.post(url, post_data)
@ -152,7 +152,10 @@ class ApiTests(TestCase):
self.assertTrue(meeting.room_set.filter(name="new room")) self.assertTrue(meeting.room_set.filter(name="new room"))
timeslots_after = meeting.timeslot_set.count() timeslots_after = meeting.timeslot_set.count()
self.assertEqual((timeslots_after - timeslots_before), (meeting.room_set.count() - 1) * timeslots_before) # It's not clear that what that ajax function is doing is the right thing to do,
# but it currently makes a new timeslot for any existing timeslot.
# The condition tested below relies on the timeslots before this test all having different start and end times
self.assertEqual( timeslots_after, 2 * timeslots_before)
def test_delete_room(self): def test_delete_room(self):
meeting = make_meeting_test_data() meeting = make_meeting_test_data()
@ -201,7 +204,7 @@ class ApiTests(TestCase):
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
info = json.loads(r.content) info = json.loads(r.content)
self.assertEqual(set([x['short_name'] for x in info]),set(['mars','ames'])) self.assertEqual(set([x['short_name'] for x in info]),set([s.session.short_name for s in meeting.agenda.scheduledsession_set.filter(session__type_id='session')]))
schedule = meeting.agenda schedule = meeting.agenda
url = urlreverse("ietf.meeting.ajax.scheduledsessions_json", url = urlreverse("ietf.meeting.ajax.scheduledsessions_json",
@ -209,7 +212,7 @@ class ApiTests(TestCase):
r = self.client.get(url) r = self.client.get(url)
self.assertEqual(r.status_code, 200) self.assertEqual(r.status_code, 200)
info = json.loads(r.content) info = json.loads(r.content)
self.assertEqual(len(info),2) self.assertEqual(len(info),schedule.scheduledsession_set.count())
def test_slot_json(self): def test_slot_json(self):

View file

@ -11,7 +11,7 @@ from pyquery import PyQuery
from ietf.doc.models import Document from ietf.doc.models import Document
from ietf.meeting.models import Session, TimeSlot from ietf.meeting.models import Session, TimeSlot
from ietf.meeting.test_data import make_meeting_test_data 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): class MeetingTests(TestCase):
def setUp(self): def setUp(self):
@ -124,6 +124,38 @@ class MeetingTests(TestCase):
self.assertTrue(session.group.acronym in agenda_content) self.assertTrue(session.group.acronym in agenda_content)
self.assertTrue(slot.location.name 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)
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): def test_materials(self):
meeting = make_meeting_test_data() meeting = make_meeting_test_data()
session = Session.objects.filter(meeting=meeting, group__acronym="mars").first() session = Session.objects.filter(meeting=meeting, group__acronym="mars").first()

View file

@ -33,6 +33,10 @@ urlpatterns = patterns('',
(r'^(?P<num>\d+)/agenda(?P<ext>.txt)$', views.agenda), (r'^(?P<num>\d+)/agenda(?P<ext>.txt)$', views.agenda),
(r'^(?P<num>\d+)/agenda.ics$', views.ical_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(?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+)/agendas/edit$', views.edit_agendas),
(r'^(?P<num>\d+)/timeslots/edit$', views.edit_timeslots), (r'^(?P<num>\d+)/timeslots/edit$', views.edit_timeslots),
(r'^(?P<num>\d+)/rooms$', ajax.timeslot_roomsurl), (r'^(?P<num>\d+)/rooms$', ajax.timeslot_roomsurl),

View file

@ -6,6 +6,7 @@ import re
import tarfile import tarfile
import urllib import urllib
from tempfile import mkstemp from tempfile import mkstemp
from collections import OrderedDict
import debug # pyflakes:ignore import debug # pyflakes:ignore
@ -258,8 +259,7 @@ def edit_agenda(request, num=None, owner=None, name=None):
meeting_base_url = request.build_absolute_uri(meeting.base_url()) meeting_base_url = request.build_absolute_uri(meeting.base_url())
site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash
rooms = meeting.room_set.order_by("capacity") rooms = meeting.room_set.filter(session_types__slug='session').distinct().order_by("capacity")
rooms = rooms.all()
saveas = SaveAsForm() saveas = SaveAsForm()
saveasurl=reverse(edit_agenda, saveasurl=reverse(edit_agenda,
args=[meeting.number, schedule.owner_email(), schedule.name]) args=[meeting.number, schedule.owner_email(), schedule.name])
@ -367,6 +367,7 @@ def edit_agendas(request, num=None, order=None):
def agenda(request, num=None, name=None, base=None, ext=None): def agenda(request, num=None, name=None, base=None, ext=None):
base = base if base else 'agenda' base = base if base else 'agenda'
ext = ext if ext else '.html' ext = ext if ext else '.html'
# This is misleading - urls.py doesn't send ics through here anymore
mimetype = { mimetype = {
".html":"text/html; charset=%s"%settings.DEFAULT_CHARSET, ".html":"text/html; charset=%s"%settings.DEFAULT_CHARSET,
".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET, ".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET,
@ -380,7 +381,39 @@ def agenda(request, num=None, name=None, base=None, ext=None):
return render(request, "meeting/no-"+base+ext, {'meeting':meeting }, content_type=mimetype[ext]) return render(request, "meeting/no-"+base+ext, {'meeting':meeting }, content_type=mimetype[ext])
updated = meeting_updated(meeting) updated = meeting_updated(meeting)
return render(request, "meeting/"+base+ext, {"schedule":schedule, "updated": updated}, content_type=mimetype[ext]) filtered_assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda'])
return render(request, "meeting/"+base+ext, {"schedule":schedule, "filtered_assignments":filtered_assignments, "updated": updated}, content_type=mimetype[ext])
@role_required('Area Director','Secretariat','IAB')
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__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})
@role_required('Area Director','Secretariat','IAB')
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','IAB')
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): def read_agenda_file(num, doc):
# XXXX FIXME: the path fragment in the code below should be moved to # XXXX FIXME: the path fragment in the code below should be moved to
@ -611,7 +644,7 @@ def ical_agenda(request, num=None, name=None, ext=None):
elif item[0] == '~': elif item[0] == '~':
include_types |= set([item[1:]]) 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(timeslot__type__slug__in = include_types) |
Q(session__group__acronym__in = include) | Q(session__group__acronym__in = include) |
Q(session__group__parent__acronym__in = include) Q(session__group__parent__acronym__in = include)
@ -626,7 +659,7 @@ def ical_agenda(request, num=None, name=None, ext=None):
def meeting_requests(request, num=None) : def meeting_requests(request, num=None) :
meeting = get_meeting(num) 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") 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")
@ -637,7 +670,7 @@ def meeting_requests(request, num=None) :
def session_details(request, num, acronym, date=None, week_day=None, seq=None) : def session_details(request, num, acronym, date=None, week_day=None, seq=None) :
meeting = get_meeting(num) 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: if not sessions:
sessions = Session.objects.filter(meeting=meeting,short=acronym) sessions = Session.objects.filter(meeting=meeting,short=acronym)
@ -684,11 +717,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') ss = session.scheduledsession_set.filter(schedule=meeting.agenda).order_by('timeslot__time')
if ss: if ss:
scheduled_time = ','.join([x.timeslot.time.strftime("%A %b-%d %H%M") for x in 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", return render(request, "meeting/session_details.html",
{ 'session':sessions[0] , { 'session':sessions[0] ,
'meeting' :meeting , 'meeting' :meeting ,
'acronym' :acronym, 'acronym' :acronym,
'time': scheduled_time, 'time': scheduled_time,
'filtered_sessionpresentation_set': filtered_sessionpresentation_set
}) })
else: else:
return render(request, "meeting/session_list.html", return render(request, "meeting/session_list.html",

View file

@ -1414,7 +1414,7 @@
"order": 0, "order": 0,
"used": true, "used": true,
"name": "None Selected", "name": "None Selected",
"desc": "" "desc": "[None selected]"
}, },
"model": "name.iprlicensetypename", "model": "name.iprlicensetypename",
"pk": "none-selected" "pk": "none-selected"
@ -2079,6 +2079,26 @@
"model": "name.timeslottypename", "model": "name.timeslottypename",
"pk": "reserved" "pk": "reserved"
}, },
{
"fields": {
"order": 0,
"used": true,
"name": "Leadership",
"desc": "Leadership Meetings"
},
"model": "name.timeslottypename",
"pk": "lead"
},
{
"fields": {
"order": 0,
"used": true,
"name": "Off Agenda",
"desc": "Other Meetings Not Published on Agenda"
},
"model": "name.timeslottypename",
"pk": "offagenda"
},
{ {
"fields": { "fields": {
"label": "State" "label": "State"

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def make_new_slot_types(apps, schema_editor):
TimeSlotTypeName = apps.get_model("name","TimeSlotTypeName")
TimeSlotTypeName.objects.create(slug='lead',name='Leadership',desc='Leadership Meetings',used=True)
TimeSlotTypeName.objects.create(slug='offagenda',name='Off Agenda',desc='Other Meetings Not Published on Agenda',used=True)
class Migration(migrations.Migration):
dependencies = [
('name', '0003_fix_ipr_none_selected_choice'),
]
operations = [
migrations.RunPython(make_new_slot_types)
]

View file

@ -179,7 +179,7 @@ class TimeSlotForm(forms.Form):
class NonSessionForm(TimeSlotForm): 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) 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) 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) show_location = forms.BooleanField(required=False)

View file

@ -147,21 +147,21 @@ class MainTestCase(TestCase):
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
q = PyQuery(response.content) q = PyQuery(response.content)
self.assertEqual(len(q("#id_rooms_table tr")),2) self.assertEqual(len(q("#id_rooms_table tr input[type='checkbox']")),meeting.room_set.count())
# test delete # test delete
# first unschedule sessions so we can delete # first unschedule sessions so we can delete
ScheduledSession.objects.filter(schedule=meeting.agenda).delete() ScheduledSession.objects.filter(schedule=meeting.agenda).delete()
self.client.login(username="secretary", password="secretary+password") self.client.login(username="secretary", password="secretary+password")
response = self.client.post(url, { post_dict = {
'room-TOTAL_FORMS': q('input[name="room-TOTAL_FORMS"]').val(), 'room-TOTAL_FORMS': q('input[name="room-TOTAL_FORMS"]').val(),
'room-INITIAL_FORMS': q('input[name="room-INITIAL_FORMS"]').val(), 'room-INITIAL_FORMS': q('input[name="room-INITIAL_FORMS"]').val(),
'room-0-meeting': q('input[name="room-0-meeting"]').val(), }
'room-0-id': q('input[name="room-0-id"]').val(), for i in range(meeting.room_set.count()):
'room-0-name': q('input[name="room-0-name"]').val(), for attr in ['meeting','id','name','capacity','DELETE']:
'room-0-capacity': q('input[name="room-0-capacity"]').val(), key = 'room-%d-%s' % (i,attr)
'room-0-DELETE': 'on' post_dict[key] = q('input[name="%s"]' % key).val()
}) response = self.client.post(url, post_dict)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
self.assertEqual(Room.objects.filter(meeting=meeting).count(),0) self.assertEqual(Room.objects.filter(meeting=meeting).count(),0)
@ -176,6 +176,7 @@ class MainTestCase(TestCase):
meeting = make_meeting_test_data() meeting = make_meeting_test_data()
qs = TimeSlot.objects.filter(meeting=meeting,type='session') qs = TimeSlot.objects.filter(meeting=meeting,type='session')
before = qs.count() before = qs.count()
expected_deletion_count = qs.filter(time=qs.first().time).count()
url = reverse('meetings_times_delete',kwargs={ url = reverse('meetings_times_delete',kwargs={
'meeting_id':42, 'meeting_id':42,
'schedule_name':'test-agenda', 'schedule_name':'test-agenda',
@ -185,7 +186,7 @@ class MainTestCase(TestCase):
response = self.client.get(url) response = self.client.get(url)
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
after = TimeSlot.objects.filter(meeting=meeting,type='session').count() after = TimeSlot.objects.filter(meeting=meeting,type='session').count()
self.assertEqual(after,before - (Room.objects.filter(meeting=meeting).count())) self.assertEqual(after,before - expected_deletion_count)
def test_meetings_times_edit(self): def test_meetings_times_edit(self):
meeting = make_meeting_test_data() meeting = make_meeting_test_data()

View file

@ -53,10 +53,15 @@ def build_timeslots(meeting,room=None):
or adding a room. or adding a room.
''' '''
slots = meeting.timeslot_set.filter(type='session') slots = meeting.timeslot_set.filter(type='session')
# Don't do anything if the room is not capable of handling sessions
if room and not room.session_types.filter(slug='session'):
return
if room: if room:
rooms = [room] rooms = [room]
else: else:
rooms = meeting.room_set.all() rooms = meeting.room_set.filter(session_types__slug='session')
if not slots or room: if not slots or room:
# if we are just building timeslots for a new room, the room argument was passed, # 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 # then we need to use current meeting times as a template, not the last meeting times
@ -95,7 +100,7 @@ def build_nonsession(meeting,schedule):
system = Person.objects.get(name='(system)') system = Person.objects.get(name='(system)')
secretariat = Group.objects.get(acronym='secretariat') 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 new_time = slot.time + delta
session = None session = None
# create Session object for Tutorials to hold materials # create Session object for Tutorials to hold materials
@ -105,13 +110,17 @@ def build_nonsession(meeting,schedule):
short=get_session(slot).short, short=get_session(slot).short,
group=get_session(slot).group, group=get_session(slot).group,
requested_by=system, requested_by=system,
status_id='sched') status_id='sched',
type=slot.type,
)
else: else:
session, __ = Session.objects.get_or_create(meeting=meeting, session, __ = Session.objects.get_or_create(meeting=meeting,
name=slot.name, name=slot.name,
group=secretariat, group=secretariat,
requested_by=system, requested_by=system,
status_id='sched') status_id='sched',
type=slot.type,
)
session.save() session.save()
ts = TimeSlot.objects.create(type=slot.type, ts = TimeSlot.objects.create(type=slot.type,
@ -128,15 +137,17 @@ def check_nonsession(meeting,schedule):
Ensure non-session timeslots exist and have appropriate ScheduledSession objects Ensure non-session timeslots exist and have appropriate ScheduledSession objects
for the specified schedule. for the specified schedule.
''' '''
slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary')) slots = TimeSlot.objects.filter(meeting=meeting,type__in=('break','reg','other','plenary','lead','offagenda'))
if not slots: if not slots:
build_nonsession(meeting,schedule) build_nonsession(meeting,schedule)
return None return None
scheduledsessions = slots.filter(type='plenary').first().scheduledsession_set.all() plenary = slots.filter(type='plenary').first()
if not scheduledsessions.filter(schedule=schedule): if plenary:
source = scheduledsessions.first().schedule scheduledsessions = plenary.scheduledsession_set.all()
copy_scheduledsessions(slots,source,schedule) if not scheduledsessions.filter(schedule=schedule):
source = scheduledsessions.first().schedule
copy_scheduledsessions(slots,source,schedule)
def copy_scheduledsessions(slots,source,target): def copy_scheduledsessions(slots,source,target):
''' '''
@ -435,7 +446,7 @@ def non_session(request, meeting_id, schedule_name):
check_nonsession(meeting,schedule) 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': if request.method == 'POST':
form = NonSessionForm(request.POST) form = NonSessionForm(request.POST)
@ -458,7 +469,7 @@ def non_session(request, meeting_id, schedule_name):
duration=duration, duration=duration,
show_location=form.cleaned_data['show_location']) 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') group = Group.objects.get(acronym='secretariat')
# create associated Session object # create associated Session object
@ -467,7 +478,9 @@ def non_session(request, meeting_id, schedule_name):
short=short, short=short,
group=group, group=group,
requested_by=Person.objects.get(name='(system)'), requested_by=Person.objects.get(name='(system)'),
status_id='sched') status_id='sched',
type=type,
)
session.save() session.save()
# create association # create association
@ -501,7 +514,7 @@ def non_session_delete(request, meeting_id, schedule_name, slot_id):
meeting = get_object_or_404(Meeting, number=meeting_id) meeting = get_object_or_404(Meeting, number=meeting_id)
# schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) # schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name)
slot = get_object_or_404(TimeSlot, id=slot_id) 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) scheduledsessions = slot.scheduledsession_set.filter(schedule__meeting=meeting)
session_objects = [ x.session for x in scheduledsessions ] session_objects = [ x.session for x in scheduledsessions ]
for session in session_objects: for session in session_objects:

View file

@ -75,7 +75,7 @@ class BluesheetTestCase(TestCase):
make_test_data() make_test_data()
meeting = Meeting.objects.filter(type='interim').first() meeting = Meeting.objects.filter(type='interim').first()
group = Group.objects.get(acronym='mars') 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'}) url = reverse('proceedings_upload_unified', kwargs={'meeting_num':meeting.number,'acronym':'mars'})
upfile = StringIO('dummy file') upfile = StringIO('dummy file')
upfile.name = "scan1.pdf" upfile.name = "scan1.pdf"

View file

@ -438,7 +438,9 @@ def interim(request, acronym):
Session.objects.create(meeting=meeting, Session.objects.create(meeting=meeting,
group=group, group=group,
requested_by=request.user.person, requested_by=request.user.person,
status_id='sched') status_id='sched',
type_id='session',
)
create_interim_directory() create_interim_directory()
make_directories(meeting) make_directories(meeting)

View file

@ -270,7 +270,9 @@ def confirm(request, acronym):
requested_by=login, requested_by=login,
requested_duration=datetime.timedelta(0,int(duration)), requested_duration=datetime.timedelta(0,int(duration)),
comments=form['comments'], comments=form['comments'],
status=SessionStatusName.objects.get(slug=slug)) status=SessionStatusName.objects.get(slug=slug),
type_id='session',
)
session_save(new_session) session_save(new_session)
if 'resources' in form: if 'resources' in form:
new_session.resources = form['resources'] new_session.resources = form['resources']
@ -383,7 +385,9 @@ def edit_mtg(request, num, acronym):
requested_by=login, requested_by=login,
requested_duration=duration, requested_duration=duration,
comments=form.cleaned_data['comments'], comments=form.cleaned_data['comments'],
status=SessionStatusName.objects.get(slug='schedw')) status=SessionStatusName.objects.get(slug='schedw'),
type_id='session',
)
new_session.save() new_session.save()
else: else:
duration = datetime.timedelta(0,int(form.cleaned_data['length_session2'])) duration = datetime.timedelta(0,int(form.cleaned_data['length_session2']))
@ -405,7 +409,9 @@ def edit_mtg(request, num, acronym):
requested_by=login, requested_by=login,
requested_duration=duration, requested_duration=duration,
comments=form.cleaned_data['comments'], comments=form.cleaned_data['comments'],
status=SessionStatusName.objects.get(slug='apprw')) status=SessionStatusName.objects.get(slug='apprw'),
type_id='session',
)
new_session.save() new_session.save()
else: else:
duration = datetime.timedelta(0,int(form.cleaned_data['length_session3'])) duration = datetime.timedelta(0,int(form.cleaned_data['length_session3']))

View file

@ -1,7 +1,7 @@
{% load humanize %}{% autoescape off %}{% load ietf_filters %}"Date","Start","End","Session","Room","Area","Acronym","Type","Description","Session ID","Agenda","Slides" {% 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 == "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 == "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 == "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 %} {% endif %}{% endfor %}{% endautoescape %}

Can't render this file because it contains an unexpected character in line 1 and column 63.

View file

@ -146,7 +146,7 @@
<iframe seamless class="hidden" id="weekview"></iframe> <iframe seamless class="hidden" id="weekview"></iframe>
<table class="table table-condensed table-striped"> <table class="table table-condensed table-striped">
{% for item in schedule.assignments.all %} {% for item in filtered_assignments.all %}
{% ifchanged item.timeslot.time|date:"Y-m-d" %} {% ifchanged item.timeslot.time|date:"Y-m-d" %}
<tr><th class="gap" colspan="6"></th></tr> <tr><th class="gap" colspan="6"></th></tr>
@ -335,7 +335,7 @@
</div> </div>
<div class="col-md-2 hidden-print bs-docs-sidebar" id="affix"> <div class="col-md-2 hidden-print bs-docs-sidebar" id="affix">
<ul class="nav nav-pills nav-stacked small" data-spy="affix"> <ul class="nav nav-pills nav-stacked small" data-spy="affix">
{% for item in schedule.assignments.all %} {% for item in filtered_assignments.all %}
{% ifchanged item.timeslot.time|date:"Y-m-d" %} {% ifchanged item.timeslot.time|date:"Y-m-d" %}
<li><a href="#{{item.timeslot.time|slugify}}">{{ item.timeslot.time|date:"l, F j, Y" }}</a></li> <li><a href="#{{item.timeslot.time|slugify}}">{{ item.timeslot.time|date:"l, F j, Y" }}</a></li>
{% endifchanged %} {% endifchanged %}

View file

@ -8,7 +8,7 @@
{% filter center:72 %}Updated {{ updated|date:"Y-m-d H:i:s T" }}{% endfilter %} {% 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 %} {% 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" }} {{ item.timeslot.time|date:"l"|upper }}, {{ item.timeslot.time|date:"F j, Y" }}
@ -20,7 +20,7 @@
{% endif %}{% if item.timeslot.type.slug == "session" %}{% if item.session.group %}{% ifchanged %} {% endif %}{% if item.timeslot.type.slug == "session" %}{% if item.session.group %}{% ifchanged %}
{{ item.timeslot.time_desc }} {{ item.timeslot.name }} {{ 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" %} {% 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 }}{% 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 %} {{ item.timeslot.time_desc }} {{ item.timeslot.name }} - {{ item.timeslot.location.name }}{% endif %}{% endfor %}

View file

@ -0,0 +1,40 @@
{% extends "base.html" %}
{% block morecss %}
ul.daylist { list-style:none; padding-left:0; }
li.daylistentry { font-size:162%; font-weight:700; }
li.even { background-color:#EDF5FF; }
li.odd { background-color:white; }
ul.roomlist {list-style:none; padding-left:0; margin-bottom:20px;}
li.roomlistentry { font-weight: 400; }
ul.sessionlist { list-style:none; padding-left:2em; margin-bottom:10px;}
li.sessionlistentry { font-size:62%; }
.type-lead:after { content: " (DO NOT POST)"; color:red; }
.type-offagenda:after { content:" (not published on agenda)"; }
{% endblock %}
{% block title %}Agenda for {{meeting}} by Room{% endblock %}
{% block content %}
<h1>Agenda for {{meeting}} by Room</h1>
<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_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 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>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -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 %}

View file

@ -110,6 +110,8 @@ promiselist.push(ss_promise);
<p>Please save this agenda to your account first.</p> <p>Please save this agenda to your account first.</p>
</div> </div>
<div class="content"> {% comment %} For preserving styling across the facelift {% endcomment %}
<div class="wrapper custom_text_stuff"> <div class="wrapper custom_text_stuff">
@ -206,10 +208,11 @@ promiselist.push(ss_promise);
</div> </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> <tr>
<th class="schedule_title"><div id="pageloaded" style="display:none">loaded</div><div id="spinner"><!-- spinney goes here --></div></th> <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 %} {% 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"> <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> <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> <tr>
<th class="th_column"><button id="show_all_button" class="styled_button">show all</button></th> <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 day in time_slices %}
{% for slot in date_slices|lookup:day %} {% 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> <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="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> <div class="right room_name">{{r.name}} <span class="capacity">({{r.capacity}})</span></div>
</th> </th>
{% comment 'The secretariat is not using these features' %}
<th class="room_features"> <th class="room_features">
<div class="resource_list"> <div class="resource_list">
{% for resource in r.resources.all %} {% for resource in r.resources.all %}
@ -255,6 +259,7 @@ promiselist.push(ss_promise);
{% endfor %} {% endfor %}
</div> </div>
</th> </th>
{% endcomment %}
{% for day in time_slices %} {% for day in time_slices %}
{% for slot in date_slices|lookup:day %} {% 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> <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>
</div> {% comment %} End of .content div {% endcomment %}
{% endblock %} {% endblock %}

View file

@ -12,11 +12,11 @@
<h2>{{ session.name }}</h2> <h2>{{ session.name }}</h2>
{% endif %} {% endif %}
{% if session.sessionpresentation_set.all.count %} {% if filtered_sessionpresentation_set %}
<p>Materials:</p> <p>Materials:</p>
<ul> <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> <li><a href="{% url 'doc_view' name=pres.document.name rev=pres.rev%}">{{ pres.document.name }}-{{ pres.rev }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>

View file

@ -18,6 +18,8 @@
.content table { border-collapse: separate; border-spacing: 2px; } .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 { background-color: #edf5ff; padding:0; border: 1px solid #89d; margin-top:4px; width: 130px; }
.ietf-navbar ul { padding: 0; margin: 0; } .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; } .ietf-navbar ul li { list-style: none; padding: 0; margin: 0; font-size: 93%; padding: 2px 0px 2px 0px; }
@ -69,6 +71,7 @@
background-color:#2647A0; background-color:#2647A0;
width:100px; /* otherwise we get overlap */ width:100px; /* otherwise we get overlap */
min-width:100px; min-width:100px;
min-height:40px;
font-size:12px; font-size:12px;
position:absolute; /* makes it float independent of scroll */ position:absolute; /* makes it float independent of scroll */
z-index:100; /* meeting events will be on top otherwise */ z-index:100; /* meeting events will be on top otherwise */
@ -242,7 +245,7 @@ tr.agenda_slot{
td.agenda_slot{ td.agenda_slot{
/* overflow-y:auto; */ /* overflow-y:auto; */
/* height:20px; */ /* height:20px; */
height: 40px; height: 45px;
/* min-height:20px; */ /* min-height:20px; */
} }

View file

@ -1172,6 +1172,10 @@ Session.prototype.event_template = function() {
} }
//console.log("acronym", groupacronym, this.group.acronym, this.visible_title()); //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 // see comment in ietf.ccs, and
// http://stackoverflow.com/questions/5148041/does-firefox-support-position-relative-on-table-elements // 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 "+ 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.wg_scheme()+" "+
this.area_scheme() +" meeting_obj'>"+ this.area_scheme() +" meeting_obj'>"+
this.visible_title()+ this.visible_title()+
"<span> ("+this.requested_duration+")</span>" + "<span>" + durationstring + "</span>" +
"</th><td class=\"ourconflicts\"></td>"+pinned+"</tr></table>"+ area_mark +"</div></div>"; "</th><td class=\"ourconflicts\"></td>"+pinned+"</tr></table>"+ area_mark +"</div></div>";
}; };