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:
Ole Laursen 2014-01-13 16:08:58 +00:00
parent c4313a4f42
commit 7e00fa1424
31 changed files with 169 additions and 291 deletions

View file

@ -19,7 +19,7 @@ from ietf.group.utils import *
from ietf.name.models import *
from ietf.person.models import *
from ietf.iesg.models import TelechatDate
from ietf.wgcharter.utils import *
from ietf.doc.utils_charter import *
class EditCharterTests(TestCase):
def setUp(self):
@ -71,13 +71,13 @@ class EditCharterTests(TestCase):
def find_event(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"):
self.assertTrue(find_event("created_ballot"))
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):
make_test_data()
@ -272,7 +272,7 @@ class ApproveCharterTests(TestCase):
self.assertEqual(len(outbox), mailbox_before + 2)
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="active").count(), 2)

View file

@ -96,7 +96,7 @@ urlpatterns = patterns('',
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._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
)

17
ietf/doc/urls_charter.py Normal file
View 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'),
)

View file

@ -1,42 +1,120 @@
# generation of mails
import textwrap, datetime
import re, datetime, os, textwrap
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.mail import send_mail, send_mail_text
from ietf.ipr.search import iprs_from_docs
from ietf.doc.models import WriteupDocEvent, DocAlias, BallotPositionDocEvent
from ietf.utils.mail import send_mail_text
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 = {}
types['state'] = "State changed"
types['state-notrev'] = "State changed to Not currently under review"
types['state-infrev'] = "State changed to Informal review"
types['state-intrev'] = "State changed to Internal review"
types['state-extrev'] = "State changed to External review"
types['state-iesgrev'] = "State changed to IESG review"
types['state-approved'] = "Charter approved"
types['conclude'] = "Request closing of group"
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
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'))
text = strip_tags(text)
send_mail(request, to, None, subject,
"wgcharter/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 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()
def email_state_changed(request, doc, text):
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),
text)
def generate_ballot_writeup(request, doc):
e = WriteupDocEvent()
e.type = "changed_ballot_writeup_text"
e.by = request.user.person
e.doc = doc
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()
return e
@ -73,7 +150,7 @@ def default_action_text(group, charter, user):
e.by = user
e.type = "changed_action_announcement"
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,
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
charter_text=read_charter_text(charter),
@ -93,7 +170,7 @@ def default_review_text(group, charter, user):
e.by = user
e.type = "changed_review_announcement"
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,
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
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")
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,
doc_url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url(),
active_ad_positions=active_ad_positions,
@ -174,3 +251,4 @@ def generate_issue_ballot_mail(request, doc, ballot):
)
)

View file

@ -23,8 +23,8 @@ from ietf.name.models import *
from ietf.person.models import *
from ietf.group.models import *
from ietf.group.utils import save_group_in_history, save_milestone_in_history
from ietf.wgcharter.mails import *
from ietf.wgcharter.utils import *
from ietf.wginfo.mails import email_secretariat
from ietf.doc.utils_charter import *
import debug
@ -124,7 +124,7 @@ def change_state(request, name, option=None):
charter.save()
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)
@ -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)
return render_to_response('wgcharter/change_state.html',
return render_to_response('doc/charter/change_state.html',
dict(form=form,
doc=group.charter,
login=login,
@ -230,7 +230,7 @@ def telechat_date(request, name):
else:
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,
form=form,
user=request.user,
@ -274,7 +274,7 @@ def edit_notify(request, name):
else:
form = NotifyForm(initial=init)
return render_to_response('wgcharter/edit_notify.html',
return render_to_response('doc/charter/edit_notify.html',
dict(doc=doc,
form=form,
user=request.user,
@ -322,7 +322,7 @@ def edit_ad(request, name):
init = { "ad" : charter.ad_id }
form = AdForm(initial=init)
return render_to_response('wgcharter/change_ad.html',
return render_to_response('doc/charter/change_ad.html',
{'form': form,
'charter': charter,
},
@ -415,7 +415,7 @@ def submit(request, name=None, acronym=None, option=None):
except IOError:
pass
form = UploadForm(initial=init)
return render_to_response('wgcharter/submit.html',
return render_to_response('doc/charter/submit.html',
{'form': form,
'next_rev': next_rev,
'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"],))
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,
announcement=ann,
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.save()
return render_to_response('wgcharter/ballot_issued.html',
return render_to_response('doc/charter/ballot_issued.html',
dict(doc=charter,
),
context_instance=RequestContext(request))
return render_to_response('wgcharter/ballot_writeupnotes.html',
return render_to_response('doc/charter/ballot_writeupnotes.html',
dict(charter=charter,
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
ballot_writeup_form=form,
@ -632,7 +632,7 @@ def approve(request, name):
charter.time = e.time
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
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 render_to_response('wgcharter/approve.html',
return render_to_response('doc/charter/approve.html',
dict(charter=charter,
announcement=announcement),
context_instance=RequestContext(request))
@ -720,7 +720,7 @@ def charter_with_milestones_txt(request, name, rev):
for m in milestones:
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,
milestones=milestones),
context_instance=RequestContext(request),

View file

@ -50,7 +50,6 @@ from ietf.doc.utils import *
from ietf.utils.history import find_history_active_at
from ietf.ietfauth.utils import *
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.doc.mails import email_ad
@ -563,14 +562,14 @@ def document_writeup(request, name):
"",
[("WG 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",
"",
[("WG 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"):
@ -578,7 +577,7 @@ def document_writeup(request, name):
"",
[("Ballot Announcement",
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:

View file

@ -354,7 +354,7 @@ def agenda_documents(request):
telechats = []
for date in dates:
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({
"date":date,

View file

@ -179,7 +179,6 @@ INSTALLED_APPS = (
'ietf.redirects',
'ietf.wginfo',
'ietf.submit',
'ietf.wgcharter',
'ietf.sync',
'ietf.community',
'ietf.release',

View file

@ -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}}.
{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %}
{% include "doc/charter/group_info.txt" %}{% endfilter %}{% endautoescape %}

View file

@ -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 }}.
{% include "wgcharter/group_info.txt" %}{% endfilter %}{% endautoescape %}
{% include "doc/charter/group_info.txt" %}{% endfilter %}{% endautoescape %}

View file

@ -1 +0,0 @@
#

View file

@ -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

View file

@ -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'),
)

View file

@ -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()

View file

@ -17,7 +17,7 @@ from ietf.name.models import *
from ietf.person.models import *
from ietf.group.models import *
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.doc.utils import get_tags_for_stream_id
@ -319,7 +319,7 @@ def conclude(request, acronym):
if form.is_valid():
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.type = "requested_close"

View file

@ -12,6 +12,20 @@ from ietf.utils.mail import send_mail, send_mail_text
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 wrap_up_email(to, text):
text = wrap(strip_tags(text), 70)