meeting AJAX code is using PUT instead of POST (even if it's not PUT'ing in the literal sense but POST'ing). Theoretical discussions aside, Django has poor support for PUTs turned POSTs so rewriting them removes the need for a couple of hacks, and makes it easier to test. - Legacy-Id: 7067
589 lines
23 KiB
Python
589 lines
23 KiB
Python
# Copyright The IETF Trust 2007, All Rights Reserved
|
|
|
|
import datetime
|
|
import os
|
|
import re
|
|
import tarfile
|
|
import debug
|
|
import urllib
|
|
import json
|
|
|
|
from tempfile import mkstemp
|
|
|
|
from django import forms
|
|
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
|
from django.http import HttpResponse, Http404
|
|
from django.core.urlresolvers import reverse
|
|
from django.db.models import Q
|
|
from django.template import RequestContext
|
|
from django.template.loader import render_to_string
|
|
from django.conf import settings
|
|
from django.utils.decorators import decorator_from_middleware
|
|
from django.middleware.gzip import GZipMiddleware
|
|
from django.db.models import Max
|
|
from django.forms.models import modelform_factory
|
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
|
|
|
from ietf.utils.pipe import pipe
|
|
from ietf.ietfauth.utils import role_required, has_role
|
|
from ietf.doc.models import Document, State
|
|
from ietf.person.models import Person
|
|
from ietf.meeting.models import Meeting, TimeSlot, Session, Schedule
|
|
from ietf.group.models import Group
|
|
|
|
from ietf.meeting.helpers import get_areas
|
|
from ietf.meeting.helpers import build_all_agenda_slices, get_wg_name_list
|
|
from ietf.meeting.helpers import get_scheduledsessions_from_schedule, 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
|
|
|
|
@decorator_from_middleware(GZipMiddleware)
|
|
def materials(request, meeting_num=None):
|
|
meeting = get_meeting(meeting_num)
|
|
|
|
begin_date = meeting.get_submission_start_date()
|
|
cut_off_date = meeting.get_submission_cut_off_date()
|
|
cor_cut_off_date = meeting.get_submission_correction_date()
|
|
now = datetime.date.today()
|
|
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", {
|
|
'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)
|
|
sessions = Session.objects.filter(meeting__number=meeting_num, scheduledsession__schedule=schedule)
|
|
plenaries = sessions.filter(name__icontains='plenary')
|
|
ietf = sessions.filter(group__parent__type__slug = 'area').exclude(group__acronym='edu')
|
|
irtf = sessions.filter(group__parent__acronym = 'irtf')
|
|
training = sessions.filter(group__acronym__in=['edu','iaoc'])
|
|
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", {
|
|
'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')
|
|
if meetings:
|
|
return redirect(materials, meetings[0].number)
|
|
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
|
|
|
|
class SaveAsForm(forms.Form):
|
|
savename = forms.CharField(max_length=100)
|
|
|
|
@role_required('Area Director','Secretariat')
|
|
def agenda_create(request, num=None, schedule_name=None):
|
|
meeting = get_meeting(num)
|
|
schedule = get_schedule(meeting, schedule_name)
|
|
|
|
if schedule is None:
|
|
# here we have to return some ajax to display an error.
|
|
raise Http404("No meeting information for meeting %s schedule %s available" % (num,schedule_name))
|
|
|
|
# authorization was enforced by the @group_require decorator above.
|
|
|
|
saveasform = SaveAsForm(request.POST)
|
|
if not saveasform.is_valid():
|
|
return HttpResponse(status=404)
|
|
|
|
savedname = saveasform.cleaned_data['savename']
|
|
|
|
# create the new schedule, and copy the scheduledsessions
|
|
try:
|
|
sched = meeting.schedule_set.get(name=savedname, owner=request.user.person)
|
|
if sched:
|
|
# XXX needs to record a session error and redirect to where?
|
|
return redirect(edit_agenda, meeting.number, sched.name)
|
|
|
|
except Schedule.DoesNotExist:
|
|
pass
|
|
|
|
# must be done
|
|
newschedule = Schedule(name=savedname,
|
|
owner=request.user.person,
|
|
meeting=meeting,
|
|
visible=False,
|
|
public=False)
|
|
|
|
newschedule.save()
|
|
if newschedule is None:
|
|
return HttpResponse(status=500)
|
|
|
|
# keep a mapping so that extendedfrom references can be chased.
|
|
mapping = {};
|
|
for ss in schedule.scheduledsession_set.all():
|
|
# hack to copy the object, creating a new one
|
|
# just reset the key, and save it again.
|
|
oldid = ss.pk
|
|
ss.pk = None
|
|
ss.schedule=newschedule
|
|
ss.save()
|
|
mapping[oldid] = ss.pk
|
|
#print "Copying %u to %u" % (oldid, ss.pk)
|
|
|
|
# now fix up any extendedfrom references to new set.
|
|
for ss in newschedule.scheduledsession_set.all():
|
|
if ss.extendedfrom is not None:
|
|
oldid = ss.extendedfrom.id
|
|
newid = mapping[oldid]
|
|
#print "Fixing %u to %u" % (oldid, newid)
|
|
ss.extendedfrom = newschedule.scheduledsession_set.get(pk = newid)
|
|
ss.save()
|
|
|
|
|
|
# now redirect to this new schedule.
|
|
return redirect(edit_agenda, meeting.number, newschedule.name)
|
|
|
|
|
|
@decorator_from_middleware(GZipMiddleware)
|
|
@ensure_csrf_cookie
|
|
def edit_timeslots(request, num=None):
|
|
|
|
meeting = get_meeting(num)
|
|
timeslots = meeting.timeslot_set.exclude(location=None).select_related("location", "type")
|
|
|
|
time_slices,date_slices,slots = meeting.build_timeslices()
|
|
|
|
meeting_base_url = request.build_absolute_uri(meeting.base_url())
|
|
site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash
|
|
|
|
rooms = meeting.room_set.order_by("capacity")
|
|
|
|
from ietf.meeting.ajax import timeslot_roomsurl, AddRoomForm, timeslot_slotsurl, AddSlotForm
|
|
|
|
roomsurl = reverse(timeslot_roomsurl, args=[meeting.number])
|
|
adddayurl = reverse(timeslot_slotsurl, args=[meeting.number])
|
|
|
|
return HttpResponse(render_to_string("meeting/timeslot_edit.html",
|
|
{"timeslots": timeslots,
|
|
"meeting_base_url": meeting_base_url,
|
|
"site_base_url": site_base_url,
|
|
"rooms":rooms,
|
|
"addroom": AddRoomForm(),
|
|
"roomsurl": roomsurl,
|
|
"addday": AddSlotForm(),
|
|
"adddayurl":adddayurl,
|
|
"time_slices":time_slices,
|
|
"slot_slices": slots,
|
|
"date_slices":date_slices,
|
|
"meeting":meeting},
|
|
RequestContext(request)), content_type="text/html")
|
|
|
|
##############################################################################
|
|
#@role_required('Area Director','Secretariat')
|
|
# disable the above security for now, check it below.
|
|
@decorator_from_middleware(GZipMiddleware)
|
|
@ensure_csrf_cookie
|
|
def edit_agenda(request, num=None, schedule_name=None):
|
|
|
|
if request.method == 'POST':
|
|
return agenda_create(request, num, schedule_name)
|
|
|
|
user = request.user
|
|
requestor = "AnonymousUser"
|
|
if not user.is_anonymous():
|
|
#print "user: %s" % (user)
|
|
try:
|
|
requestor = user.person
|
|
except Person.DoesNotExist:
|
|
# if we can not find them, leave them alone, only used for debugging.
|
|
pass
|
|
|
|
meeting = get_meeting(num)
|
|
#sys.stdout.write("requestor: %s for sched_name: %s \n" % ( requestor, schedule_name ))
|
|
schedule = get_schedule(meeting, schedule_name)
|
|
#sys.stdout.write("2 requestor: %u for sched owned by: %u \n" % ( requestor.id, schedule.owner.id ))
|
|
|
|
meeting_base_url = request.build_absolute_uri(meeting.base_url())
|
|
site_base_url = request.build_absolute_uri('/')[:-1] # skip the trailing slash
|
|
|
|
rooms = meeting.room_set.order_by("capacity")
|
|
rooms = rooms.all()
|
|
saveas = SaveAsForm()
|
|
saveasurl=reverse(edit_agenda,
|
|
args=[meeting.number, schedule.name])
|
|
|
|
can_see, can_edit = agenda_permissions(meeting, schedule, user)
|
|
|
|
if not can_see:
|
|
#sys.stdout.write("visible: %s public: %s owner: %s request from: %s\n" % (
|
|
# schedule.visible, schedule.public, schedule.owner, requestor))
|
|
return HttpResponse(render_to_string("meeting/private_agenda.html",
|
|
{"schedule":schedule,
|
|
"meeting": meeting,
|
|
"meeting_base_url":meeting_base_url},
|
|
RequestContext(request)), status=403, content_type="text/html")
|
|
|
|
sessions = meeting.sessions_that_can_meet.order_by("id", "group", "requested_by")
|
|
scheduledsessions = get_all_scheduledsessions_from_schedule(schedule)
|
|
|
|
session_jsons = [ json.dumps(s.json_dict(site_base_url)) for s in sessions ]
|
|
|
|
# useful when debugging javascript
|
|
#session_jsons = session_jsons[1:20]
|
|
|
|
# get_modified_from needs the query set, not the list
|
|
modified = get_modified_from_scheduledsessions(scheduledsessions)
|
|
|
|
area_list = get_areas()
|
|
wg_name_list = get_wg_name_list(scheduledsessions)
|
|
wg_list = get_wg_list(wg_name_list)
|
|
ads = find_ads_for_meeting(meeting)
|
|
for ad in ads:
|
|
# set the default to avoid needing extra arguments in templates
|
|
# django 1.3+
|
|
ad.default_hostscheme = site_base_url
|
|
|
|
time_slices,date_slices = build_all_agenda_slices(scheduledsessions, True)
|
|
|
|
return HttpResponse(render_to_string("meeting/landscape_edit.html",
|
|
{"schedule":schedule,
|
|
"saveas": saveas,
|
|
"saveasurl": saveasurl,
|
|
"meeting_base_url": meeting_base_url,
|
|
"site_base_url": site_base_url,
|
|
"rooms":rooms,
|
|
"time_slices":time_slices,
|
|
"date_slices":date_slices,
|
|
"modified": modified,
|
|
"meeting":meeting,
|
|
"area_list": area_list,
|
|
"area_directors" : ads,
|
|
"wg_list": wg_list ,
|
|
"session_jsons": session_jsons,
|
|
"scheduledsessions": scheduledsessions,
|
|
"show_inline": set(["txt","htm","html"]) },
|
|
RequestContext(request)), content_type="text/html")
|
|
|
|
##############################################################################
|
|
# show the properties associated with an agenda (visible, public)
|
|
# this page uses ajax POST requests to the API
|
|
#
|
|
AgendaPropertiesForm = modelform_factory(Schedule, fields=('name','visible', 'public'))
|
|
|
|
@role_required('Area Director','Secretariat')
|
|
@decorator_from_middleware(GZipMiddleware)
|
|
@ensure_csrf_cookie
|
|
def edit_agenda_properties(request, num=None, schedule_name=None):
|
|
|
|
meeting = get_meeting(num)
|
|
schedule = get_schedule(meeting, schedule_name)
|
|
form = AgendaPropertiesForm(instance=schedule)
|
|
|
|
return HttpResponse(render_to_string("meeting/properties_edit.html",
|
|
{"schedule":schedule,
|
|
"form":form,
|
|
"meeting":meeting},
|
|
RequestContext(request)), content_type="text/html")
|
|
|
|
##############################################################################
|
|
# show list of agendas.
|
|
#
|
|
|
|
@role_required('Area Director','Secretariat')
|
|
@decorator_from_middleware(GZipMiddleware)
|
|
@ensure_csrf_cookie
|
|
def edit_agendas(request, num=None, order=None):
|
|
|
|
#if request.method == 'POST':
|
|
# return agenda_create(request, num, schedule_name)
|
|
|
|
meeting = get_meeting(num)
|
|
user = request.user
|
|
|
|
schedules = meeting.schedule_set
|
|
if not has_role(user, 'Secretariat'):
|
|
schedules = schedules.filter(visible = True) | schedules.filter(owner = user.person)
|
|
|
|
schedules = schedules.order_by('owner', 'name')
|
|
|
|
return HttpResponse(render_to_string("meeting/agenda_list.html",
|
|
{"meeting": meeting,
|
|
"schedules": schedules.all()
|
|
},
|
|
RequestContext(request)),
|
|
content_type="text/html")
|
|
|
|
@ensure_csrf_cookie
|
|
def agenda(request, num=None, name=None, base=None, ext=None):
|
|
base = base if base else 'agenda'
|
|
ext = ext if ext else '.html'
|
|
if 'iPhone' in get_user_agent(request) and ext == ".html":
|
|
base = 'm_agenda'
|
|
mimetype = {".html":"text/html", ".txt": "text/plain", ".ics":"text/calendar", ".csv":"text/csv"}
|
|
meeting = get_meeting(num)
|
|
schedule = get_schedule(meeting, name)
|
|
updated = meeting_updated(meeting)
|
|
return HttpResponse(render_to_string("meeting/"+base+ext,
|
|
{"schedule":schedule, "updated": updated}, RequestContext(request)), content_type=mimetype[ext])
|
|
|
|
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":
|
|
d = d.filter(session__name__icontains="technical", session__slots__type="plenary")
|
|
elif session == "plenaryw":
|
|
d = d.filter(session__name__icontains="admin", session__slots__type="plenary")
|
|
else:
|
|
d = d.filter(session__group__acronym=session)
|
|
|
|
if d:
|
|
agenda = d[0]
|
|
content = read_agenda_file(num, agenda) or "Could not read agenda file"
|
|
_, ext = os.path.splitext(agenda.external_url)
|
|
ext = ext.lstrip(".").lower()
|
|
|
|
if ext == "txt":
|
|
return HttpResponse(content, content_type="text/plain")
|
|
elif ext == "pdf":
|
|
return HttpResponse(content, content_type="application/pdf")
|
|
else:
|
|
return HttpResponse(content)
|
|
|
|
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()
|
|
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()
|
|
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:
|
|
agenda = Document.objects.filter(type="agenda",
|
|
session__meeting__number=num,
|
|
session__group__acronym=session,
|
|
states=State.objects.get(type="agenda", slug="active")).distinct().get()
|
|
except Document.DoesNotExist:
|
|
raise Http404
|
|
|
|
drafts = set()
|
|
content = read_agenda_file(num, agenda)
|
|
if content:
|
|
drafts.update(re.findall('(draft-[-a-z0-9]*)', content))
|
|
|
|
result = []
|
|
for draft in drafts:
|
|
try:
|
|
if re.search('-[0-9]{2}$', draft):
|
|
doc_name = draft
|
|
else:
|
|
doc = Document.objects.get(name=draft)
|
|
doc_name = draft + "-" + doc.rev
|
|
|
|
if doc_name not in result:
|
|
result.append(doc_name)
|
|
except Document.DoesNotExist:
|
|
pass
|
|
|
|
return sorted(result)
|
|
|
|
def session_draft_tarfile(request, num, session):
|
|
drafts = session_draft_list(num, session);
|
|
|
|
response = HttpResponse(content_type='application/octet-stream')
|
|
response['Content-Disposition'] = 'attachment; filename=%s-drafts.tgz'%(session)
|
|
tarstream = tarfile.open('','w:gz',response)
|
|
mfh, mfn = mkstemp()
|
|
manifest = open(mfn, "w")
|
|
|
|
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 os.path.exists(pdf_path):
|
|
try:
|
|
tarstream.add(pdf_path, str(doc_name + ".pdf"))
|
|
manifest.write("Included: "+pdf_path+"\n")
|
|
except Exception, e:
|
|
manifest.write(("Failed (%s): "%e)+pdf_path+"\n")
|
|
else:
|
|
manifest.write("Not found: "+pdf_path+"\n")
|
|
|
|
manifest.close()
|
|
tarstream.add(mfn, "manifest.txt")
|
|
tarstream.close()
|
|
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
|
|
pmh, pmn = mkstemp()
|
|
pdfmarks = open(pmn, "w")
|
|
pdf_list = ""
|
|
|
|
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 (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
|
|
curr_page = curr_page + pages
|
|
|
|
pdfmarks.close()
|
|
pdfh, pdfn = mkstemp()
|
|
pipe("gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=" + pdfn + " " + pdf_list + " " + pmn)
|
|
|
|
pdf = open(pdfn,"r")
|
|
pdf_contents = pdf.read()
|
|
pdf.close()
|
|
|
|
os.unlink(pmn)
|
|
os.unlink(pdfn)
|
|
return HttpResponse(pdf_contents, content_type="application/pdf")
|
|
|
|
def week_view(request, num=None):
|
|
meeting = get_meeting(num)
|
|
timeslots = TimeSlot.objects.filter(meeting=meeting)
|
|
|
|
template = "meeting/week-view.html"
|
|
return render_to_response(template,
|
|
{"timeslots":timeslots,"render_types":["Session","Other","Break","Plenary"]}, context_instance=RequestContext(request))
|
|
|
|
def ical_agenda(request, num=None, name=None, ext=None):
|
|
meeting = get_meeting(num)
|
|
schedule = get_schedule(meeting, name)
|
|
updated = meeting_updated(meeting)
|
|
|
|
q = request.META.get('QUERY_STRING','') or ""
|
|
filter = set(urllib.unquote(q).lower().split(','))
|
|
include = [ i for i in filter if not (i.startswith('-') or i.startswith('~')) ]
|
|
include_types = set(["plenary","other"])
|
|
exclude = []
|
|
|
|
# Process the special flags.
|
|
# "-wgname" will remove a working group from the output.
|
|
# "~Type" will add that type to the output.
|
|
# "-~Type" will remove that type from the output
|
|
# Current types are:
|
|
# Session, Other (default on), Break, Plenary (default on)
|
|
# Non-Working Group "wg names" include:
|
|
# 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:]])
|
|
|
|
assignments = schedule.assignments.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))
|
|
|
|
return HttpResponse(render_to_string("meeting/agenda.ics",
|
|
{"schedule":schedule, "assignments":assignments, "updated":updated},
|
|
RequestContext(request)), content_type="text/calendar")
|
|
|
|
def meeting_requests(request, num=None) :
|
|
meeting = get_meeting(num)
|
|
sessions = Session.objects.filter(meeting__number=meeting.number,group__parent__isnull = False).exclude(requested_by=0).order_by("group__parent__acronym","status__slug","group__acronym")
|
|
|
|
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",
|
|
{"meeting": meeting, "sessions":sessions,
|
|
"groups_not_meeting": groups_not_meeting},
|
|
context_instance=RequestContext(request))
|
|
|