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:
commit
fb66c1856f
|
@ -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]):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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">×</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">×</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 %}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
14
ietf/utils/pdf.py
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue