Move the Secretariat group email utility to wginfo and the rest of the wgcharter stuff to doc/(views|urls|utils)_charter.py alongside the other document types
- Legacy-Id: 7121
This commit is contained in:
parent
c4313a4f42
commit
7e00fa1424
|
@ -19,7 +19,7 @@ from ietf.group.utils import *
|
||||||
from ietf.name.models import *
|
from ietf.name.models import *
|
||||||
from ietf.person.models import *
|
from ietf.person.models import *
|
||||||
from ietf.iesg.models import TelechatDate
|
from ietf.iesg.models import TelechatDate
|
||||||
from ietf.wgcharter.utils import *
|
from ietf.doc.utils_charter import *
|
||||||
|
|
||||||
class EditCharterTests(TestCase):
|
class EditCharterTests(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -71,13 +71,13 @@ class EditCharterTests(TestCase):
|
||||||
def find_event(t):
|
def find_event(t):
|
||||||
return [e for e in charter.docevent_set.all()[:events_now - events_before] if e.type == t]
|
return [e for e in charter.docevent_set.all()[:events_now - events_before] if e.type == t]
|
||||||
|
|
||||||
self.assertTrue("State changed" in find_event("changed_document")[0].desc)
|
self.assertTrue("state changed" in find_event("changed_document")[0].desc.lower())
|
||||||
|
|
||||||
if slug in ("intrev", "iesgrev"):
|
if slug in ("intrev", "iesgrev"):
|
||||||
self.assertTrue(find_event("created_ballot"))
|
self.assertTrue(find_event("created_ballot"))
|
||||||
|
|
||||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||||
self.assertTrue("State changed" in outbox[-1]['Subject'])
|
self.assertTrue("state changed" in outbox[-1]['Subject'].lower())
|
||||||
|
|
||||||
def test_edit_telechat_date(self):
|
def test_edit_telechat_date(self):
|
||||||
make_test_data()
|
make_test_data()
|
||||||
|
@ -272,7 +272,7 @@ class ApproveCharterTests(TestCase):
|
||||||
|
|
||||||
self.assertEqual(len(outbox), mailbox_before + 2)
|
self.assertEqual(len(outbox), mailbox_before + 2)
|
||||||
self.assertTrue("WG Action" in outbox[-1]['Subject'])
|
self.assertTrue("WG Action" in outbox[-1]['Subject'])
|
||||||
self.assertTrue("Charter approved" in outbox[-2]['Subject'])
|
self.assertTrue("approved" in outbox[-2]['Subject'].lower())
|
||||||
|
|
||||||
self.assertEqual(group.groupmilestone_set.filter(state="charter").count(), 0)
|
self.assertEqual(group.groupmilestone_set.filter(state="charter").count(), 0)
|
||||||
self.assertEqual(group.groupmilestone_set.filter(state="active").count(), 2)
|
self.assertEqual(group.groupmilestone_set.filter(state="active").count(), 2)
|
|
@ -96,7 +96,7 @@ urlpatterns = patterns('',
|
||||||
|
|
||||||
url(r'^help/state/(?P<type>[\w-]+)/$', 'ietf.doc.views_help.state_help', name="state_help"),
|
url(r'^help/state/(?P<type>[\w-]+)/$', 'ietf.doc.views_help.state_help', name="state_help"),
|
||||||
|
|
||||||
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.wgcharter.urls')),
|
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.doc.urls_charter')),
|
||||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
|
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
|
||||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
|
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
|
||||||
)
|
)
|
||||||
|
|
17
ietf/doc/urls_charter.py
Normal file
17
ietf/doc/urls_charter.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||||
|
|
||||||
|
from django.conf.urls import patterns, url
|
||||||
|
|
||||||
|
urlpatterns = patterns('',
|
||||||
|
url(r'^state/$', "ietf.doc.views_charter.change_state", name='charter_change_state'),
|
||||||
|
url(r'^(?P<option>initcharter|recharter|abandon)/$', "ietf.doc.views_charter.change_state", name='charter_startstop_process'),
|
||||||
|
url(r'^telechat/$', "ietf.doc.views_charter.telechat_date", name='charter_telechat_date'),
|
||||||
|
url(r'^notify/$', "ietf.doc.views_charter.edit_notify", name='charter_edit_notify'),
|
||||||
|
url(r'^ad/$', "ietf.doc.views_charter.edit_ad", name='charter_edit_ad'),
|
||||||
|
url(r'^(?P<ann>action|review)/$', "ietf.doc.views_charter.announcement_text", name="charter_edit_announcement"),
|
||||||
|
url(r'^ballotwriteupnotes/$', "ietf.doc.views_charter.ballot_writeupnotes"),
|
||||||
|
url(r'^approve/$', "ietf.doc.views_charter.approve", name='charter_approve'),
|
||||||
|
url(r'^submit/$', "ietf.doc.views_charter.submit", name='charter_submit'),
|
||||||
|
url(r'^submit/(?P<option>initcharter|recharter)/$', "ietf.doc.views_charter.submit", name='charter_submit'), # shouldn't be here
|
||||||
|
url(r'^withmilestones-(?P<rev>[0-9-]+).txt$', "ietf.doc.views_charter.charter_with_milestones_txt", name='charter_with_milestones_txt'),
|
||||||
|
)
|
|
@ -1,42 +1,120 @@
|
||||||
# generation of mails
|
import re, datetime, os, textwrap
|
||||||
|
|
||||||
import textwrap, datetime
|
|
||||||
|
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse as urlreverse
|
from django.core.urlresolvers import reverse as urlreverse
|
||||||
|
|
||||||
from ietf.utils.mail import send_mail, send_mail_text
|
from ietf.utils.mail import send_mail_text
|
||||||
from ietf.ipr.search import iprs_from_docs
|
|
||||||
from ietf.doc.models import WriteupDocEvent, DocAlias, BallotPositionDocEvent
|
|
||||||
from ietf.person.models import Person
|
from ietf.person.models import Person
|
||||||
from ietf.wgcharter.utils import *
|
from ietf.group.models import GroupEvent, ChangeStateGroupEvent
|
||||||
|
from ietf.doc.models import Document, DocAlias, DocHistory, RelatedDocument, DocumentAuthor
|
||||||
|
from ietf.doc.models import DocEvent, NewRevisionDocEvent, WriteupDocEvent, BallotPositionDocEvent
|
||||||
|
from ietf.utils.history import find_history_active_at
|
||||||
|
|
||||||
def email_secretariat(request, group, type, text):
|
|
||||||
to = ["iesg-secretary@ietf.org"]
|
|
||||||
|
|
||||||
types = {}
|
def log_state_changed(request, doc, by, prev_state):
|
||||||
types['state'] = "State changed"
|
e = DocEvent(doc=doc, by=by)
|
||||||
types['state-notrev'] = "State changed to Not currently under review"
|
e.type = "changed_document"
|
||||||
types['state-infrev'] = "State changed to Informal review"
|
e.desc = u"State changed to <b>%s</b> from %s" % (
|
||||||
types['state-intrev'] = "State changed to Internal review"
|
doc.get_state().name,
|
||||||
types['state-extrev'] = "State changed to External review"
|
prev_state.name if prev_state else "None")
|
||||||
types['state-iesgrev'] = "State changed to IESG review"
|
e.save()
|
||||||
types['state-approved'] = "Charter approved"
|
return e
|
||||||
types['conclude'] = "Request closing of group"
|
|
||||||
|
|
||||||
subject = u"Regarding %s %s: %s" % (group.type.name, group.acronym, types[type])
|
def next_revision(rev):
|
||||||
|
if rev == "":
|
||||||
|
return "00-00"
|
||||||
|
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
||||||
|
if m.group('minor'):
|
||||||
|
return "%s-%#02d" % (m.group('major'), int(m.group('minor')) + 1)
|
||||||
|
else:
|
||||||
|
return "%s-00" % (m.group('major'))
|
||||||
|
|
||||||
|
def approved_revision(rev):
|
||||||
|
if rev == "":
|
||||||
|
return ""
|
||||||
|
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
||||||
|
return m.group('major')
|
||||||
|
|
||||||
|
def next_approved_revision(rev):
|
||||||
|
if rev == "":
|
||||||
|
return "01"
|
||||||
|
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
||||||
|
return "%#02d" % (int(m.group('major')) + 1)
|
||||||
|
|
||||||
|
def read_charter_text(doc):
|
||||||
|
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
|
||||||
|
try:
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
return f.read()
|
||||||
|
except IOError:
|
||||||
|
return "Error: couldn't read charter text"
|
||||||
|
|
||||||
|
def historic_milestones_for_charter(charter, rev):
|
||||||
|
"""Return GroupMilestone/GroupMilestoneHistory objects for charter
|
||||||
|
document at rev by looking through the history."""
|
||||||
|
|
||||||
|
chartering = "-" in rev
|
||||||
|
if chartering:
|
||||||
|
need_state = "charter"
|
||||||
|
else:
|
||||||
|
need_state = "active"
|
||||||
|
|
||||||
|
# slight complication - we can assign milestones to a revision up
|
||||||
|
# until the point where the next superseding revision is
|
||||||
|
# published, so that time shall be our limit
|
||||||
|
revision_event = charter.latest_event(NewRevisionDocEvent, type="new_revision", rev=rev)
|
||||||
|
if not revision_event:
|
||||||
|
return []
|
||||||
|
|
||||||
|
e = charter.docevent_set.filter(time__gt=revision_event.time, type="new_revision").order_by("time")
|
||||||
|
if not chartering:
|
||||||
|
e = e.exclude(newrevisiondocevent__rev__contains="-")
|
||||||
|
|
||||||
|
if e:
|
||||||
|
# subtract a margen of error to avoid collisions with
|
||||||
|
# milestones being published at the same time as the new
|
||||||
|
# revision (when approving a charter)
|
||||||
|
just_before_next_rev = e[0].time - datetime.timedelta(seconds=5)
|
||||||
|
else:
|
||||||
|
just_before_next_rev = datetime.datetime.now()
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for m in charter.chartered_group.groupmilestone_set.all():
|
||||||
|
mh = find_history_active_at(m, just_before_next_rev)
|
||||||
|
if mh and mh.state_id == need_state:
|
||||||
|
res.append(mh)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
text = strip_tags(text)
|
|
||||||
send_mail(request, to, None, subject,
|
def update_telechat(request, doc, by, new_telechat_date):
|
||||||
"wgcharter/email_secretariat.txt",
|
# FIXME: reuse function in doc/utils.py instead of this one
|
||||||
dict(text=text,
|
# (need to fix auto-setting returning item problem first though)
|
||||||
group=group,
|
from ietf.doc.models import TelechatDocEvent
|
||||||
group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(acronym=group.acronym)),
|
|
||||||
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)),
|
on_agenda = bool(new_telechat_date)
|
||||||
)
|
|
||||||
)
|
prev = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||||
|
prev_telechat = prev.telechat_date if prev else None
|
||||||
|
prev_agenda = bool(prev_telechat)
|
||||||
|
|
||||||
|
e = TelechatDocEvent()
|
||||||
|
e.type = "scheduled_for_telechat"
|
||||||
|
e.by = by
|
||||||
|
e.doc = doc
|
||||||
|
e.telechat_date = new_telechat_date
|
||||||
|
|
||||||
|
if on_agenda != prev_agenda:
|
||||||
|
if on_agenda:
|
||||||
|
e.desc = "Placed on agenda for telechat - %s" % new_telechat_date
|
||||||
|
else:
|
||||||
|
e.desc = "Removed from agenda for telechat"
|
||||||
|
e.save()
|
||||||
|
elif on_agenda and new_telechat_date != prev_telechat:
|
||||||
|
e.desc = "Telechat date has been changed to <b>%s</b> from <b>%s</b>" % (new_telechat_date, prev_telechat)
|
||||||
|
e.save()
|
||||||
|
|
||||||
def email_state_changed(request, doc, text):
|
def email_state_changed(request, doc, text):
|
||||||
to = [e.strip() for e in doc.notify.replace(';', ',').split(',')]
|
to = [e.strip() for e in doc.notify.replace(';', ',').split(',')]
|
||||||
|
@ -51,14 +129,13 @@ def email_state_changed(request, doc, text):
|
||||||
"State changed: %s-%s" % (doc.canonical_name(), doc.rev),
|
"State changed: %s-%s" % (doc.canonical_name(), doc.rev),
|
||||||
text)
|
text)
|
||||||
|
|
||||||
|
|
||||||
def generate_ballot_writeup(request, doc):
|
def generate_ballot_writeup(request, doc):
|
||||||
e = WriteupDocEvent()
|
e = WriteupDocEvent()
|
||||||
e.type = "changed_ballot_writeup_text"
|
e.type = "changed_ballot_writeup_text"
|
||||||
e.by = request.user.person
|
e.by = request.user.person
|
||||||
e.doc = doc
|
e.doc = doc
|
||||||
e.desc = u"Ballot writeup was generated"
|
e.desc = u"Ballot writeup was generated"
|
||||||
e.text = unicode(render_to_string("wgcharter/ballot_writeup.txt"))
|
e.text = unicode(render_to_string("doc/charter/ballot_writeup.txt"))
|
||||||
e.save()
|
e.save()
|
||||||
|
|
||||||
return e
|
return e
|
||||||
|
@ -73,7 +150,7 @@ def default_action_text(group, charter, user):
|
||||||
e.by = user
|
e.by = user
|
||||||
e.type = "changed_action_announcement"
|
e.type = "changed_action_announcement"
|
||||||
e.desc = "%s action text was changed" % group.type.name
|
e.desc = "%s action text was changed" % group.type.name
|
||||||
e.text = render_to_string("wgcharter/action_text.txt",
|
e.text = render_to_string("doc/charter/action_text.txt",
|
||||||
dict(group=group,
|
dict(group=group,
|
||||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||||
charter_text=read_charter_text(charter),
|
charter_text=read_charter_text(charter),
|
||||||
|
@ -93,7 +170,7 @@ def default_review_text(group, charter, user):
|
||||||
e.by = user
|
e.by = user
|
||||||
e.type = "changed_review_announcement"
|
e.type = "changed_review_announcement"
|
||||||
e.desc = "%s review text was changed" % group.type.name
|
e.desc = "%s review text was changed" % group.type.name
|
||||||
e.text = render_to_string("wgcharter/review_text.txt",
|
e.text = render_to_string("doc/charter/review_text.txt",
|
||||||
dict(group=group,
|
dict(group=group,
|
||||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||||
charter_text=read_charter_text(charter),
|
charter_text=read_charter_text(charter),
|
||||||
|
@ -163,7 +240,7 @@ def generate_issue_ballot_mail(request, doc, ballot):
|
||||||
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
e = doc.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||||
ballot_writeup = e.text if e else ""
|
ballot_writeup = e.text if e else ""
|
||||||
|
|
||||||
return render_to_string("wgcharter/issue_ballot_mail.txt",
|
return render_to_string("doc/charter/issue_ballot_mail.txt",
|
||||||
dict(doc=doc,
|
dict(doc=doc,
|
||||||
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
|
||||||
active_ad_positions=active_ad_positions,
|
active_ad_positions=active_ad_positions,
|
||||||
|
@ -174,3 +251,4 @@ def generate_issue_ballot_mail(request, doc, ballot):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ from ietf.name.models import *
|
||||||
from ietf.person.models import *
|
from ietf.person.models import *
|
||||||
from ietf.group.models import *
|
from ietf.group.models import *
|
||||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history
|
from ietf.group.utils import save_group_in_history, save_milestone_in_history
|
||||||
from ietf.wgcharter.mails import *
|
from ietf.wginfo.mails import email_secretariat
|
||||||
from ietf.wgcharter.utils import *
|
from ietf.doc.utils_charter import *
|
||||||
|
|
||||||
import debug
|
import debug
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ def change_state(request, name, option=None):
|
||||||
charter.save()
|
charter.save()
|
||||||
|
|
||||||
if message:
|
if message:
|
||||||
email_secretariat(request, group, "state-%s" % charter_state.slug, message)
|
email_secretariat(request, group, "Charter state changed to %s" % charter_state.name, message)
|
||||||
|
|
||||||
email_state_changed(request, charter, "State changed to %s." % charter_state)
|
email_state_changed(request, charter, "State changed to %s." % charter_state)
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ def change_state(request, name, option=None):
|
||||||
|
|
||||||
states_for_ballot_wo_extern = State.objects.filter(used=True, type="charter", slug="intrev").values_list("pk", flat=True)
|
states_for_ballot_wo_extern = State.objects.filter(used=True, type="charter", slug="intrev").values_list("pk", flat=True)
|
||||||
|
|
||||||
return render_to_response('wgcharter/change_state.html',
|
return render_to_response('doc/charter/change_state.html',
|
||||||
dict(form=form,
|
dict(form=form,
|
||||||
doc=group.charter,
|
doc=group.charter,
|
||||||
login=login,
|
login=login,
|
||||||
|
@ -230,7 +230,7 @@ def telechat_date(request, name):
|
||||||
else:
|
else:
|
||||||
form = TelechatForm(initial=initial)
|
form = TelechatForm(initial=initial)
|
||||||
|
|
||||||
return render_to_response('wgcharter/edit_telechat_date.html',
|
return render_to_response('doc/charter/edit_telechat_date.html',
|
||||||
dict(doc=doc,
|
dict(doc=doc,
|
||||||
form=form,
|
form=form,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
|
@ -274,7 +274,7 @@ def edit_notify(request, name):
|
||||||
else:
|
else:
|
||||||
form = NotifyForm(initial=init)
|
form = NotifyForm(initial=init)
|
||||||
|
|
||||||
return render_to_response('wgcharter/edit_notify.html',
|
return render_to_response('doc/charter/edit_notify.html',
|
||||||
dict(doc=doc,
|
dict(doc=doc,
|
||||||
form=form,
|
form=form,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
|
@ -322,7 +322,7 @@ def edit_ad(request, name):
|
||||||
init = { "ad" : charter.ad_id }
|
init = { "ad" : charter.ad_id }
|
||||||
form = AdForm(initial=init)
|
form = AdForm(initial=init)
|
||||||
|
|
||||||
return render_to_response('wgcharter/change_ad.html',
|
return render_to_response('doc/charter/change_ad.html',
|
||||||
{'form': form,
|
{'form': form,
|
||||||
'charter': charter,
|
'charter': charter,
|
||||||
},
|
},
|
||||||
|
@ -415,7 +415,7 @@ def submit(request, name=None, acronym=None, option=None):
|
||||||
except IOError:
|
except IOError:
|
||||||
pass
|
pass
|
||||||
form = UploadForm(initial=init)
|
form = UploadForm(initial=init)
|
||||||
return render_to_response('wgcharter/submit.html',
|
return render_to_response('doc/charter/submit.html',
|
||||||
{'form': form,
|
{'form': form,
|
||||||
'next_rev': next_rev,
|
'next_rev': next_rev,
|
||||||
'group': group },
|
'group': group },
|
||||||
|
@ -481,7 +481,7 @@ def announcement_text(request, name, ann):
|
||||||
messages.success(request, "The email To: '%s' with Subject: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
messages.success(request, "The email To: '%s' with Subject: '%s' has been sent." % (parsed_msg["To"],parsed_msg["Subject"],))
|
||||||
return redirect('doc_writeup', name=charter.name)
|
return redirect('doc_writeup', name=charter.name)
|
||||||
|
|
||||||
return render_to_response('wgcharter/announcement_text.html',
|
return render_to_response('doc/charter/announcement_text.html',
|
||||||
dict(charter=charter,
|
dict(charter=charter,
|
||||||
announcement=ann,
|
announcement=ann,
|
||||||
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
back_url=urlreverse("doc_writeup", kwargs=dict(name=charter.name)),
|
||||||
|
@ -547,13 +547,13 @@ def ballot_writeupnotes(request, name):
|
||||||
e.desc = "Ballot has been sent"
|
e.desc = "Ballot has been sent"
|
||||||
e.save()
|
e.save()
|
||||||
|
|
||||||
return render_to_response('wgcharter/ballot_issued.html',
|
return render_to_response('doc/charter/ballot_issued.html',
|
||||||
dict(doc=charter,
|
dict(doc=charter,
|
||||||
),
|
),
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
return render_to_response('wgcharter/ballot_writeupnotes.html',
|
return render_to_response('doc/charter/ballot_writeupnotes.html',
|
||||||
dict(charter=charter,
|
dict(charter=charter,
|
||||||
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
||||||
ballot_writeup_form=form,
|
ballot_writeup_form=form,
|
||||||
|
@ -632,7 +632,7 @@ def approve(request, name):
|
||||||
charter.time = e.time
|
charter.time = e.time
|
||||||
charter.save()
|
charter.save()
|
||||||
|
|
||||||
email_secretariat(request, group, "state-%s" % new_charter_state.slug, change_description)
|
email_secretariat(request, group, "Charter state changed to %s" % new_charter_state.name, change_description)
|
||||||
|
|
||||||
# move milestones over
|
# move milestones over
|
||||||
milestones_to_delete = list(group.groupmilestone_set.filter(state__in=("active", "review")))
|
milestones_to_delete = list(group.groupmilestone_set.filter(state__in=("active", "review")))
|
||||||
|
@ -689,7 +689,7 @@ def approve(request, name):
|
||||||
|
|
||||||
return HttpResponseRedirect(charter.get_absolute_url())
|
return HttpResponseRedirect(charter.get_absolute_url())
|
||||||
|
|
||||||
return render_to_response('wgcharter/approve.html',
|
return render_to_response('doc/charter/approve.html',
|
||||||
dict(charter=charter,
|
dict(charter=charter,
|
||||||
announcement=announcement),
|
announcement=announcement),
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
@ -720,7 +720,7 @@ def charter_with_milestones_txt(request, name, rev):
|
||||||
for m in milestones:
|
for m in milestones:
|
||||||
m.desc_filled = wrapper.fill(m.desc)
|
m.desc_filled = wrapper.fill(m.desc)
|
||||||
|
|
||||||
return render_to_response('wgcharter/charter_with_milestones.txt',
|
return render_to_response('doc/charter/charter_with_milestones.txt',
|
||||||
dict(charter_text=charter_text,
|
dict(charter_text=charter_text,
|
||||||
milestones=milestones),
|
milestones=milestones),
|
||||||
context_instance=RequestContext(request),
|
context_instance=RequestContext(request),
|
|
@ -50,7 +50,6 @@ from ietf.doc.utils import *
|
||||||
from ietf.utils.history import find_history_active_at
|
from ietf.utils.history import find_history_active_at
|
||||||
from ietf.ietfauth.utils import *
|
from ietf.ietfauth.utils import *
|
||||||
from ietf.doc.views_status_change import RELATION_SLUGS as status_change_relationships
|
from ietf.doc.views_status_change import RELATION_SLUGS as status_change_relationships
|
||||||
from ietf.wgcharter.utils import historic_milestones_for_charter
|
|
||||||
from ietf.ipr.models import IprDocAlias
|
from ietf.ipr.models import IprDocAlias
|
||||||
from ietf.doc.mails import email_ad
|
from ietf.doc.mails import email_ad
|
||||||
|
|
||||||
|
@ -563,14 +562,14 @@ def document_writeup(request, name):
|
||||||
"",
|
"",
|
||||||
[("WG Review Announcement",
|
[("WG Review Announcement",
|
||||||
text_from_writeup("changed_review_announcement"),
|
text_from_writeup("changed_review_announcement"),
|
||||||
urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="review")))]
|
urlreverse("ietf.doc.views_charter.announcement_text", kwargs=dict(name=doc.name, ann="review")))]
|
||||||
))
|
))
|
||||||
|
|
||||||
sections.append(("WG Action Announcement",
|
sections.append(("WG Action Announcement",
|
||||||
"",
|
"",
|
||||||
[("WG Action Announcement",
|
[("WG Action Announcement",
|
||||||
text_from_writeup("changed_action_announcement"),
|
text_from_writeup("changed_action_announcement"),
|
||||||
urlreverse("ietf.wgcharter.views.announcement_text", kwargs=dict(name=doc.name, ann="action")))]
|
urlreverse("ietf.doc.views_charter.announcement_text", kwargs=dict(name=doc.name, ann="action")))]
|
||||||
))
|
))
|
||||||
|
|
||||||
if doc.latest_event(BallotDocEvent, type="created_ballot"):
|
if doc.latest_event(BallotDocEvent, type="created_ballot"):
|
||||||
|
@ -578,7 +577,7 @@ def document_writeup(request, name):
|
||||||
"",
|
"",
|
||||||
[("Ballot Announcement",
|
[("Ballot Announcement",
|
||||||
text_from_writeup("changed_ballot_writeup_text"),
|
text_from_writeup("changed_ballot_writeup_text"),
|
||||||
urlreverse("ietf.wgcharter.views.ballot_writeupnotes", kwargs=dict(name=doc.name)))]
|
urlreverse("ietf.doc.views_charter.ballot_writeupnotes", kwargs=dict(name=doc.name)))]
|
||||||
))
|
))
|
||||||
|
|
||||||
if not sections:
|
if not sections:
|
||||||
|
|
|
@ -354,7 +354,7 @@ def agenda_documents(request):
|
||||||
telechats = []
|
telechats = []
|
||||||
for date in dates:
|
for date in dates:
|
||||||
sections = agenda_sections()
|
sections = agenda_sections()
|
||||||
fill_in_agenda_docs(date, sections, docs_by_date[d])
|
fill_in_agenda_docs(date, sections, docs_by_date[date])
|
||||||
|
|
||||||
telechats.append({
|
telechats.append({
|
||||||
"date":date,
|
"date":date,
|
||||||
|
|
|
@ -179,7 +179,6 @@ INSTALLED_APPS = (
|
||||||
'ietf.redirects',
|
'ietf.redirects',
|
||||||
'ietf.wginfo',
|
'ietf.wginfo',
|
||||||
'ietf.submit',
|
'ietf.submit',
|
||||||
'ietf.wgcharter',
|
|
||||||
'ietf.sync',
|
'ietf.sync',
|
||||||
'ietf.community',
|
'ietf.community',
|
||||||
'ietf.release',
|
'ietf.release',
|
||||||
|
|
|
@ -5,4 +5,4 @@ Subject: WG Action: {{ action_type }} {{ group.name }} ({{ group.acronym }})
|
||||||
|
|
||||||
{% filter wordwrap:73 %}{% if action_type == "Formed" %}A new IETF working group has been formed in the {{ group.parent.name }}.{% endif %}{% if action_type == "Rechartered" %}The {{ group.name }} ({{ group.acronym }}) working group in the {{ group.parent.name }} of the IETF has been rechartered.{% endif %} For additional information please contact the Area Directors or the {{ group.type.name }} Chair{{ chairs|pluralize}}.
|
{% filter wordwrap:73 %}{% if action_type == "Formed" %}A new IETF working group has been formed in the {{ group.parent.name }}.{% endif %}{% if action_type == "Rechartered" %}The {{ group.name }} ({{ group.acronym }}) working group in the {{ group.parent.name }} of the IETF has been rechartered.{% endif %} For additional information please contact the Area Directors or the {{ group.type.name }} Chair{{ chairs|pluralize}}.
|
||||||
|
|
||||||
{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %}
|
{% include "doc/charter/group_info.txt" %}{% endfilter %}{% endautoescape %}
|
|
@ -5,4 +5,4 @@ Subject: WG Review: {{ group.name }} ({{ group.acronym }})
|
||||||
|
|
||||||
{% filter wordwrap:73 %}{% if review_type == "new" %}A new IETF working group has been proposed in the {{ group.parent.name }}.{% endif %}{% if review_type == "recharter" %}The {{ group.name }} ({{group.acronym}}) working group in the {{ group.parent.name }} of the IETF is undergoing rechartering.{% endif %} The IESG has not made any determination yet. The following draft charter was submitted, and is provided for informational purposes only. Please send your comments to the IESG mailing list (iesg at ietf.org) by {{ review_date }}.
|
{% filter wordwrap:73 %}{% if review_type == "new" %}A new IETF working group has been proposed in the {{ group.parent.name }}.{% endif %}{% if review_type == "recharter" %}The {{ group.name }} ({{group.acronym}}) working group in the {{ group.parent.name }} of the IETF is undergoing rechartering.{% endif %} The IESG has not made any determination yet. The following draft charter was submitted, and is provided for informational purposes only. Please send your comments to the IESG mailing list (iesg at ietf.org) by {{ review_date }}.
|
||||||
|
|
||||||
{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %}
|
{% include "doc/charter/group_info.txt" %}{% endfilter %}{% endautoescape %}
|
|
@ -1 +0,0 @@
|
||||||
#
|
|
|
@ -1,101 +0,0 @@
|
||||||
import sys, os, re, datetime
|
|
||||||
|
|
||||||
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
|
|
||||||
sys.path = [ basedir ] + sys.path
|
|
||||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ietf.settings")
|
|
||||||
|
|
||||||
from ietf.doc.models import *
|
|
||||||
|
|
||||||
# make sure ballot positions and types are right
|
|
||||||
BallotPositionName.objects.get_or_create(slug="block",
|
|
||||||
order=3,
|
|
||||||
name="Block",
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
BallotPositionName.objects.filter(slug="discuss").update(blocking=True)
|
|
||||||
|
|
||||||
charter_positions = BallotPositionName.objects.filter(slug__in=["yes", "noobj", "block", "abstain", "norecord" ])
|
|
||||||
|
|
||||||
o,_ = BallotType.objects.get_or_create(doc_type_id="charter",
|
|
||||||
slug="r-extrev",
|
|
||||||
name="Ready for external review",
|
|
||||||
question="Is this charter ready for external review?",
|
|
||||||
order=1,
|
|
||||||
)
|
|
||||||
|
|
||||||
o.positions = charter_positions
|
|
||||||
|
|
||||||
o,_ = BallotType.objects.get_or_create(doc_type_id="charter",
|
|
||||||
slug="r-wo-ext",
|
|
||||||
name="Ready w/o external review",
|
|
||||||
question="Is this charter ready for external review? Is this charter ready for approval without external review?",
|
|
||||||
order=2,
|
|
||||||
)
|
|
||||||
o.positions = charter_positions
|
|
||||||
|
|
||||||
o,_ = BallotType.objects.get_or_create(doc_type_id="charter",
|
|
||||||
slug="approve",
|
|
||||||
name="Approve",
|
|
||||||
question="Do we approve of this charter?",
|
|
||||||
order=3,
|
|
||||||
)
|
|
||||||
o.positions = charter_positions
|
|
||||||
|
|
||||||
draft_ballot,_ = BallotType.objects.get_or_create(doc_type_id="draft",
|
|
||||||
slug="approve",
|
|
||||||
name="Approve",
|
|
||||||
question="",
|
|
||||||
order=1,
|
|
||||||
)
|
|
||||||
draft_ballot.positions = BallotPositionName.objects.filter(slug__in=["yes", "noobj", "discuss", "abstain", "recuse", "norecord"])
|
|
||||||
|
|
||||||
|
|
||||||
# add events for drafts
|
|
||||||
|
|
||||||
# prevent memory from leaking when settings.DEBUG=True
|
|
||||||
from django.db import connection
|
|
||||||
class DontSaveQueries(object):
|
|
||||||
def append(self, x):
|
|
||||||
pass
|
|
||||||
connection.queries = DontSaveQueries()
|
|
||||||
|
|
||||||
relevant_docs = Document.objects.filter(type="draft", docevent__type__in=("changed_ballot_position", "sent_ballot_announcement")).distinct()
|
|
||||||
for d in relevant_docs.iterator():
|
|
||||||
ballot = None
|
|
||||||
for e in d.docevent_set.order_by("time", "id").select_related("ballotpositiondocevent"):
|
|
||||||
if e.type == "created_ballot":
|
|
||||||
ballot = e
|
|
||||||
|
|
||||||
if e.type == "closed_ballot":
|
|
||||||
ballot = None
|
|
||||||
|
|
||||||
if not ballot and e.type in ("sent_ballot_announcement", "changed_ballot_position"):
|
|
||||||
ballot = BallotDocEvent(doc=e.doc, by=e.by)
|
|
||||||
ballot.type = "created_ballot"
|
|
||||||
ballot.ballot_type = draft_ballot
|
|
||||||
# place new event just before
|
|
||||||
ballot.time = e.time - datetime.timedelta(seconds=1)
|
|
||||||
ballot.desc = u'Created "%s" ballot' % draft_ballot
|
|
||||||
ballot.save()
|
|
||||||
|
|
||||||
if e.type == "sent_ballot_announcement":
|
|
||||||
print "added ballot for", d.name
|
|
||||||
else:
|
|
||||||
print "MISSING ballot issue event, added ballot for", d.name
|
|
||||||
|
|
||||||
if e.type == "changed_ballot_position" and not e.ballotpositiondocevent.ballot:
|
|
||||||
e.ballotpositiondocevent.ballot_id = ballot.id
|
|
||||||
e.ballotpositiondocevent.save()
|
|
||||||
|
|
||||||
if e.type in ("iesg_approved", "iesg_disapproved") and ballot:
|
|
||||||
c = BallotDocEvent(doc=e.doc, by=e.by)
|
|
||||||
c.type = "closed_ballot"
|
|
||||||
c.ballot_type = draft_ballot
|
|
||||||
# place new event just before
|
|
||||||
c.time = e.time - datetime.timedelta(seconds=1)
|
|
||||||
c.desc = u'Closed "%s" ballot' % draft_ballot.name
|
|
||||||
c.save()
|
|
||||||
ballot = None
|
|
||||||
|
|
||||||
print "closed ballot for", d.name
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Copyright The IETF Trust 2011, All Rights Reserved
|
|
||||||
|
|
||||||
from django.conf.urls import patterns, url
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
|
||||||
url(r'^state/$', "ietf.wgcharter.views.change_state", name='charter_change_state'),
|
|
||||||
url(r'^(?P<option>initcharter|recharter|abandon)/$', "ietf.wgcharter.views.change_state", name='charter_startstop_process'),
|
|
||||||
url(r'^telechat/$', "ietf.wgcharter.views.telechat_date", name='charter_telechat_date'),
|
|
||||||
url(r'^notify/$', "ietf.wgcharter.views.edit_notify", name='charter_edit_notify'),
|
|
||||||
url(r'^ad/$', "ietf.wgcharter.views.edit_ad", name='charter_edit_ad'),
|
|
||||||
url(r'^(?P<ann>action|review)/$', "ietf.wgcharter.views.announcement_text", name="charter_edit_announcement"),
|
|
||||||
url(r'^ballotwriteupnotes/$', "ietf.wgcharter.views.ballot_writeupnotes"),
|
|
||||||
url(r'^approve/$', "ietf.wgcharter.views.approve", name='charter_approve'),
|
|
||||||
url(r'^submit/$', "ietf.wgcharter.views.submit", name='charter_submit'),
|
|
||||||
url(r'^submit/(?P<option>initcharter|recharter)/$', "ietf.wgcharter.views.submit", name='charter_submit'), # shouldn't be here
|
|
||||||
url(r'^withmilestones-(?P<rev>[0-9-]+).txt$', "ietf.wgcharter.views.charter_with_milestones_txt", name='charter_with_milestones_txt'),
|
|
||||||
)
|
|
|
@ -1,110 +0,0 @@
|
||||||
import re, datetime, os
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from ietf.group.models import GroupEvent, ChangeStateGroupEvent
|
|
||||||
from ietf.doc.models import Document, DocAlias, DocHistory, RelatedDocument, DocumentAuthor, DocEvent, NewRevisionDocEvent
|
|
||||||
from ietf.utils.history import find_history_active_at
|
|
||||||
|
|
||||||
def log_state_changed(request, doc, by, prev_state):
|
|
||||||
e = DocEvent(doc=doc, by=by)
|
|
||||||
e.type = "changed_document"
|
|
||||||
e.desc = u"State changed to <b>%s</b> from %s" % (
|
|
||||||
doc.get_state().name,
|
|
||||||
prev_state.name if prev_state else "None")
|
|
||||||
e.save()
|
|
||||||
return e
|
|
||||||
|
|
||||||
def next_revision(rev):
|
|
||||||
if rev == "":
|
|
||||||
return "00-00"
|
|
||||||
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
|
||||||
if m.group('minor'):
|
|
||||||
return "%s-%#02d" % (m.group('major'), int(m.group('minor')) + 1)
|
|
||||||
else:
|
|
||||||
return "%s-00" % (m.group('major'))
|
|
||||||
|
|
||||||
def approved_revision(rev):
|
|
||||||
if rev == "":
|
|
||||||
return ""
|
|
||||||
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
|
||||||
return m.group('major')
|
|
||||||
|
|
||||||
def next_approved_revision(rev):
|
|
||||||
if rev == "":
|
|
||||||
return "01"
|
|
||||||
m = re.match(r"(?P<major>[0-9][0-9])(-(?P<minor>[0-9][0-9]))?", rev)
|
|
||||||
return "%#02d" % (int(m.group('major')) + 1)
|
|
||||||
|
|
||||||
def read_charter_text(doc):
|
|
||||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
|
|
||||||
try:
|
|
||||||
with open(filename, 'r') as f:
|
|
||||||
return f.read()
|
|
||||||
except IOError:
|
|
||||||
return "Error: couldn't read charter text"
|
|
||||||
|
|
||||||
def historic_milestones_for_charter(charter, rev):
|
|
||||||
"""Return GroupMilestone/GroupMilestoneHistory objects for charter
|
|
||||||
document at rev by looking through the history."""
|
|
||||||
|
|
||||||
chartering = "-" in rev
|
|
||||||
if chartering:
|
|
||||||
need_state = "charter"
|
|
||||||
else:
|
|
||||||
need_state = "active"
|
|
||||||
|
|
||||||
# slight complication - we can assign milestones to a revision up
|
|
||||||
# until the point where the next superseding revision is
|
|
||||||
# published, so that time shall be our limit
|
|
||||||
revision_event = charter.latest_event(NewRevisionDocEvent, type="new_revision", rev=rev)
|
|
||||||
if not revision_event:
|
|
||||||
return []
|
|
||||||
|
|
||||||
e = charter.docevent_set.filter(time__gt=revision_event.time, type="new_revision").order_by("time")
|
|
||||||
if not chartering:
|
|
||||||
e = e.exclude(newrevisiondocevent__rev__contains="-")
|
|
||||||
|
|
||||||
if e:
|
|
||||||
# subtract a margen of error to avoid collisions with
|
|
||||||
# milestones being published at the same time as the new
|
|
||||||
# revision (when approving a charter)
|
|
||||||
just_before_next_rev = e[0].time - datetime.timedelta(seconds=5)
|
|
||||||
else:
|
|
||||||
just_before_next_rev = datetime.datetime.now()
|
|
||||||
|
|
||||||
res = []
|
|
||||||
for m in charter.chartered_group.groupmilestone_set.all():
|
|
||||||
mh = find_history_active_at(m, just_before_next_rev)
|
|
||||||
if mh and mh.state_id == need_state:
|
|
||||||
res.append(mh)
|
|
||||||
|
|
||||||
return res
|
|
||||||
|
|
||||||
|
|
||||||
def update_telechat(request, doc, by, new_telechat_date):
|
|
||||||
# FIXME: reuse function in doc/utils.py instead of this one
|
|
||||||
# (need to fix auto-setting returning item problem first though)
|
|
||||||
from ietf.doc.models import TelechatDocEvent
|
|
||||||
|
|
||||||
on_agenda = bool(new_telechat_date)
|
|
||||||
|
|
||||||
prev = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
|
||||||
prev_telechat = prev.telechat_date if prev else None
|
|
||||||
prev_agenda = bool(prev_telechat)
|
|
||||||
|
|
||||||
e = TelechatDocEvent()
|
|
||||||
e.type = "scheduled_for_telechat"
|
|
||||||
e.by = by
|
|
||||||
e.doc = doc
|
|
||||||
e.telechat_date = new_telechat_date
|
|
||||||
|
|
||||||
if on_agenda != prev_agenda:
|
|
||||||
if on_agenda:
|
|
||||||
e.desc = "Placed on agenda for telechat - %s" % new_telechat_date
|
|
||||||
else:
|
|
||||||
e.desc = "Removed from agenda for telechat"
|
|
||||||
e.save()
|
|
||||||
elif on_agenda and new_telechat_date != prev_telechat:
|
|
||||||
e.desc = "Telechat date has been changed to <b>%s</b> from <b>%s</b>" % (new_telechat_date, prev_telechat)
|
|
||||||
e.save()
|
|
|
@ -17,7 +17,7 @@ from ietf.name.models import *
|
||||||
from ietf.person.models import *
|
from ietf.person.models import *
|
||||||
from ietf.group.models import *
|
from ietf.group.models import *
|
||||||
from ietf.group.utils import save_group_in_history
|
from ietf.group.utils import save_group_in_history
|
||||||
from ietf.wgcharter.mails import email_secretariat
|
from ietf.wginfo.mails import email_secretariat
|
||||||
from ietf.person.forms import EmailsField
|
from ietf.person.forms import EmailsField
|
||||||
from ietf.doc.utils import get_tags_for_stream_id
|
from ietf.doc.utils import get_tags_for_stream_id
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ def conclude(request, acronym):
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
instructions = form.cleaned_data['instructions']
|
instructions = form.cleaned_data['instructions']
|
||||||
|
|
||||||
email_secretariat(request, wg, "conclude", instructions)
|
email_secretariat(request, wg, "Request closing of group", instructions)
|
||||||
|
|
||||||
e = GroupEvent(group=wg, by=login)
|
e = GroupEvent(group=wg, by=login)
|
||||||
e.type = "requested_close"
|
e.type = "requested_close"
|
||||||
|
|
|
@ -12,6 +12,20 @@ from ietf.utils.mail import send_mail, send_mail_text
|
||||||
|
|
||||||
from ietf.group.models import *
|
from ietf.group.models import *
|
||||||
|
|
||||||
|
def email_secretariat(request, group, subject, text):
|
||||||
|
to = ["iesg-secretary@ietf.org"]
|
||||||
|
full_subject = u"Regarding %s %s: %s" % (group.type.name, group.acronym, subject)
|
||||||
|
text = strip_tags(text)
|
||||||
|
|
||||||
|
send_mail(request, to, None, subject,
|
||||||
|
"wginfo/email_secretariat.txt",
|
||||||
|
dict(text=text,
|
||||||
|
group=group,
|
||||||
|
group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(acronym=group.acronym)),
|
||||||
|
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def email_milestones_changed(request, group, changes):
|
def email_milestones_changed(request, group, changes):
|
||||||
def wrap_up_email(to, text):
|
def wrap_up_email(to, text):
|
||||||
text = wrap(strip_tags(text), 70)
|
text = wrap(strip_tags(text), 70)
|
||||||
|
|
Loading…
Reference in a new issue