Merged in [9669] from olau@iola.dk:

Summary: Make the meeting agenda code use the historic info available
for groups. In the process, added some select_related/prefetch_related
code to cut the number of database queries in the agenda down from
4000-5000 to about 50. Rewritten agenda CSV code to use Python arrays
rather than a template for improved readability/reuse. Rewritten week
view to assemble its data in Python. Plus a few other minor cleanups,
e.g. lame_description is now gone.
Fixes #1088. Branch
 - Legacy-Id: 10005
Note: SVN reference [9669] has been migrated to Git commit acda84208d
This commit is contained in:
Henrik Levkowetz 2015-08-10 19:46:11 +00:00
commit fb66c1856f
12 changed files with 569 additions and 308 deletions

View file

@ -198,8 +198,13 @@ def get_list(repo, filename):
continue
try:
note(" '%s'" % line)
changeset = line.split()[0]
branch, rev = changeset.split('@')
parts = line.split()
if len(parts) >1 and parts[1] == '@':
branch, rev = parts[0], parts[2]
changeset = "%s@%s" % (branch, rev)
else:
changeset = parts[0]
branch, rev = changeset.split('@')
if branch.startswith('/'):
branch = branch[1:]
if not (rev in merged_revs and branch == merged_revs[rev]):

View file

@ -2,9 +2,12 @@
import datetime
import pytz
import os
import re
from tempfile import mkstemp
from django.http import HttpRequest
from django.db.models import Max, Q
from django.db.models import Max, Q, Prefetch, F
from django.conf import settings
from django.core.cache import cache
from django.utils.cache import get_cache_key
@ -12,11 +15,13 @@ from django.shortcuts import get_object_or_404
import debug # pyflakes:ignore
from ietf.doc.models import Document
from ietf.group.models import Group
from ietf.ietfauth.utils import has_role, user_is_person
from ietf.person.models import Person
from ietf.meeting.models import Meeting
from ietf.utils.history import find_history_active_at
from ietf.utils.history import find_history_active_at, find_history_replacements_active_at
from ietf.utils.pipe import pipe
def find_ads_for_meeting(meeting):
ads = []
@ -144,6 +149,109 @@ def meeting_updated(meeting):
ts = tz.localize(ts)
return ts
def preprocess_assignments_for_agenda(assignments_queryset, meeting):
# prefetch some stuff to prevent a myriad of small, inefficient queries
assignments_queryset = assignments_queryset.select_related(
"timeslot", "timeslot__location", "timeslot__type",
"session",
"session__group", "session__group__charter", "session__group__charter__group",
).prefetch_related(
Prefetch("session__materials",
queryset=Document.objects.exclude(states__type=F("type"),states__slug='deleted').select_related("group").order_by("order"),
to_attr="prefetched_active_materials",
),
"timeslot__meeting",
)
assignments = list(assignments_queryset) # make sure we're set in stone
meeting_time = datetime.datetime.combine(meeting.date, datetime.time())
# replace groups with historic counterparts
for a in assignments:
if a.session:
a.session.historic_group = None
groups = [a.session.group for a in assignments if a.session and a.session.group]
group_replacements = find_history_replacements_active_at(groups, meeting_time)
for a in assignments:
if a.session and a.session.group:
a.session.historic_group = group_replacements.get(a.session.group_id)
# replace group parents with historic counterparts
for a in assignments:
if a.session and a.session.historic_group:
a.session.historic_group.historic_parent = None
parents = Group.objects.filter(pk__in=set(a.session.historic_group.parent_id for a in assignments if a.session and a.session.historic_group and a.session.historic_group.parent_id))
parent_replacements = find_history_replacements_active_at(parents, meeting_time)
for a in assignments:
if a.session and a.session.historic_group and a.session.historic_group.parent_id:
a.session.historic_group.historic_parent = parent_replacements.get(a.session.historic_group.parent_id)
return assignments
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()
# style python format, something like this:
# DOC_PATH_FORMAT = { "agenda": "/foo/bar/agenda-{meeting.number}/agenda-{meeting-number}-{doc.group}*", }
path = os.path.join(settings.AGENDA_PATH, "%s/agenda/%s" % (num, doc.external_url))
if os.path.exists(path):
with open(path) as f:
return f.read()
else:
return None
def convert_draft_to_pdf(doc_name):
inpath = os.path.join(settings.IDSUBMIT_REPOSITORY_PATH, doc_name + ".txt")
outpath = os.path.join(settings.INTERNET_DRAFT_PDF_PATH, doc_name + ".pdf")
try:
infile = open(inpath, "r")
except IOError:
return
t,tempname = mkstemp()
os.close(t)
tempfile = open(tempname, "w")
pageend = 0;
newpage = 0;
formfeed = 0;
for line in infile:
line = re.sub("\r","",line)
line = re.sub("[ \t]+$","",line)
if re.search("\[?[Pp]age [0-9ivx]+\]?[ \t]*$",line):
pageend=1
tempfile.write(line)
continue
if re.search("^[ \t]*\f",line):
formfeed=1
tempfile.write(line)
continue
if re.search("^ *INTERNET.DRAFT.+[0-9]+ *$",line) or re.search("^ *Internet.Draft.+[0-9]+ *$",line) or re.search("^draft-[-a-z0-9_.]+.*[0-9][0-9][0-9][0-9]$",line) or re.search("^RFC.+[0-9]+$",line):
newpage=1
if re.search("^[ \t]*$",line) and pageend and not newpage:
continue
if pageend and newpage and not formfeed:
tempfile.write("\f")
pageend=0
formfeed=0
newpage=0
tempfile.write(line)
infile.close()
tempfile.close()
t,psname = mkstemp()
os.close(t)
pipe("enscript --margins 76::76: -B -q -p "+psname + " " +tempname)
os.unlink(tempname)
pipe("ps2pdf "+psname+" "+outpath)
os.unlink(psname)
def agenda_permissions(meeting, schedule, user):
# do this in positive logic.
cansee = False

View file

@ -638,16 +638,6 @@ class Schedule(models.Model):
self._cached_sessions_that_can_meet = self.meeting.sessions_that_can_meet.all()
return self._cached_sessions_that_can_meet
def area_list(self):
return ( self.assignments.filter(session__group__type__slug__in=['wg', 'rg', 'ag', 'iab'],
session__group__parent__isnull=False)
.order_by('session__group__parent__acronym')
.values_list('session__group__parent__acronym', flat=True)
.distinct() )
def groups(self):
return Group.objects.filter(type__slug__in=['wg', 'rg', 'ag', 'iab'], parent__isnull=False, session__scheduledsession__schedule=self).exclude(session__scheduledsession__timeslot__type__in=['lead','offagenda']).distinct().order_by('parent__acronym', 'acronym')
# calculate badness of entire schedule
def calc_badness(self):
# now calculate badness
@ -768,6 +758,35 @@ class ScheduledSession(models.Model):
ss["pinned"] = self.pinned
return ss
def slug(self):
"""Return sensible id string for session, e.g. suitable for use as HTML anchor."""
components = []
if not self.timeslot:
components.append("unknown")
if not self.session or not (getattr(self.session, "historic_group") or self.session.group):
components.append("unknown")
else:
components.append(self.timeslot.time.strftime("%a-%H%M"))
g = getattr(self.session, "historic_group", None) or self.session.group
if self.timeslot.type_id in ('break', 'reg', 'other'):
components.append(g.acronym)
if self.timeslot.type_id in ('session', 'plenary'):
if self.timeslot.type_id == "plenary":
components.append("1plenary")
else:
p = getattr(g, "historic_parent", None) or g.parent
if p and p.type_id in ("area", "irtf"):
components.append(p.acronym)
components.append(g.acronym)
return u"-".join(components).lower()
class Constraint(models.Model):
"""
Specifies a constraint on the scheduling.
@ -886,14 +905,30 @@ class Session(models.Model):
# Should work on how materials are captured so that deleted things are no longer associated with the session
# (We can keep the information about something being added to and removed from a session in the document's history)
def get_material(self, material_type, only_one):
if hasattr(self, "prefetched_active_materials"):
l = [d for d in self.prefetched_active_materials if d.type_id == material_type]
for d in l:
d.meeting_related = lambda: True
else:
l = self.materials.filter(type=material_type).exclude(states__type=material_type, states__slug='deleted').order_by("order")
if only_one:
if l:
return l[0]
else:
return None
else:
return l
def agenda(self):
return self.materials.filter(type='agenda').exclude(states__type='agenda',states__slug='deleted').first()
return self.get_material("agenda", only_one=True)
def minutes(self):
return self.materials.filter(type='minutes').exclude(states__type='minutes',states__slug='deleted').first()
return self.get_material("minutes", only_one=True)
def slides(self):
return list(self.materials.filter(type='slides').exclude(states__type='slides',states__slug='deleted').order_by('order'))
return list(self.get_material("slides", only_one=False))
def __unicode__(self):
if self.meeting.type_id == "interim":
@ -908,9 +943,6 @@ class Session(models.Model):
ss0name = ','.join([x.timeslot.time.strftime("%a-%H%M") for x in ss])
return u"%s: %s %s %s" % (self.meeting, self.group.acronym, self.name, ss0name)
def is_bof(self):
return self.group.is_bof();
@property
def short_name(self):
if self.name:
@ -994,7 +1026,7 @@ class Session(models.Model):
sess1['name'] = str(self.name)
sess1['title'] = str(self.short_name)
sess1['short_name'] = str(self.short_name)
sess1['bof'] = str(self.is_bof())
sess1['bof'] = str(self.group.is_bof())
sess1['agenda_note'] = str(self.agenda_note)
sess1['attendees'] = str(self.attendees)
sess1['status'] = str(self.status)
@ -1024,18 +1056,6 @@ class Session(models.Model):
else:
return "The agenda has not been uploaded yet."
# 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:
return ""
def ical_status(self):
if self.status.slug == 'canceled': # sic
return "CANCELLED"
@ -1050,13 +1070,13 @@ class Session(models.Model):
if not hasattr(self, '_agenda_file'):
self._agenda_file = ""
docs = self.materials.filter(type="agenda", states__type="agenda", states__slug="active")
if not docs:
agenda = self.agenda()
if not agenda:
return ""
# we use external_url at the moment, should probably regularize
# the filenames to match the document name instead
filename = docs[0].external_url
filename = agenda.external_url
self._agenda_file = "%s/agenda/%s" % (self.meeting.number, filename)
return self._agenda_file

View file

@ -7,33 +7,36 @@ import tarfile
import urllib
from tempfile import mkstemp
from collections import OrderedDict
import csv
import json
import debug # pyflakes:ignore
from django import forms
from django.shortcuts import render, render_to_response, redirect
from django.shortcuts import render, redirect
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.contrib import messages
from django.core.urlresolvers import reverse
from django.db.models import Q, Min, Max
from django.template import RequestContext
from django.template.loader import render_to_string
from django.db.models import Min, Max
from django.conf import settings
from django.forms.models import modelform_factory
from django.views.decorators.csrf import ensure_csrf_cookie
from django.forms import ModelForm
from django.views.decorators.csrf import ensure_csrf_cookie
from ietf.doc.models import Document, State
from ietf.group.models import Group
from ietf.ietfauth.utils import role_required, has_role
from ietf.meeting.models import Meeting, TimeSlot, Session, Schedule, Room
from ietf.meeting.models import Meeting, Session, Schedule, Room
from ietf.meeting.helpers import get_areas, get_person_by_email, get_schedule_by_name
from ietf.meeting.helpers import build_all_agenda_slices, get_wg_name_list
from ietf.meeting.helpers import get_all_scheduledsessions_from_schedule
from ietf.meeting.helpers import get_modified_from_scheduledsessions
from ietf.meeting.helpers import get_wg_list, find_ads_for_meeting
from ietf.meeting.helpers import get_meeting, get_schedule, agenda_permissions, meeting_updated
from ietf.meeting.helpers import preprocess_assignments_for_agenda, read_agenda_file
from ietf.meeting.helpers import convert_draft_to_pdf
from ietf.utils.pipe import pipe
from ietf.utils.pdf import pdf_pages
def materials(request, meeting_num=None):
meeting = get_meeting(meeting_num)
@ -45,12 +48,12 @@ def materials(request, meeting_num=None):
if settings.SERVER_MODE != 'production' and '_testoverride' in request.REQUEST:
pass
elif now > cor_cut_off_date:
return render_to_response("meeting/materials_upload_closed.html", {
return render(request, "meeting/materials_upload_closed.html", {
'meeting_num': meeting_num,
'begin_date': begin_date,
'cut_off_date': cut_off_date,
'cor_cut_off_date': cor_cut_off_date
}, context_instance=RequestContext(request))
})
#sessions = Session.objects.filter(meeting__number=meeting_num, timeslot__isnull=False)
schedule = get_schedule(meeting, None)
@ -62,14 +65,14 @@ def materials(request, meeting_num=None):
iab = sessions.filter(group__parent__acronym = 'iab')
cache_version = Document.objects.filter(session__meeting__number=meeting_num).aggregate(Max('time'))["time__max"]
return render_to_response("meeting/materials.html", {
return render(request, "meeting/materials.html", {
'meeting_num': meeting_num,
'plenaries': plenaries, 'ietf': ietf, 'training': training, 'irtf': irtf, 'iab': iab,
'cut_off_date': cut_off_date,
'cor_cut_off_date': cor_cut_off_date,
'submission_started': now > begin_date,
'cache_version': cache_version,
}, context_instance=RequestContext(request))
})
def current_materials(request):
meetings = Meeting.objects.exclude(number__startswith='interim-').order_by('-number')
@ -78,17 +81,6 @@ def current_materials(request):
else:
raise Http404
def get_user_agent(request):
if settings.SERVER_MODE != 'production' and '_testiphone' in request.REQUEST:
user_agent = "iPhone"
elif 'user_agent' in request.REQUEST:
user_agent = request.REQUEST['user_agent']
elif 'HTTP_USER_AGENT' in request.META:
user_agent = request.META["HTTP_USER_AGENT"]
else:
user_agent = ""
return user_agent
def ascii_alphanumeric(string):
return re.match(r'^[a-zA-Z0-9]*$', string)
@ -266,12 +258,12 @@ def edit_agenda(request, num=None, owner=None, name=None):
can_see, can_edit,secretariat = agenda_permissions(meeting, schedule, user)
if not can_see:
return HttpResponse(render_to_string("meeting/private_agenda.html",
return render(request, "meeting/private_agenda.html",
{"schedule":schedule,
"meeting": meeting,
"meeting_base_url":meeting_base_url,
"hide_menu": True},
RequestContext(request)), status=403, content_type="text/html")
"hide_menu": True
}, status=403, content_type="text/html")
scheduledsessions = get_all_scheduledsessions_from_schedule(schedule)
@ -366,12 +358,10 @@ def edit_agendas(request, num=None, order=None):
def agenda(request, num=None, name=None, base=None, ext=None):
base = base if base else 'agenda'
ext = ext if ext else '.html'
# This is misleading - urls.py doesn't send ics through here anymore
mimetype = {
".html":"text/html; charset=%s"%settings.DEFAULT_CHARSET,
".txt": "text/plain; charset=%s"%settings.DEFAULT_CHARSET,
".ics":"text/calendar; charset=%s"%settings.DEFAULT_CHARSET,
".csv":"text/csv; charset=%s"%settings.DEFAULT_CHARSET,
".csv": "text/csv; charset=%s"%settings.DEFAULT_CHARSET,
}
meeting = get_meeting(num)
schedule = get_schedule(meeting, name)
@ -381,7 +371,123 @@ def agenda(request, num=None, name=None, base=None, ext=None):
updated = meeting_updated(meeting)
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])
filtered_assignments = preprocess_assignments_for_agenda(filtered_assignments, meeting)
if ext == ".csv":
return agenda_csv(schedule, filtered_assignments)
# extract groups hierarchy, it's a little bit complicated because
# we can be dealing with historic groups
seen = set()
groups = [a.session.historic_group for a in filtered_assignments
if a.session
and a.session.historic_group
and a.session.historic_group.type_id in ('wg', 'rg', 'ag', 'iab')
and a.session.historic_group.historic_parent]
group_parents = []
for g in groups:
if g.historic_parent.acronym not in seen:
group_parents.append(g.historic_parent)
seen.add(g.historic_parent.acronym)
seen = set()
for p in group_parents:
p.group_list = []
for g in groups:
if g.acronym not in seen and g.historic_parent.acronym == p.acronym:
p.group_list.append(g)
seen.add(g.acronym)
p.group_list.sort(key=lambda g: g.acronym)
return render(request, "meeting/"+base+ext, {
"schedule": schedule,
"filtered_assignments": filtered_assignments,
"updated": updated,
"group_parents": group_parents,
}, content_type=mimetype[ext])
def agenda_csv(schedule, filtered_assignments):
response = HttpResponse(content_type="text/csv; charset=%s"%settings.DEFAULT_CHARSET)
writer = csv.writer(response, delimiter=',', quoting=csv.QUOTE_ALL)
headings = ["Date", "Start", "End", "Session", "Room", "Area", "Acronym", "Type", "Description", "Session ID", "Agenda", "Slides"]
def write_row(row):
encoded_row = [v.encode('utf-8') if isinstance(v, unicode) else v for v in row]
while len(encoded_row) < len(headings):
encoded_row.append(None) # produce empty entries at the end as necessary
writer.writerow(encoded_row)
def agenda_field(item):
agenda_doc = item.session.agenda()
if agenda_doc:
return "http://www.ietf.org/proceedings/{schedule.meeting.number}/agenda/{agenda.external_url}".format(schedule=schedule, agenda=agenda_doc)
else:
return ""
def slides_field(item):
return "|".join("http://www.ietf.org/proceedings/{schedule.meeting.number}/slides/{slide.external_url}".format(schedule=schedule, slide=slide) for slide in item.session.slides())
write_row(headings)
for item in filtered_assignments:
row = []
row.append(item.timeslot.time.strftime("%Y-%m-%d"))
row.append(item.timeslot.time.strftime("%H%M"))
row.append(item.timeslot.end_time().strftime("%H%M"))
if item.timeslot.type_id == "break":
row.append(item.timeslot.type.name)
row.append(schedule.meeting.break_area)
row.append("")
row.append("")
row.append("")
row.append(item.timeslot.name)
row.append("b{}".format(item.timeslot.pk))
elif item.timeslot.type_id == "reg":
row.append(item.timeslot.type.name)
row.append(schedule.meeting.reg_area)
row.append("")
row.append("")
row.append("")
row.append(item.timeslot.name)
row.append("r{}".format(item.timeslot.pk))
elif item.timeslot.type_id == "other":
row.append("None")
row.append(item.timeslot.location.name)
row.append("")
row.append(item.session.historic_group.acronym)
row.append(item.session.historic_group.historic_parent.acronym.upper() if item.session.historic_group.historic_parent else "")
row.append(item.session.name)
row.append(item.session.pk)
elif item.timeslot.type_id == "plenary":
row.append(item.session.name)
row.append(item.timeslot.location.name)
row.append("")
row.append(item.session.historic_group.acronym if item.session.historic_group else "")
row.append("")
row.append(item.session.name)
row.append(item.session.pk)
row.append(agenda_field(item))
row.append(slides_field(item))
elif item.timeslot.type_id == "session":
row.append(item.timeslot.name)
row.append(item.timeslot.location.name)
row.append(item.session.historic_group.historic_parent.acronym.upper() if item.session.historic_group.historic_parent else "")
row.append(item.session.historic_group.acronym if item.session.historic_group else "")
row.append("BOF" if item.session.historic_group.state_id in ("bof", "bof-conc") else item.session.historic_group.type.name)
row.append(item.session.historic_group.name if item.session.historic_group else "")
row.append(item.session.pk)
row.append(agenda_field(item))
row.append(slides_field(item))
if len(row) > 3:
write_row(row)
return response
@role_required('Area Director','Secretariat','IAB')
def agenda_by_room(request,num=None):
@ -414,18 +520,6 @@ def agenda_by_type_ics(request,num=None,type=None):
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()
# style python format, something like this:
# DOC_PATH_FORMAT = { "agenda": "/foo/bar/agenda-{meeting.number}/agenda-{meeting-number}-{doc.group}*", }
path = os.path.join(settings.AGENDA_PATH, "%s/agenda/%s" % (num, doc.external_url))
if os.path.exists(path):
with open(path) as f:
return f.read()
else:
return None
def session_agenda(request, num, session):
d = Document.objects.filter(type="agenda", session__meeting__number=num)
if session == "plenaryt":
@ -457,53 +551,6 @@ def session_agenda(request, num, session):
raise Http404("No agenda for the %s session of IETF %s is available" % (session, num))
def convert_to_pdf(doc_name):
inpath = os.path.join(settings.IDSUBMIT_REPOSITORY_PATH, doc_name + ".txt")
outpath = os.path.join(settings.INTERNET_DRAFT_PDF_PATH, doc_name + ".pdf")
try:
infile = open(inpath, "r")
except IOError:
return
t,tempname = mkstemp()
os.close(t)
tempfile = open(tempname, "w")
pageend = 0;
newpage = 0;
formfeed = 0;
for line in infile:
line = re.sub("\r","",line)
line = re.sub("[ \t]+$","",line)
if re.search("\[?[Pp]age [0-9ivx]+\]?[ \t]*$",line):
pageend=1
tempfile.write(line)
continue
if re.search("^[ \t]*\f",line):
formfeed=1
tempfile.write(line)
continue
if re.search("^ *INTERNET.DRAFT.+[0-9]+ *$",line) or re.search("^ *Internet.Draft.+[0-9]+ *$",line) or re.search("^draft-[-a-z0-9_.]+.*[0-9][0-9][0-9][0-9]$",line) or re.search("^RFC.+[0-9]+$",line):
newpage=1
if re.search("^[ \t]*$",line) and pageend and not newpage:
continue
if pageend and newpage and not formfeed:
tempfile.write("\f")
pageend=0
formfeed=0
newpage=0
tempfile.write(line)
infile.close()
tempfile.close()
t,psname = mkstemp()
os.close(t)
pipe("enscript --margins 76::76: -B -q -p "+psname + " " +tempname)
os.unlink(tempname)
pipe("ps2pdf "+psname+" "+outpath)
os.unlink(psname)
def session_draft_list(num, session):
try:
agendas = Document.objects.filter(type="agenda",
@ -548,8 +595,8 @@ def session_draft_tarfile(request, num, session):
for doc_name in drafts:
pdf_path = os.path.join(settings.INTERNET_DRAFT_PDF_PATH, doc_name + ".pdf")
if (not os.path.exists(pdf_path)):
convert_to_pdf(doc_name)
if not os.path.exists(pdf_path):
convert_draft_to_pdf(doc_name)
if os.path.exists(pdf_path):
try:
@ -566,18 +613,6 @@ def session_draft_tarfile(request, num, session):
os.unlink(mfn)
return response
def pdf_pages(file):
try:
infile = open(file, "r")
except IOError:
return 0
for line in infile:
m = re.match('\] /Count ([0-9]+)',line)
if m:
return int(m.group(1))
return 0
def session_draft_pdf(request, num, session):
drafts = session_draft_list(num, session);
curr_page = 1
@ -588,10 +623,10 @@ def session_draft_pdf(request, num, session):
for draft in drafts:
pdf_path = os.path.join(settings.INTERNET_DRAFT_PDF_PATH, draft + ".pdf")
if (not os.path.exists(pdf_path)):
convert_to_pdf(draft)
if not os.path.exists(pdf_path):
convert_draft_to_pdf(draft)
if (os.path.exists(pdf_path)):
if os.path.exists(pdf_path):
pages = pdf_pages(pdf_path)
pdfmarks.write("[/Page "+str(curr_page)+" /View [/XYZ 0 792 1.0] /Title (" + draft + ") /OUT pdfmark\n")
pdf_list = pdf_list + " " + pdf_path
@ -612,11 +647,62 @@ def session_draft_pdf(request, num, session):
def week_view(request, num=None):
meeting = get_meeting(num)
timeslots = TimeSlot.objects.filter(meeting=meeting)
schedule = get_schedule(meeting)
template = "meeting/week-view.html"
return render_to_response(template,
{"timeslots":timeslots,"render_types":["Session","Other","Break","Plenary"]}, context_instance=RequestContext(request))
if not schedule:
raise Http404
filtered_assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda'])
filtered_assignments = preprocess_assignments_for_agenda(filtered_assignments, meeting)
items = []
for a in filtered_assignments:
# we don't HTML escape any of these as the week-view code is using createTextNode
item = {
"key": str(a.timeslot.pk),
"day": a.timeslot.time.strftime("%w"),
"time": a.timeslot.time.strftime("%H%M") + "-" + a.timeslot.end_time().strftime("%H%M"),
"duration": a.timeslot.duration.seconds,
"time_id": a.timeslot.time.strftime("%m%d%H%M"),
"dayname": "{weekday}, {month} {day_of_month}, {year}".format(
weekday=a.timeslot.time.strftime("%A").upper(),
month=a.timeslot.time.strftime("%B"),
day_of_month=a.timeslot.time.strftime("%d").lstrip("0"),
year=a.timeslot.time.strftime("%Y"),
),
"type": a.timeslot.type.name
}
if a.session:
if a.session.historic_group:
item["group"] = a.session.historic_group.acronym
if a.session.name:
item["name"] = a.session.name
elif a.timeslot.type_id == "break":
item["name"] = a.timeslot.name
item["area"] = a.timeslot.type_id
item["group"] = a.timeslot.type_id
elif a.session.historic_group:
item["name"] = a.session.historic_group.name
if a.session.historic_group.state_id == "bof":
item["name"] += " BOF"
item["state"] = a.session.historic_group.state.name
if a.session.historic_group.historic_parent:
item["area"] = a.session.historic_group.historic_parent.acronym
if a.timeslot.show_location:
item["room"] = a.timeslot.get_location()
if a.session and a.session.agenda():
item["agenda"] = a.session.agenda().get_absolute_url()
items.append(item)
return render(request, "meeting/week-view.html", {
"items": json.dumps(items),
})
@role_required('Area Director','Secretariat','IAB')
def room_view(request, num=None):
@ -695,39 +781,39 @@ def ical_agenda(request, num=None, name=None, ext=None):
# edu, ietf, tools, iesg, iab
for item in filter:
if item:
if item[0] == '-' and item[1] == '~':
include_types -= set([item[2:]])
elif item[0] == '-':
exclude.append(item[1:])
elif item[0] == '~':
include_types |= set([item[1:]])
if len(item) > 2 and item[0] == '-' and item[1] == '~':
include_types -= set([item[2:]])
elif len(item) > 1 and item[0] == '-':
exclude.append(item[1:])
elif len(item) > 1 and item[0] == '~':
include_types |= set([item[1:]])
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)
).exclude(session__group__acronym__in = exclude).distinct()
#.exclude(Q(session__group__isnull = False),
#Q(session__group__acronym__in = exclude) |
#Q(session__group__parent__acronym__in = exclude))
assignments = schedule.assignments.exclude(timeslot__type__in=['lead','offagenda'])
assignments = preprocess_assignments_for_agenda(assignments, meeting)
return HttpResponse(render_to_string("meeting/agenda.ics",
{"schedule":schedule, "assignments":assignments, "updated":updated},
RequestContext(request)), content_type="text/calendar")
assignments = [a for a in assignments if
(a.timeslot.type_id in include_types
or (a.session.historic_group and a.session.historic_group.acronym in include)
or (a.session.historic_group and a.session.historic_group.historic_parent and a.session.historic_group.historic_parent.acronym in include))
and (not a.session.historic_group or a.session.historic_group.acronym not in exclude)]
def meeting_requests(request, num=None) :
return render(request, "meeting/agenda.ics", {
"schedule": schedule,
"assignments": assignments,
"updated": updated
}, content_type="text/calendar")
def meeting_requests(request, num=None):
meeting = get_meeting(num)
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")
return render_to_response("meeting/requests.html",
return render(request, "meeting/requests.html",
{"meeting": meeting, "sessions":sessions,
"groups_not_meeting": groups_not_meeting},
context_instance=RequestContext(request))
"groups_not_meeting": groups_not_meeting})
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)
sessions = Session.objects.filter(meeting=meeting,group__acronym=acronym,type__in=['session','plenary','other'])
@ -775,7 +861,7 @@ def session_details(request, num, acronym, date=None, week_day=None, seq=None) :
scheduled_time = "Not yet scheduled"
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])
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",

View file

@ -101,6 +101,7 @@ body { padding-top: 70px; }
h2.anchor-target:before,
h3.anchor-target:before,
h4.anchor-target:before,
tr th.anchor-target:before,
div.anchor-target:before {
content: '';
display: block;

View file

@ -84,29 +84,28 @@
<p>Groups displayed in <b><i>italics</i></b> are BOFs.</p>
{% regroup schedule.groups by parent.acronym as area_sessions %}
<table class="table table-condensed">
<table class="table table-condensed">
<thead>
<tr>
{% for area in area_sessions %}
<th style="width:{% widthratio 1 area_sessions|length 100 %}%">
<button class="btn btn-default btn-block pickview {{area.grouper|lower}}">{{area.grouper|upper}}</button>
{% for p in group_parents %}
<th style="width:{% widthratio 1 group_parents|length 100 %}%">
<button class="btn btn-default btn-block pickview {{p.acronym|lower}}">{{p.acronym|upper}}</button>
</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for area in area_sessions %}
<td class="view {{area.grouper|lower}}">
{% for p in group_parents %}
<td class="view {{p.acronym|lower}}">
<div class="btn-group-vertical btn-block">
{% for wg in area.list %}
{% for group in p.group_list %}
<div class="btn-group btn-group-xs btn-group-justified">
<button class="btn btn-default pickview {{wg.acronym}}">
{% if wg.is_bof %}
<b><i>{{wg.acronym}}</i></b>
<button class="btn btn-default pickview {{group.acronym}}">
{% if group.is_bof %}
<i>{{group.acronym}}</i>
{% else %}
{{wg.acronym}}
{{group.acronym}}
{% endif %}
</button>
</div>
@ -134,8 +133,8 @@
<h2>Download as .ics</h2>
<p class="buttonlist">
{% for area in schedule.area_list %}
<a class="btn btn-default" href="{% url "ietf.meeting.views.ical_agenda" num=schedule.meeting.number %}?{{area|upper}},-~Other,-~Plenary">{{area|upper}}</a>
{% for p in group_parents %}
<a class="btn btn-default" href="{% url "ietf.meeting.views.ical_agenda" num=schedule.meeting.number %}?{{p.acronym|upper}},-~Other,-~Plenary">{{p.acronym|upper}}</a>
{% endfor %}
<a class="btn btn-default" href="{% url "ietf.meeting.views.ical_agenda" num=schedule.meeting.number %}">Non-area events</a>
<a id="ical-link" class="hidden btn btn-primary" href="{% url "ietf.meeting.views.ical_agenda" num=schedule.meeting.number %}">Customized schedule</a>
@ -152,7 +151,7 @@
<iframe seamless class="hidden" id="weekview"></iframe>
<table class="table table-condensed table-striped">
{% for item in filtered_assignments.all %}
{% for item in filtered_assignments %}
{% ifchanged item.timeslot.time|date:"Y-m-d" %}
<tr><th class="gap" colspan="6"></th></tr>
@ -190,8 +189,7 @@
{% endif %}
{% if item.timeslot.type.slug == 'break' or item.timeslot.type.slug == 'reg' or item.timeslot.type.slug == 'other' %}
{% with session_id=item.timeslot.time|date:"D-Hi"|lower|add:"-"|add:item.session.group.acronym|lower|add:"-"|add:item.timeslot.get_location|slugify %}
<tr id="row-{{session_id}}">
<tr id="row-{{ item.slug }}">
<td class="text-nowrap text-right">
{% if "-utc" in request.path %}
{{item.timeslot.utc_start_time|date:"G:i"}}-{{item.timeslot.utc_end_time|date:"G:i"}}
@ -208,122 +206,120 @@
{{item.timeslot.name}}
</td>
</tr>
{% endwith %}
{% endif %}
{% if item.timeslot.type.slug = 'session' or item.timeslot.type.slug == 'plenary' %}
{% if item.session.group %}
{% with session_id=item.timeslot.time|date:"D-Hi"|lower|add:"-"|add:item.area|default:"unknown"|lower|add:"-"|add:item.session.group.acronym|lower %}
<tr id="row-{{session_id}}" {% if item.timeslot.type.slug == 'plenary' %}class="{{item.timeslot.type.slug}}danger"{% endif %}>
{% if item.session.historic_group %}
<tr id="row-{{item.slug}}" data-ske="row-{{ item.slug }}" {% if item.timeslot.type.slug == 'plenary' %}class="{{item.timeslot.type.slug}}danger"{% endif %}>
{% if item.timeslot.type.slug == 'plenary' %}
<th class="text-nowrap text-right">
{% if "-utc" in request.path %}
{{item.timeslot.utc_start_time|date:"G:i"}}-{{item.timeslot.utc_end_time|date:"G:i"}}
{% else %}
{{item.timeslot.time|date:"G:i"}}-{{item.timeslot.end_time|date:"G:i"}}
{% endif %}
</th>
<td colspan="3">
{% if item.timeslot.show_location and item.timeslot.get_location %}
<a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/venue/?room={{ item.timeslot.get_location|slugify }}">{{item.timeslot.get_location|split:"/"|join:"/<wbr>"}}</a>
{% endif %}
</td>
{% if item.timeslot.type.slug == 'plenary' %}
<th class="text-nowrap text-right">
{% if "-utc" in request.path %}
{{item.timeslot.utc_start_time|date:"G:i"}}-{{item.timeslot.utc_end_time|date:"G:i"}}
{% else %}
{{item.timeslot.time|date:"G:i"}}-{{item.timeslot.end_time|date:"G:i"}}
{% endif %}
</th>
<td colspan="3">
{% if item.timeslot.show_location and item.timeslot.get_location %}
<a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/venue/?room={{ item.timeslot.get_location|slugify }}">{{item.timeslot.get_location|split:"/"|join:"/<wbr>"}}</a>
{% endif %}
</td>
{% else %}
<td></td>
{% else %}
<td></td>
<td>
{% if item.timeslot.show_location and item.timeslot.get_location %}
<a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/venue/?room={{ item.timeslot.get_location|slugify }}">{{item.timeslot.get_location|split:"/"|join:"/<wbr>"}}</a>
{% endif %}
</td>
<td>
{% if item.timeslot.show_location and item.timeslot.get_location %}
<a href="https://tools.ietf.org/agenda/{{schedule.meeting.number}}/venue/?room={{ item.timeslot.get_location|slugify }}">{{item.timeslot.get_location|split:"/"|join:"/<wbr>"}}</a>
{% endif %}
</td>
<td><span class="hidden-xs">{{item.session.historic_group.historic_parent.acronym}}</span></td>
<td><span class="hidden-xs">{{item.session.group.parent.acronym}}</span></td>
<td>
{% if item.session.historic_group.charter %}
<a href="{{item.session.historic_group.charter.get_absolute_url}}">{{item.session.historic_group.acronym}}</a>
{% else %}
{{item.session.historic_group.acronym}}
{% endif %}
</td>
{% endif %}
<td>
{% if item.session.group.charter %}
<a href="{{item.session.group.charter.get_absolute_url}}">{{item.session.group.acronym}}</a>
{% else %}
{{item.session.group.acronym}}
{% endif %}
</td>
{% endif %}
<td>
{% if item.session.agenda %}
<a href="/meeting/{{ schedule.meeting.number }}/agenda/{{ item.session.historic_group.acronym }}/">
{% endif %}
{% if item.timeslot.type.slug == 'plenary' %}
{{item.timeslot.name}}
{% else %}
{{item.session.historic_group.name}}
{% endif %}
{% if item.session.agenda %}
</a>
{% endif %}
<td>
{% if item.session.agenda %}
<a href="/meeting/{{ schedule.meeting.number }}/agenda/{{ item.session.group.acronym }}/">
{% endif %}
{% if item.timeslot.type.slug == 'plenary' %}
{{item.timeslot.name}}
{% else %}
{{item.session.group.name}}
{% endif %}
{% if item.session.agenda %}
</a>
{% endif %}
{% if item.session.historic_group.state_id = "bof" %}
<span class="label label-success pull-right">BOF</span>
{% endif %}
{% if item.session.group.state.name = "BOF" %}
<span class="label label-success pull-right">BOF</span>
{% endif %}
{% if item.session.agenda_note %}
<br><span class="text-danger">{{item.session.agenda_note}}</span>
{% endif %}
{% if item.session.agenda_note %}
<br><span class="text-danger">{{item.session.agenda_note}}</span>
{% endif %}
<div class="modal fade" id="modal-{{ item.slug }}" tabindex="-1" role="dialog" aria-labelledby="label-{{ item.slug }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="label-{{item.slug}}">
Meeting materials for
{% if item.timeslot.type.slug == 'plenary' %}{{item.timeslot.name}}{% else %}{{item.session.historic_group.name}}{% endif %}
<div class="modal fade" id="modal-{{ session_id }}" tabindex="-1" role="dialog" aria-labelledby="label-{{ session_id }}" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="label-{{session_id}}">
Meeting materials for
{% if item.timeslot.type.slug == 'plenary' %}{{item.timeslot.name}}{% else %}{{item.session.group.name}}{% endif %}
</h4>
</div>
<div class="modal-body">
{% with item.session.agenda as agenda %}
{% if agenda %}
{% if agenda.file_extension == "txt" or agenda.file_extension == "html" or agenda.file_extension == "htm" %}
<h4>Agenda</h4>
<div class="frame" data-src="{{agenda.href}}"></div>
{% else %}
<span class="label label-info">Agenda submitted as {{agenda.file_extension|upper}}</span>
{% endif %}
{% else %}
<span class="label label-warning">No agenda submitted</span>
{% endif %}
{% endwith %}
</h4>
</div>
<div class="modal-body">
{% if item.session.agenda %}
{% if item.session.agenda.file_extension == "txt" or item.session.agenda.file_extension == "html" or item.session.agenda.file_extension == "htm" %}
<h4>Agenda</h4>
<div class="frame" data-src="{{item.session.agenda.href}}"></div>
{% else %}
<span class="label label-info">Agenda submitted as {{item.session.agenda.file_extension|upper}}</span>
{% endif %}
{% else %}
<span class="label label-warning">No agenda submitted</span>
{% endif %}
{% if item.session.slides %}
<h4>Slides</h4>
<ul class="fa-ul list-unstyled">
{% for slide in item.session.slides %}
<li>
<span class="fa-li fa fa-file-{{slide.file_extension|lower}}-o"></span>
<a href="{{ slide.href }}">{{ slide.title|clean_whitespace }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</td>
<td class="text-nowrap">
<span class="hidden-xs">
{% if item.session.agenda %}
<button class="btn btn-default btn-xs" data-toggle="modal" data-target="#modal-{{session_id}}"><span class="fa fa-arrows-alt" title="Show meeting materials"></span></button>
<a class="btn btn-default btn-xs" href="/meeting/{{schedule.meeting.number}}/agenda/{{item.session.group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-file-archive-o"></span></a>
<a class="btn btn-default btn-xs" href="/meeting/{{ schedule.meeting.number }}/agenda/{{item.session.group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-file-pdf-o"></span></a>
{% endif %}
</span>
</td>
</tr>
{% endwith %}
{% if item.session.slides %}
<h4>Slides</h4>
<ul class="fa-ul list-unstyled">
{% for slide in item.session.slides %}
<li>
<span class="fa-li fa fa-file-{{slide.file_extension|lower}}-o"></span>
<a href="{{ slide.href }}">{{ slide.title|clean_whitespace }}</a>
</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</td>
<td class="text-nowrap">
<span class="hidden-xs">
{% if item.session.agenda %}
<button class="btn btn-default btn-xs" data-toggle="modal" data-target="#modal-{{item.slug}}"><span class="fa fa-arrows-alt" title="Show meeting materials"></span></button>
<a class="btn btn-default btn-xs" href="/meeting/{{schedule.meeting.number}}/agenda/{{item.session.historic_group.acronym}}-drafts.tgz" title="Download meeting materials as .tar archive"><span class="fa fa-file-archive-o"></span></a>
<a class="btn btn-default btn-xs" href="/meeting/{{ schedule.meeting.number }}/agenda/{{item.session.historic_group.acronym}}-drafts.pdf" title="Download meeting materials as PDF file"><span class="fa fa-file-pdf-o"></span></a>
{% endif %}
</span>
</td>
</tr>
{% endif %}
{% endif %}
{% endfor %}
@ -332,7 +328,7 @@
</div>
<div class="col-md-2 hidden-print bs-docs-sidebar" id="affix">
<ul class="nav nav-pills nav-stacked small" data-spy="affix">
{% for item in filtered_assignments.all %}
{% for item in filtered_assignments %}
{% 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>
{% endifchanged %}

View file

@ -2,9 +2,9 @@
VERSION:2.0
METHOD:PUBLISH
PRODID:-//IETF//datatracker.ietf.org ical agenda//EN
{{schedule.meeting.vtimezone}}{% for item in assignments %}{% if item.session.group %}BEGIN:VEVENT
{{schedule.meeting.vtimezone}}{% for item in assignments %}{% if item.session.historic_group %}BEGIN:VEVENT
UID:ietf-{{schedule.meeting.number}}-{{item.timeslot.pk}}
SUMMARY:{% if item.session.name %}{{item.session.name|ics_esc}}{% else %}{% if not item.session.group %}{{item.timeslot.name|ics_esc}}{% else %}{{item.session.group.acronym|lower}} - {{item.session.group.name}}{% endif%}{%endif%}
SUMMARY:{% if item.session.name %}{{item.session.name|ics_esc}}{% else %}{% if not item.session.historic_group %}{{item.timeslot.name|ics_esc}}{% else %}{{item.session.historic_group.acronym|lower}} - {{item.session.historic_group.name}}{% endif%}{%endif%}
{% if item.timeslot.show_location %}LOCATION:{{item.timeslot.get_location}}
{% endif %}STATUS:{{item.session.ical_status}}
CLASS:PUBLIC

View file

@ -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 filtered_assignments.all.distinct %}{% ifchanged %}
{% for item in filtered_assignments %}{% ifchanged %}
{{ item.timeslot.time|date:"l"|upper }}, {{ item.timeslot.time|date:"F j, Y" }}
@ -17,10 +17,10 @@
{{ item.timeslot.time_desc }} {{ item.session.name }} - {{ item.timeslot.location.name }}
{{ item.session.agenda_text.strip|indent:"3" }}
{% endif %}{% if item.timeslot.type.slug == "session" %}{% if item.session.group %}{% ifchanged %}
{% endif %}{% if item.timeslot.type.slug == "session" %}{% if item.session.historic_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.lame_description }}{% if item.session.agenda_note %} - {{ item.session.agenda_note }}{% endif %}
{% endifchanged %}{{ item.timeslot.location.name|ljust:14 }} {{ item.session.historic_group.historic_parent.acronym|upper|ljust:4 }} {{ item.session.historic_group.acronym|ljust:10 }} {{ item.session.historic_group.name }} {% if item.session.historic_group.state_id == "bof" %}BOF{% elif item.session.historic_group.type_id == "wg" %}WG{% endif %}{% 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 %}

View file

@ -81,12 +81,7 @@
}
// then actual script
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|escapejs}}",{% if slot.session.group.acronym %} wg:"{{slot.session.group.acronym}}",{%endif%}{% else %}{% if slot.type.name == "Break" %}name:"{{slot.name|escapejs}}", 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 %}
var items = {{ items|safe }};
/* Saturday events need to be moved to the day -1 */
for (var i = 0; i < items.length; i++)
@ -154,10 +149,10 @@
// Current types are:
// Session, Other, Break, Plenary
if ("wg" in item)
if ("group" in item)
{
if (include[(item.wg).toLowerCase()]) { return true; }
if (include["-"+(item.wg).toLowerCase()]) { return false; }
if (include[(item.group).toLowerCase()]) { return true; }
if (include["-"+(item.group).toLowerCase()]) { return false; }
}
if ("state" in item)
{
@ -211,7 +206,7 @@
{
if (is_visible(items[i]))
/*
if (!("wg" in items[i]) || (include[(items[i].wg).toLowerCase()]
if (!("group" in items[i]) || (include[(items[i].group).toLowerCase()]
|| include[(items[i].area).toLowerCase()]))
*/
{
@ -322,7 +317,7 @@
{
if (is_visible(items[i]))
/*
if (!("wg" in items[i]) || (include[(items[i].wg).toLowerCase()]
if (!("group" in items[i]) || (include[(items[i].group).toLowerCase()]
|| include[(items[i].area).toLowerCase()]))
*/
{
@ -389,9 +384,9 @@
var label = items[i].name;
if (label.length === 0) { label = "Free Slot"; }
if (items[i].wg && fg[items[i].area])
if (items[i].group && fg[items[i].area])
{
label = label + " (" + items[i].wg + ")";
label = label + " (" + items[i].group + ")";
}
var bold = document.createElement("span");
bold.appendChild(document.createTextNode(label));

View file

@ -22,6 +22,41 @@ def find_history_active_at(obj, time):
return None
def find_history_replacements_active_at(objects, time):
"""Return dictionary mapping object pk to object or its history
object at the time, if any.
Same caveats as for find_history_active_at applies."""
if not objects:
return {}
# automatically figure out how to query history model
history_model = objects[0].history_set.model
# core_filters contains something like "group__exact": obj
relation_name = objects[0].history_set.core_filters.keys()[0].replace("__exact", "")
# now the querying is a bit tricky - we are only interested in the
# history version just before time, or if we can't get that, the
# one just after, but lacking a good way of expressing that
# through SQL we just grab all of them and sort it out ourselves
changed_objects = [o for o in objects if o.time > time]
histories = history_model.objects.filter(**{ relation_name + "__in": changed_objects }).order_by(relation_name, "-time")
history_for_obj = { o.pk: o for o in objects }
skip = None
for h in histories:
obj_id = getattr(h, relation_name + "_id")
if obj_id == skip:
continue
history_for_obj[obj_id] = h
if h.time <= time:
skip = obj_id # we're far enough, go to next obj
return history_for_obj
def get_history_object_for(obj):
"""Construct history object for obj, i.e. instantiate history
object, copy relevant attributes and set a link to obj, but don't

14
ietf/utils/pdf.py Normal file
View file

@ -0,0 +1,14 @@
import re
def pdf_pages(filename):
"""Return number of pages in PDF."""
try:
infile = open(filename, "r")
except IOError:
return 0
for line in infile:
m = re.match('\] /Count ([0-9]+)',line)
if m:
return int(m.group(1))
return 0

View file

@ -7,7 +7,8 @@
# --- Add entries at the top ---
branch/iola/milestone-editing-bugfix-r9994@9996
branch/iola/meeting-history-r9663 @ 9669
branch/iola/milestone-editing-bugfix-r9994 @ 9996
#personal/rjs/v6.0.2.dev0@9540:9542
#personal/lars/6.0.2.dev0@9526
personal/lars/6.0.2.dev0@9525