utilities to agenda.py, fix a couple of things, remove obsolete test versions of agenda view, add support for viewing future IESG agendas through /agenda/YYYY-MM-DD/* (useful when testing) - Legacy-Id: 6395
583 lines
24 KiB
Python
583 lines
24 KiB
Python
# Copyright The IETF Trust 2007, All Rights Reserved
|
|
|
|
# Portion Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
#
|
|
# * Redistributions in binary form must reproduce the above
|
|
# copyright notice, this list of conditions and the following
|
|
# disclaimer in the documentation and/or other materials provided
|
|
# with the distribution.
|
|
#
|
|
# * Neither the name of the Nokia Corporation and/or its
|
|
# subsidiary(-ies) nor the names of its contributors may be used
|
|
# to endorse or promote products derived from this software
|
|
# without specific prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
import codecs, re, os, glob
|
|
import datetime
|
|
import tarfile
|
|
|
|
from django.views.generic.simple import direct_to_template
|
|
from django.views.decorators.vary import vary_on_cookie
|
|
from django.core.urlresolvers import reverse as urlreverse
|
|
from django.http import Http404, HttpResponse, HttpResponseForbidden, HttpResponseRedirect
|
|
from django.template import RequestContext, Context, loader
|
|
from django.shortcuts import render_to_response, get_object_or_404
|
|
from django.conf import settings
|
|
from django.utils import simplejson as json
|
|
from django import forms
|
|
|
|
from ietf.idtracker.models import IDInternal, InternetDraft, AreaGroup, Position, IESGLogin, Acronym
|
|
|
|
from ietf.iesg.models import TelechatDates, TelechatAgendaItem, WGAction
|
|
from ietf.idrfc.idrfc_wrapper import IdWrapper, RfcWrapper
|
|
|
|
from ietf.iesg.models import TelechatDate, TelechatAgendaItem
|
|
from ietf.ipr.models import IprDocAlias
|
|
from ietf.doc.models import Document, TelechatDocEvent, LastCallDocEvent, ConsensusDocEvent, DocEvent
|
|
from ietf.group.models import Group, GroupMilestone
|
|
from ietf.person.models import Person
|
|
|
|
from ietf.doc.utils import update_telechat
|
|
from ietf.ietfauth.utils import has_role, role_required
|
|
from ietf.iesg.agenda import get_agenda_date, agenda_data, agenda_docs, agenda_wg_actions, agenda_management_issues
|
|
|
|
def review_decisions(request, year=None):
|
|
events = DocEvent.objects.filter(type__in=("iesg_disapproved", "iesg_approved"))
|
|
|
|
years = sorted((d.year for d in events.dates('time', 'year')), reverse=True)
|
|
|
|
if year:
|
|
year = int(year)
|
|
events = events.filter(time__year=year)
|
|
else:
|
|
d = datetime.date.today() - datetime.timedelta(days=185)
|
|
d = datetime.date(d.year, d.month, 1)
|
|
events = events.filter(time__gte=d)
|
|
|
|
events = events.select_related("doc", "doc__intended_std_level").order_by("-time", "-id")
|
|
|
|
#proto_levels = ["bcp", "ds", "ps", "std"]
|
|
#doc_levels = ["exp", "inf"]
|
|
|
|
timeframe = u"%s" % year if year else u"the past 6 months"
|
|
|
|
return render_to_response('iesg/review_decisions.html',
|
|
dict(events=events,
|
|
years=years,
|
|
year=year,
|
|
timeframe=timeframe),
|
|
context_instance=RequestContext(request))
|
|
|
|
def agenda_json(request, date=None):
|
|
date = get_agenda_date(date)
|
|
|
|
data = {'telechat-date':str(date),
|
|
'as-of':str(datetime.datetime.utcnow()),
|
|
'sections':{}}
|
|
data['sections']['1'] = {'title':"Administrivia"}
|
|
data['sections']['1.1'] = {'title':"Roll Call"}
|
|
data['sections']['1.2'] = {'title':"Bash the Agenda"}
|
|
data['sections']['1.3'] = {'title':"Approval of the Minutes of Past Telechats"}
|
|
data['sections']['1.4'] = {'title':"List of Remaining Action Items from Last Telechat"}
|
|
data['sections']['2'] = {'title':"Protocol Actions"}
|
|
data['sections']['2.1'] = {'title':"WG Submissions"}
|
|
data['sections']['2.1.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['2.1.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['2.2'] = {'title':"Individual Submissions"}
|
|
data['sections']['2.2.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['2.2.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['2.3'] = {'title':"Individual Submissions"}
|
|
data['sections']['2.3.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['2.3.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['3'] = {'title':"Document Actions"}
|
|
data['sections']['3.1'] = {'title':"WG Submissions"}
|
|
data['sections']['3.1.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['3.1.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['3.2'] = {'title':"Individual Submissions Via AD"}
|
|
data['sections']['3.2.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['3.2.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['3.3'] = {'title':"Status Changes"}
|
|
data['sections']['3.3.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['3.3.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['3.4'] = {'title':"IRTF and Independent Submission Stream Documents"}
|
|
data['sections']['3.4.1'] = {'title':"New Items", 'docs':[]}
|
|
data['sections']['3.4.2'] = {'title':"Returning Items", 'docs':[]}
|
|
data['sections']['4'] = {'title':"Working Group Actions"}
|
|
data['sections']['4.1'] = {'title':"WG Creation"}
|
|
data['sections']['4.1.1'] = {'title':"Proposed for IETF Review", 'wgs':[]}
|
|
data['sections']['4.1.2'] = {'title':"Proposed for Approval", 'wgs':[]}
|
|
data['sections']['4.2'] = {'title':"WG Rechartering"}
|
|
data['sections']['4.2.1'] = {'title':"Under Evaluation for IETF Review", 'wgs':[]}
|
|
data['sections']['4.2.2'] = {'title':"Proposed for Approval", 'wgs':[]}
|
|
data['sections']['5'] = {'title':"IAB News We Can Use"}
|
|
data['sections']['6'] = {'title':"Management Issues"}
|
|
data['sections']['7'] = {'title':"Working Group News"}
|
|
|
|
docs = agenda_docs(date)
|
|
for section in docs.keys():
|
|
# in case the document is in a state that does not have an agenda section
|
|
if section == 's':
|
|
continue
|
|
|
|
s = str(".".join(list(section)[1:]))
|
|
if s[0:1] == '4':
|
|
# ignore these; not sure why they are included by agenda_docs
|
|
continue
|
|
|
|
if not docs[section]:
|
|
continue
|
|
|
|
# If needed, add a "For Action" section to agenda
|
|
if s[4:5] == '3':
|
|
data['sections'][s] = {'title':"For Action", 'docs':[]}
|
|
|
|
for d in docs[section]:
|
|
docinfo = {'docname':d.canonical_name(),
|
|
'title':d.title,
|
|
'ad':d.ad.name if d.ad else None }
|
|
if d.note:
|
|
docinfo['note'] = d.note
|
|
defer = d.active_defer_event()
|
|
if defer:
|
|
docinfo['defer-by'] = defer.by.name
|
|
docinfo['defer-at'] = str(defer.time)
|
|
if d.type_id == "draft":
|
|
docinfo['rev'] = d.rev
|
|
docinfo['intended-std-level'] = str(d.intended_std_level)
|
|
if d.rfc_number():
|
|
docinfo['rfc-number'] = d.rfc_number()
|
|
|
|
iana_state = d.get_state("draft-iana-review")
|
|
if iana_state and iana_state.slug in ("not-ok", "changed", "need-rev"):
|
|
docinfo['iana-review-state'] = str(iana_state)
|
|
|
|
if d.get_state_slug("draft-iesg") == "lc":
|
|
e = d.latest_event(LastCallDocEvent, type="sent_last_call")
|
|
if e:
|
|
docinfo['lastcall-expires'] = e.expires.strftime("%Y-%m-%d")
|
|
|
|
docinfo['consensus'] = None
|
|
e = d.latest_event(ConsensusDocEvent, type="changed_consensus")
|
|
if e:
|
|
docinfo['consensus'] = e.consensus
|
|
elif d.type_id == 'conflrev':
|
|
docinfo['rev'] = d.rev
|
|
td = d.relateddocument_set.get(relationship__slug='conflrev').target.document
|
|
docinfo['target-docname'] = td.canonical_name()
|
|
docinfo['target-title'] = td.title
|
|
docinfo['target-rev'] = td.rev
|
|
docinfo['intended-std-level'] = str(td.intended_std_level)
|
|
docinfo['stream'] = str(td.stream)
|
|
else:
|
|
# XXX check this -- is there nothing to set for
|
|
# all other documents here?
|
|
pass
|
|
data['sections'][s]['docs'] += [docinfo, ]
|
|
|
|
wgs = agenda_wg_actions(date)
|
|
for section in wgs.keys():
|
|
# in case the charter is in a state that does not have an agenda section
|
|
if section == 's':
|
|
continue
|
|
|
|
s = str(".".join(list(section)[1:]))
|
|
if s[0:1] != '4':
|
|
# ignore these; not sure why they are included by agenda_wg_actions
|
|
continue
|
|
|
|
if not wgs[section]:
|
|
continue
|
|
|
|
for doc in wgs[section]:
|
|
wginfo = {'docname': doc.canonical_name(),
|
|
'rev': doc.rev,
|
|
'wgname': doc.group.name,
|
|
'acronym': doc.group.acronym,
|
|
'ad': doc.group.ad.name}
|
|
data['sections'][s]['wgs'] += [wginfo, ]
|
|
|
|
mgmt = agenda_management_issues(date)
|
|
num = 0
|
|
for m in mgmt:
|
|
num += 1
|
|
data['sections']["6.%d" % num] = {'title':m.title}
|
|
|
|
return HttpResponse(json.dumps(data, indent=2), mimetype='text/plain')
|
|
|
|
@vary_on_cookie
|
|
def agenda(request, date=None):
|
|
data = agenda_data(request, date)
|
|
data['private'] = 'private' in request.REQUEST
|
|
data['settings'] = settings
|
|
return render_to_response("iesg/agenda.html", data, context_instance=RequestContext(request))
|
|
|
|
def agenda_txt(request, date=None):
|
|
data = agenda_data(request, date)
|
|
return render_to_response("iesg/agenda.txt", data, context_instance=RequestContext(request), mimetype="text/plain")
|
|
|
|
def agenda_scribe_template(request, date=None):
|
|
date = get_agenda_date(date)
|
|
docs = agenda_docs(date)
|
|
return render_to_response('iesg/scribe_template.html', { 'date':str(date), 'docs':docs }, context_instance=RequestContext(request) )
|
|
|
|
@role_required('Area Director', 'Secretariat')
|
|
def agenda_moderator_package(request, date=None):
|
|
data = agenda_data(request, date)
|
|
data['ads'] = sorted(Person.objects.filter(role__name="ad", role__group__state="active"),
|
|
key=lambda p: p.name_parts()[3])
|
|
return render_to_response("iesg/moderator_package.html", data, context_instance=RequestContext(request))
|
|
|
|
@role_required('Area Director', 'Secretariat')
|
|
def agenda_package(request, date=None):
|
|
data = agenda_data(request)
|
|
return render_to_response("iesg/agenda_package.txt", data, context_instance=RequestContext(request), mimetype='text/plain')
|
|
|
|
|
|
def agenda_documents_txt(request):
|
|
dates = TelechatDates.objects.all()[0].dates()
|
|
docs = []
|
|
for date in dates:
|
|
from ietf.doc.models import TelechatDocEvent
|
|
for d in Document.objects.filter(docevent__telechatdocevent__telechat_date=date).distinct():
|
|
if d.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date == date:
|
|
docs.append(d)
|
|
t = loader.get_template('iesg/agenda_documents.txt')
|
|
c = Context({'docs':docs,'special_stream_list':['ise','irtf']})
|
|
return HttpResponse(t.render(c), mimetype='text/plain')
|
|
|
|
class RescheduleForm(forms.Form):
|
|
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False)
|
|
clear_returning_item = forms.BooleanField(initial=False, required=False)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
dates = kwargs.pop('telechat_dates')
|
|
|
|
super(self.__class__, self).__init__(*args, **kwargs)
|
|
|
|
# telechat choices
|
|
init = kwargs['initial']['telechat_date']
|
|
if init and init not in dates:
|
|
dates.insert(0, init)
|
|
|
|
choices = [("", "(not on agenda)")]
|
|
for d in dates:
|
|
choices.append((d, d.strftime("%Y-%m-%d")))
|
|
|
|
self.fields['telechat_date'].choices = choices
|
|
|
|
def handle_reschedule_form(request, doc, dates):
|
|
initial = dict(telechat_date=doc.telechat_date())
|
|
|
|
formargs = dict(telechat_dates=dates,
|
|
prefix="%s" % doc.name,
|
|
initial=initial)
|
|
if request.method == 'POST':
|
|
form = RescheduleForm(request.POST, **formargs)
|
|
if form.is_valid():
|
|
login = request.user.get_profile()
|
|
update_telechat(request, doc, login,
|
|
form.cleaned_data['telechat_date'],
|
|
False if form.cleaned_data['clear_returning_item'] else None)
|
|
doc.time = datetime.datetime.now()
|
|
doc.save()
|
|
else:
|
|
form = RescheduleForm(**formargs)
|
|
|
|
form.show_clear = doc.returning_item()
|
|
return form
|
|
|
|
def agenda_documents(request):
|
|
dates = TelechatDates.objects.all()[0].dates()
|
|
from ietf.doc.models import TelechatDocEvent
|
|
docs = []
|
|
for d in Document.objects.filter(docevent__telechatdocevent__telechat_date__in=dates).distinct():
|
|
if d.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date in dates:
|
|
docs.append(d)
|
|
|
|
e = d.latest_event(type="started_iesg_process")
|
|
d.balloting_started = e.time if e else datetime.datetime.min
|
|
docs.sort(key=lambda d: d.balloting_started)
|
|
for i in docs:
|
|
i.reschedule_form = handle_reschedule_form(request, i, dates)
|
|
|
|
# some may have been taken off the schedule by the reschedule form
|
|
docs = [d for d in docs if d.telechat_date()]
|
|
|
|
telechats = []
|
|
for date in dates:
|
|
matches = filter(lambda x: x.telechat_date() == date, docs)
|
|
res = {}
|
|
for i in matches:
|
|
section_key = "s" + get_doc_section(i)
|
|
if section_key not in res:
|
|
res[section_key] = []
|
|
if i.type_id=='draft':
|
|
if i.get_state_slug()!="rfc":
|
|
i.iprUrl = "/ipr/search?option=document_search&id_document_tag=" + str(i.name)
|
|
else:
|
|
i.iprUrl = "/ipr/search?option=rfc_search&rfc_search=" + str(i.rfc_number())
|
|
i.iprCount = len(i.ipr())
|
|
res[section_key].append(i)
|
|
telechats.append({'date':date, 'docs':res})
|
|
return direct_to_template(request, 'iesg/agenda_documents_redesign.html', {'telechats':telechats, 'hide_telechat_date':True})
|
|
|
|
def telechat_docs_tarfile(request,year,month,day):
|
|
from tempfile import mkstemp
|
|
date=datetime.date(int(year),int(month),int(day))
|
|
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
|
from ietf.doc.models import TelechatDocEvent
|
|
docs = []
|
|
for d in IDInternal.objects.filter(docevent__telechatdocevent__telechat_date=date).distinct():
|
|
if d.latest_event(TelechatDocEvent, type="scheduled_for_telechat").telechat_date == date:
|
|
docs.append(d)
|
|
else:
|
|
docs= IDInternal.objects.filter(telechat_date=date, primary_flag=1, agenda=1)
|
|
response = HttpResponse(mimetype='application/octet-stream')
|
|
response['Content-Disposition'] = 'attachment; filename=telechat-%s-%s-%s-docs.tgz'%(year, month, day)
|
|
tarstream = tarfile.open('','w:gz',response)
|
|
mfh, mfn = mkstemp()
|
|
manifest = open(mfn, "w")
|
|
for doc in docs:
|
|
doc_path = os.path.join(settings.INTERNET_DRAFT_PATH, doc.draft.filename+"-"+doc.draft.revision_display()+".txt")
|
|
if os.path.exists(doc_path):
|
|
try:
|
|
tarstream.add(doc_path, str(doc.draft.filename+"-"+doc.draft.revision_display()+".txt"))
|
|
manifest.write("Included: "+doc_path+"\n")
|
|
except Exception, e:
|
|
manifest.write(("Failed (%s): "%e)+doc_path+"\n")
|
|
else:
|
|
manifest.write("Not found: "+doc_path+"\n")
|
|
manifest.close()
|
|
tarstream.add(mfn, "manifest.txt")
|
|
tarstream.close()
|
|
os.unlink(mfn)
|
|
return response
|
|
|
|
def discusses(request):
|
|
res = []
|
|
|
|
for d in IDInternal.objects.filter(states__type="draft-iesg", states__slug__in=("pub-req", "ad-eval", "review-e", "lc-req", "lc", "writeupw", "goaheadw", "iesg-eva", "defer", "watching"), docevent__ballotpositiondocevent__pos="discuss").distinct():
|
|
found = False
|
|
for p in d.positions.all():
|
|
if p.discuss:
|
|
found = True
|
|
break
|
|
|
|
if not found:
|
|
continue
|
|
|
|
if d.rfc_flag:
|
|
doc = RfcWrapper(d)
|
|
else:
|
|
doc = IdWrapper(draft=d)
|
|
|
|
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
|
|
# quick hack - to be removed when the proxy code is removed
|
|
doc.underlying = doc.underlying_document()
|
|
doc.underlying.milestones = d.groupmilestone_set.filter(state="active").order_by("time").select_related("group")
|
|
|
|
res.append(doc)
|
|
|
|
return direct_to_template(request, 'iesg/discusses.html', {'docs':res})
|
|
|
|
@role_required('Area Director', 'Secretariat')
|
|
def milestones_needing_review(request):
|
|
# collect milestones, grouped on AD and group
|
|
ads = {}
|
|
for m in GroupMilestone.objects.filter(state="review").exclude(group__state="concluded", group__ad=None).distinct().select_related("group", "group__ad"):
|
|
groups = ads.setdefault(m.group.ad, {})
|
|
milestones = groups.setdefault(m.group, [])
|
|
milestones.append(m)
|
|
|
|
ad_list = []
|
|
for ad, groups in ads.iteritems():
|
|
ad_list.append(ad)
|
|
ad.groups_needing_review = sorted(groups, key=lambda g: g.acronym)
|
|
for g, milestones in groups.iteritems():
|
|
g.milestones_needing_review = sorted(milestones, key=lambda m: m.due)
|
|
|
|
return render_to_response('iesg/milestones_needing_review.html',
|
|
dict(ads=sorted(ad_list, key=lambda ad: ad.plain_name()),
|
|
),
|
|
context_instance=RequestContext(request))
|
|
|
|
def parse_wg_action_file(path):
|
|
f = open(path, 'rU')
|
|
|
|
line = f.readline()
|
|
while line and not line.strip():
|
|
line = f.readline()
|
|
|
|
# name
|
|
m = re.search(r'([^\(]*) \(', line)
|
|
if not m:
|
|
return None
|
|
name = m.group(1)
|
|
|
|
# acronym
|
|
m = re.search(r'\((\w+)\)', line)
|
|
if not m:
|
|
return None
|
|
acronym = m.group(1)
|
|
|
|
# date
|
|
line = f.readline()
|
|
m = re.search(r'(\d{4})-(\d{2})-(\d{2})', line)
|
|
while line and not m:
|
|
line = f.readline()
|
|
m = re.search(r'(\d{4})-(\d{2})-(\d{2})', line)
|
|
|
|
last_updated = None
|
|
if m:
|
|
try:
|
|
last_updated = datetime.date(int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
|
except:
|
|
pass
|
|
|
|
# token
|
|
line = f.readline()
|
|
while line and not 'area director' in line.lower():
|
|
line = f.readline()
|
|
|
|
line = f.readline()
|
|
line = f.readline()
|
|
m = re.search(r'\s*(\w+)\s*', line)
|
|
token = ""
|
|
if m:
|
|
token = m.group(1)
|
|
|
|
return dict(filename=os.path.basename(path), name=name, acronym=acronym,
|
|
status_date=last_updated, token=token)
|
|
|
|
def get_possible_wg_actions():
|
|
res = []
|
|
charters = glob.glob(os.path.join(settings.IESG_WG_EVALUATION_DIR, '*-charter.txt'))
|
|
for path in charters:
|
|
d = parse_wg_action_file(path)
|
|
if d:
|
|
if not d['status_date']:
|
|
d['status_date'] = datetime.date(1900,1,1)
|
|
res.append(d)
|
|
|
|
res.sort(key=lambda x: x['status_date'])
|
|
|
|
return res
|
|
|
|
|
|
@role_required('Area Director', 'Secretariat')
|
|
def working_group_actions(request):
|
|
current_items = WGAction.objects.order_by('status_date').select_related()
|
|
|
|
if request.method == 'POST' and has_role(request.user, 'Secretariat'):
|
|
filename = request.POST.get('filename')
|
|
if filename and filename in os.listdir(settings.IESG_WG_EVALUATION_DIR):
|
|
if 'delete' in request.POST:
|
|
os.unlink(os.path.join(settings.IESG_WG_EVALUATION_DIR, filename))
|
|
if 'add' in request.POST:
|
|
d = parse_wg_action_file(os.path.join(settings.IESG_WG_EVALUATION_DIR, filename))
|
|
qstr = "?" + "&".join("%s=%s" % t for t in d.iteritems())
|
|
return HttpResponseRedirect(urlreverse('iesg_add_working_group_action') + qstr)
|
|
|
|
|
|
skip = [c.group_acronym.acronym for c in current_items]
|
|
possible_items = filter(lambda x: x['acronym'] not in skip,
|
|
get_possible_wg_actions())
|
|
|
|
return render_to_response("iesg/working_group_actions.html",
|
|
dict(current_items=current_items,
|
|
possible_items=possible_items),
|
|
context_instance=RequestContext(request))
|
|
|
|
class EditWGActionForm(forms.ModelForm):
|
|
token_name = forms.ChoiceField(required=True)
|
|
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False)
|
|
|
|
class Meta:
|
|
model = WGAction
|
|
fields = ['status_date', 'token_name', 'category', 'note']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(self.__class__, self).__init__(*args, **kwargs)
|
|
|
|
# token name choices
|
|
self.fields['token_name'].choices = [("", "(None)")] + [(p.plain_name(), p.plain_name()) for p in IESGLogin.active_iesg().order_by('first_name')]
|
|
|
|
# telechat choices
|
|
dates = TelechatDates.objects.all()[0].dates()
|
|
init = kwargs['initial']['telechat_date']
|
|
if init and init not in dates:
|
|
dates.insert(0, init)
|
|
|
|
choices = [("", "(not on agenda)")]
|
|
for d in dates:
|
|
choices.append((d, d.strftime("%Y-%m-%d")))
|
|
|
|
self.fields['telechat_date'].choices = choices
|
|
|
|
|
|
@role_required('Secretariat')
|
|
def edit_working_group_action(request, wga_id):
|
|
if wga_id != None:
|
|
wga = get_object_or_404(WGAction, pk=wga_id)
|
|
else:
|
|
wga = WGAction()
|
|
try:
|
|
wga.group_acronym = Acronym.objects.get(acronym=request.GET.get('acronym'))
|
|
except Acronym.DoesNotExist:
|
|
pass
|
|
|
|
wga.token_name = request.GET.get('token')
|
|
try:
|
|
d = datetime.datetime.strptime(request.GET.get('status_date'), '%Y-%m-%d').date()
|
|
except:
|
|
d = datetime.date.today()
|
|
wga.status_date = d
|
|
wga.telechat_date = TelechatDates.objects.all()[0].date1
|
|
wga.agenda = True
|
|
|
|
initial = dict(telechat_date=wga.telechat_date if wga.agenda else None)
|
|
|
|
if request.method == 'POST':
|
|
if "delete" in request.POST:
|
|
wga.delete()
|
|
return HttpResponseRedirect(urlreverse('iesg_working_group_actions'))
|
|
|
|
form = EditWGActionForm(request.POST, instance=wga, initial=initial)
|
|
if form.is_valid():
|
|
form.save(commit=False)
|
|
wga.agenda = bool(form.cleaned_data['telechat_date'])
|
|
if wga.category in (11, 21):
|
|
wga.agenda = False
|
|
if wga.agenda:
|
|
wga.telechat_date = form.cleaned_data['telechat_date']
|
|
wga.save()
|
|
return HttpResponseRedirect(urlreverse('iesg_working_group_actions'))
|
|
else:
|
|
form = EditWGActionForm(instance=wga, initial=initial)
|
|
|
|
|
|
return render_to_response("iesg/edit_working_group_action.html",
|
|
dict(wga=wga,
|
|
form=form),
|
|
context_instance=RequestContext(request))
|