checkpoint
- Legacy-Id: 10016
This commit is contained in:
parent
1e84077e53
commit
839d0f89ad
|
@ -9,12 +9,12 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
|
||||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.ipr.utils import iprs_from_docs, related_docs
|
||||
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent, DocTagName
|
||||
from ietf.doc.models import WriteupDocEvent, BallotPositionDocEvent, LastCallDocEvent, DocAlias, ConsensusDocEvent
|
||||
from ietf.doc.utils import needed_ballot_positions
|
||||
from ietf.person.models import Person
|
||||
from ietf.group.models import Role
|
||||
from ietf.doc.models import Document
|
||||
from ietf.mailtoken.utils import gather_addresses
|
||||
from ietf.mailtoken.utils import gather_addresses, gather_address_list
|
||||
|
||||
def email_state_changed(request, doc, text):
|
||||
to = [x.strip() for x in doc.notify.replace(';', ',').split(',')]
|
||||
|
@ -35,7 +35,7 @@ def email_stream_changed(request, doc, old_stream, new_stream, text=""):
|
|||
streams.append(old_stream.slug)
|
||||
if new_stream:
|
||||
streams.append(new_stream.slug)
|
||||
to = gather_addresses('doc_stream_changed',doc=doc,streams=streams)
|
||||
to = gather_address_list('doc_stream_changed',doc=doc,streams=streams)
|
||||
|
||||
if not to:
|
||||
return
|
||||
|
@ -74,6 +74,7 @@ def email_authors(request, doc, subject, text):
|
|||
def html_to_text(html):
|
||||
return strip_tags(html.replace("<", "<").replace(">", ">").replace("&", "&").replace("<br>", "\n"))
|
||||
|
||||
#TODO Expunge this
|
||||
def email_ad(request, doc, ad, changed_by, text, subject=None):
|
||||
if not ad or not changed_by or ad == changed_by:
|
||||
return
|
||||
|
@ -406,7 +407,7 @@ def email_last_call_expired(doc):
|
|||
text = "IETF Last Call has ended, and the state has been changed to\n%s." % doc.get_state("draft-iesg").name
|
||||
|
||||
send_mail(None,
|
||||
gather_addresses('last_call_expired',doc=doc)
|
||||
gather_addresses('last_call_expired',doc=doc),
|
||||
"DraftTracker Mail System <iesg-secretary@ietf.org>",
|
||||
"Last Call Expired: %s" % doc.file_tag(),
|
||||
"doc/mail/change_notice.txt",
|
||||
|
@ -416,27 +417,8 @@ def email_last_call_expired(doc):
|
|||
cc = gather_addresses('last_call_expired_cc',doc=doc)
|
||||
)
|
||||
|
||||
def stream_state_email_recipients(doc, extra_recipients=[]):
|
||||
persons = set()
|
||||
res = []
|
||||
for r in Role.objects.filter(group=doc.group, name__in=("chair", "delegate")).select_related("person", "email"):
|
||||
res.append(r.formatted_email())
|
||||
persons.add(r.person)
|
||||
|
||||
for email in doc.authors.all():
|
||||
if email.person not in persons:
|
||||
res.append(email.formatted_email())
|
||||
persons.add(email.person)
|
||||
|
||||
for e in extra_recipients:
|
||||
if e.person not in persons:
|
||||
res.append(e.formatted_email())
|
||||
persons.add(e.person)
|
||||
|
||||
return res
|
||||
|
||||
def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=""):
|
||||
recipients = stream_state_email_recipients(doc)
|
||||
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
|
||||
|
||||
state_type = (prev_state or new_state).type
|
||||
|
||||
|
@ -452,12 +434,8 @@ def email_stream_state_changed(request, doc, prev_state, new_state, by, comment=
|
|||
comment=comment))
|
||||
|
||||
def email_stream_tags_changed(request, doc, added_tags, removed_tags, by, comment=""):
|
||||
extra_recipients = []
|
||||
|
||||
if DocTagName.objects.get(slug="sheph-u") in added_tags and doc.shepherd:
|
||||
extra_recipients.append(doc.shepherd)
|
||||
|
||||
recipients = stream_state_email_recipients(doc, extra_recipients)
|
||||
recipients = gather_address_list('doc_stream_state_edited',doc=doc)
|
||||
|
||||
send_mail(request, recipients, settings.DEFAULT_FROM_EMAIL,
|
||||
u"Tags changed for %s" % doc.name,
|
||||
|
|
|
@ -232,7 +232,7 @@ class BallotWriteupsTests(TestCase):
|
|||
send_last_call_request="1"))
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc-req")
|
||||
self.assertEqual(len(outbox), mailbox_before + 3)
|
||||
self.assertEqual(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue("Last Call" in outbox[-1]['Subject'])
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
|
||||
|
@ -387,7 +387,7 @@ class ApproveBallotTests(TestCase):
|
|||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "ann")
|
||||
self.assertEqual(len(outbox), mailbox_before + 4)
|
||||
self.assertEqual(len(outbox), mailbox_before + 3)
|
||||
self.assertTrue("Protocol Action" in outbox[-2]['Subject'])
|
||||
# the IANA copy
|
||||
self.assertTrue("Protocol Action" in outbox[-1]['Subject'])
|
||||
|
@ -409,7 +409,7 @@ class ApproveBallotTests(TestCase):
|
|||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "dead")
|
||||
self.assertEqual(len(outbox), mailbox_before + 3)
|
||||
self.assertEqual(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue("NOT be published" in str(outbox[-1]))
|
||||
|
||||
|
||||
|
@ -441,11 +441,11 @@ class MakeLastCallTests(TestCase):
|
|||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "lc")
|
||||
self.assertEqual(draft.latest_event(LastCallDocEvent, "sent_last_call").expires.strftime("%Y-%m-%d"), expire_date)
|
||||
self.assertEqual(len(outbox), mailbox_before + 4)
|
||||
self.assertEqual(len(outbox), mailbox_before + 3)
|
||||
|
||||
self.assertTrue("Last Call" in outbox[-4]['Subject'])
|
||||
# the IANA copy
|
||||
self.assertTrue("Last Call" in outbox[-3]['Subject'])
|
||||
# the IANA copy
|
||||
self.assertTrue("Last Call" in outbox[-2]['Subject'])
|
||||
self.assertTrue("Last Call" in draft.message_set.order_by("-time")[0].subject)
|
||||
|
||||
class DeferUndeferTestCase(TestCase):
|
||||
|
|
|
@ -72,9 +72,8 @@ class ChangeStateTests(TestCase):
|
|||
self.assertEqual(draft.docevent_set.count(), events_before + 2)
|
||||
self.assertTrue("Test comment" in draft.docevent_set.all()[0].desc)
|
||||
self.assertTrue("IESG state changed" in draft.docevent_set.all()[1].desc)
|
||||
self.assertEqual(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue("State Update Notice" in outbox[-2]['Subject'])
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("State Update Notice" in outbox[-1]['Subject'])
|
||||
|
||||
|
||||
# check that we got a previous state now
|
||||
|
@ -101,7 +100,7 @@ class ChangeStateTests(TestCase):
|
|||
|
||||
draft = Document.objects.get(name=draft.name)
|
||||
self.assertEqual(draft.get_state_slug("draft-iesg"), "review-e")
|
||||
self.assertEqual(len(outbox), mailbox_before + 2 + 1)
|
||||
self.assertEqual(len(outbox), mailbox_before + 2)
|
||||
self.assertTrue(draft.name in outbox[-1]['Subject'])
|
||||
self.assertTrue("changed state" in outbox[-1]['Subject'])
|
||||
self.assertTrue("is no longer" in str(outbox[-1]))
|
||||
|
@ -1095,7 +1094,7 @@ class AdoptDraftTests(TestCase):
|
|||
self.assertEqual(draft.notify,"aliens@example.mars")
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("state changed" in outbox[-1]["Subject"].lower())
|
||||
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
|
||||
|
||||
self.assertFalse(mars.list_email in draft.notify)
|
||||
|
@ -1137,7 +1136,7 @@ class ChangeStreamStateTests(TestCase):
|
|||
self.assertEqual(draft.docevent_set.count() - events_before, 2)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("tags changed" in outbox[-1]["Subject"].lower())
|
||||
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("plain@example.com" in unicode(outbox[-1]))
|
||||
|
||||
|
@ -1181,7 +1180,7 @@ class ChangeStreamStateTests(TestCase):
|
|||
self.assertTrue(due - datetime.timedelta(days=1) <= reminder[0].due <= due + datetime.timedelta(days=1))
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("state changed" in outbox[-1]["Subject"].lower())
|
||||
self.assertTrue("marschairman@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("mars-chairs@ietf.org" in unicode(outbox[-1]))
|
||||
self.assertTrue("marsdelegate@ietf.org" in unicode(outbox[-1]))
|
||||
|
||||
class ChangeReplacesTests(TestCase):
|
||||
|
|
|
@ -18,18 +18,18 @@ from ietf.group.models import Role
|
|||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.utils import draft, markup_txt
|
||||
from ietf.utils.mail import send_mail
|
||||
from ietf.mailtoken.utils import gather_address_list
|
||||
|
||||
#FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
|
||||
#TODO FIXME - it would be better if this lived in ietf/doc/mails.py, but there's
|
||||
# an import order issue to work out.
|
||||
def email_update_telechat(request, doc, text):
|
||||
to = set(['iesg@ietf.org','iesg-secretary@ietf.org'])
|
||||
to.update(set([x.strip() for x in doc.notify.replace(';', ',').split(',')]))
|
||||
to = gather_address_list('doc_telechat_details_changed',doc=doc)
|
||||
|
||||
if not to:
|
||||
return
|
||||
|
||||
text = strip_tags(text)
|
||||
send_mail(request, list(to), None,
|
||||
send_mail(request, to, None,
|
||||
"Telechat update notice: %s" % doc.file_tag(),
|
||||
"doc/mail/update_telechat.txt",
|
||||
dict(text=text,
|
||||
|
|
|
@ -17,7 +17,7 @@ from ietf.doc.models import ( Document, State, DocEvent, BallotDocEvent, BallotP
|
|||
BallotType, LastCallDocEvent, WriteupDocEvent, save_document_in_history, IESG_SUBSTATE_TAGS )
|
||||
from ietf.doc.utils import ( add_state_change_event, close_ballot, close_open_ballots,
|
||||
create_ballot_if_not_open, update_telechat )
|
||||
from ietf.doc.mails import ( email_ad, email_ballot_deferred, email_ballot_undeferred,
|
||||
from ietf.doc.mails import ( email_ballot_deferred, email_ballot_undeferred,
|
||||
email_state_changed, extra_automation_headers, generate_last_call_announcement,
|
||||
generate_issue_ballot_mail, generate_ballot_writeup, generate_approval_mail )
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
|
@ -464,7 +464,6 @@ def lastcalltext(request, name):
|
|||
|
||||
if e:
|
||||
email_state_changed(request, doc, e.desc)
|
||||
email_ad(request, doc, doc.ad, login, e.desc)
|
||||
|
||||
request_last_call(request, doc)
|
||||
|
||||
|
@ -708,7 +707,6 @@ def approve_ballot(request, name):
|
|||
doc.save()
|
||||
|
||||
email_state_changed(request, doc, change_description)
|
||||
email_ad(request, doc, doc.ad, login, change_description)
|
||||
|
||||
# send announcement
|
||||
|
||||
|
@ -790,7 +788,6 @@ def make_last_call(request, name):
|
|||
change_description = "Last call has been made for %s and state has been changed to %s" % (doc.name, new_state.name)
|
||||
|
||||
email_state_changed(request, doc, change_description)
|
||||
email_ad(request, doc, doc.ad, login, change_description)
|
||||
|
||||
e = LastCallDocEvent(doc=doc, by=login)
|
||||
e.type = "sent_last_call"
|
||||
|
|
|
@ -51,7 +51,6 @@ from ietf.doc.utils import ( add_links_in_new_revision_events, augment_events_wi
|
|||
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot,
|
||||
get_initial_notify, make_notify_changed_event )
|
||||
from ietf.community.models import CommunityList
|
||||
from ietf.doc.mails import email_ad
|
||||
from ietf.group.models import Role
|
||||
from ietf.group.utils import can_manage_group_type, can_manage_materials
|
||||
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person, role_required
|
||||
|
@ -59,6 +58,7 @@ from ietf.name.models import StreamName, BallotPositionName
|
|||
from ietf.person.models import Email
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.doc.forms import TelechatForm, NotifyForm
|
||||
from ietf.doc.mails import email_ad
|
||||
|
||||
def render_document_top(request, doc, tab, name):
|
||||
tabs = []
|
||||
|
@ -878,6 +878,7 @@ def add_comment(request, name):
|
|||
e.save()
|
||||
|
||||
if doc.type_id == "draft":
|
||||
# TODO - build an explicit message for when a comment is added
|
||||
email_ad(request, doc, doc.ad, login,
|
||||
"A new comment added by %s" % login.name)
|
||||
return redirect("doc_history", name=doc.name)
|
||||
|
|
|
@ -111,7 +111,6 @@ def change_state(request, name):
|
|||
doc.save()
|
||||
|
||||
email_state_changed(request, doc, msg)
|
||||
email_ad(request, doc, doc.ad, login, msg)
|
||||
|
||||
|
||||
if prev_state and prev_state.slug in ("ann", "rfcqueue") and new_state.slug not in ("rfcqueue", "pub"):
|
||||
|
@ -450,6 +449,7 @@ def change_intention(request, name):
|
|||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
# TODO: Build explicit changed_intended_publication_status
|
||||
email_ad(request, doc, doc.ad, login, email_desc)
|
||||
|
||||
return HttpResponseRedirect(doc.get_absolute_url())
|
||||
|
@ -726,6 +726,7 @@ def edit_info(request, name):
|
|||
doc.time = datetime.datetime.now()
|
||||
|
||||
if changes and not new_document:
|
||||
#TODO - use the 'this thing changed' messages instead
|
||||
email_ad(request, doc, orig_ad, login, "\n".join(changes))
|
||||
|
||||
doc.save()
|
||||
|
|
|
@ -12,6 +12,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.group.models import Group
|
||||
from ietf.group.utils import milestone_reviewer_for_group_type
|
||||
from ietf.mailtoken.utils import gather_address_list
|
||||
|
||||
def email_iesg_secretary_re_charter(request, group, subject, text):
|
||||
to = ["iesg-secretary@ietf.org"]
|
||||
|
@ -77,26 +78,18 @@ def email_milestones_changed(request, group, changes):
|
|||
|
||||
send_mail_text(request, to, None, subject, text)
|
||||
|
||||
# first send to management and chairs
|
||||
to = []
|
||||
if group.ad_role():
|
||||
to.append(group.ad_role().email.formatted_email())
|
||||
elif group.type_id == "rg":
|
||||
to.append("IRTF Chair <irtf-chair@irtf.org>")
|
||||
|
||||
for r in group.role_set.filter(name="chair"):
|
||||
to.append(r.formatted_email())
|
||||
|
||||
# first send to those who should see any edits (such as management and chairs)
|
||||
to = gather_address_list('group_milestones_edited',group=group)
|
||||
if to:
|
||||
wrap_up_email(to, u"\n\n".join(c + "." for c in changes))
|
||||
|
||||
# then send to group
|
||||
if group.list_email:
|
||||
review_re = re.compile("Added .* for review, due")
|
||||
to = [ group.list_email ]
|
||||
msg = u"\n\n".join(c + "." for c in changes if not review_re.match(c))
|
||||
if msg:
|
||||
wrap_up_email(to, msg)
|
||||
# then send only the approved milestones to those who shouldn't be
|
||||
# bothered with milestones pending approval
|
||||
review_re = re.compile("Added .* for review, due")
|
||||
to = gather_address_list('group_approved_milestones_edited',group=group)
|
||||
msg = u"\n\n".join(c + "." for c in changes if not review_re.match(c))
|
||||
if to and msg:
|
||||
wrap_up_email(to, msg)
|
||||
|
||||
|
||||
def email_milestone_review_reminder(group, grace_period=7):
|
||||
|
|
|
@ -37,6 +37,10 @@ def make_recipients(apps):
|
|||
desc="The document's group chairs (if the document is assigned to a working or research group)",
|
||||
template=None)
|
||||
|
||||
rc(slug='doc_group_delegates',
|
||||
desc="The document's group delegates (if the document is assigned to a working or research group)",
|
||||
template=None)
|
||||
|
||||
rc(slug='doc_affecteddoc_authors',
|
||||
desc="The authors of the subject documents of a conflict-review or status-change",
|
||||
template=None)
|
||||
|
@ -105,6 +109,9 @@ def make_recipients(apps):
|
|||
desc="The group's chairs",
|
||||
template="{{group.acronym}}-chairs@ietf.org")
|
||||
|
||||
rc(slug='group_responsible_directors',
|
||||
desc="The group's responsible AD(s) or IRTF chair",
|
||||
template=None)
|
||||
|
||||
def make_mailtokens(apps):
|
||||
|
||||
|
@ -300,7 +307,51 @@ def make_mailtokens(apps):
|
|||
recipient_slugs=['stream_managers',
|
||||
'doc_notify',
|
||||
])
|
||||
|
||||
mt_factory(slug='doc_stream_state_edited',
|
||||
desc="Recipients when the stream state of a document is manually edited",
|
||||
recipient_slugs=['doc_group_chairs',
|
||||
'doc_group_delegates',
|
||||
'doc_shepherd',
|
||||
'doc_authors',
|
||||
])
|
||||
|
||||
mt_factory(slug='group_milestones_edited',
|
||||
desc="Recipients when any of a group's milestones are edited",
|
||||
recipient_slugs=['group_responsible_directors',
|
||||
'group_chairs',
|
||||
])
|
||||
|
||||
mt_factory(slug='group_approved_milestones_edited',
|
||||
desc="Recipients when the set of approved milestones for a group are edited",
|
||||
recipient_slugs=['group_mail_list',
|
||||
])
|
||||
|
||||
mt_factory(slug='doc_state_edited',
|
||||
desc="Recipients when a document's state is manutally edited",
|
||||
recipient_slugs=['doc_notify',
|
||||
'doc_ad',
|
||||
'doc_authors',
|
||||
'doc_shepherd',
|
||||
'doc_group_chairs',
|
||||
'doc_affecteddoc_authors',
|
||||
'doc_affecteddoc_group_chairs',
|
||||
'doc_affecteddoc_notify',
|
||||
])
|
||||
|
||||
mt_factory(slug='doc_telechat_details_changed',
|
||||
desc="Recipients when a document's telechat date or other telechat specific details are changed",
|
||||
recipient_slugs=['iesg',
|
||||
'iesg-secretary',
|
||||
'doc_notify',
|
||||
'doc_authors',
|
||||
'doc_shepherd',
|
||||
'doc_group_chairs',
|
||||
'doc_affecteddoc_authors',
|
||||
'doc_affecteddoc_group_chairs',
|
||||
'doc_affecteddoc_notify',
|
||||
])
|
||||
|
||||
|
||||
def forward(apps, schema_editor):
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
from django.db import models
|
||||
from django.template import Template, Context
|
||||
|
||||
from ietf.group.models import Role
|
||||
|
||||
class MailToken(models.Model):
|
||||
slug = models.CharField(max_length=32, primary_key=True)
|
||||
desc = models.TextField(blank=True)
|
||||
|
@ -41,10 +43,18 @@ class Recipient(models.Model):
|
|||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
doc=kwargs['doc']
|
||||
if doc.group.type.slug in ['wg','rg']:
|
||||
if doc.group and doc.group.type.slug in ['wg','rg']:
|
||||
addrs.append('%s-chairs@ietf.org'%doc.group.acronym)
|
||||
return addrs
|
||||
|
||||
def gather_doc_group_delegates(self, **kwargs):
|
||||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
doc=kwargs['doc']
|
||||
if doc.group and doc.group.type.slug in ['wg','rg']:
|
||||
addrs.extend(Role.objects.filter(group=doc.group,name='delegate').values_list('email__address',flat=True))
|
||||
return addrs
|
||||
|
||||
def gather_doc_group_mail_list(self, **kwargs):
|
||||
addrs = []
|
||||
if 'doc' in kwargs:
|
||||
|
@ -115,3 +125,11 @@ class Recipient(models.Model):
|
|||
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':[kwargs['doc'].stream_id]}))
|
||||
return addrs
|
||||
|
||||
def gather_group_responsible_directors(self, **kwargs):
|
||||
addrs = []
|
||||
if 'group' in kwargs:
|
||||
group = kwargs['group']
|
||||
addrs.extend(Role.objects.filter(group=group,name='ad').values_list('email__address',flat=True))
|
||||
if group.type_id=='rg':
|
||||
addrs.extend(Recipient.objects.get(slug='stream_managers').gather(**{'streams':['irtf']}))
|
||||
return addrs
|
||||
|
|
|
@ -26,12 +26,12 @@ class EventMailTests(TestCase):
|
|||
url = urlreverse('ietf.mailtoken.views.show_recipients')
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue('bogus' in r.content)
|
||||
self.assertTrue('doc_group_mail_list' in r.content)
|
||||
|
||||
url = urlreverse('ietf.mailtoken.views.show_recipients',kwargs=dict(recipient_slug='bogus'))
|
||||
url = urlreverse('ietf.mailtoken.views.show_recipients',kwargs=dict(recipient_slug='doc_group_mail_list'))
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue('bogus' in r.content)
|
||||
self.assertTrue('doc_group_mail_list' in r.content)
|
||||
|
||||
class RecipientTests(TestCase):
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ def gather_address_list(slug,**kwargs):
|
|||
for recipient in mailtoken.recipients.all():
|
||||
addrs.extend(recipient.gather(**kwargs))
|
||||
|
||||
return list(set(addrs))
|
||||
return list(set([addr for addr in addrs if addr]))
|
||||
|
||||
def gather_addresses(slug,**kwargs):
|
||||
return ",\n ".join(gather_address_list(slug,**kwargs))
|
||||
|
|
|
@ -3017,7 +3017,7 @@
|
|||
"slug": "rfcqueue",
|
||||
"type": "draft-iesg",
|
||||
"order": 31,
|
||||
"desc": "The document is in the RFC editor Queue (as confirmed by https://www.rfc-editor.org/queue.html)."
|
||||
"desc": "The document is in the RFC editor Queue (as confirmed by http://www.rfc-editor.org/queue.html)."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 17
|
||||
|
@ -3489,7 +3489,7 @@
|
|||
"slug": "c-adopt",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 1,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.1\" target=\"_blank\">4.2.1. Call for Adoption by WG Issued</a>\n\n The \"Call for Adoption by WG Issued\" state should be used to indicate when an I-D is being considered for adoption by an IETF WG. An I-D that is in this state is actively being considered for adoption and has not yet achieved consensus, preference, or selection in the WG.\n\n This state may be used to describe an I-D that someone has asked a WG to consider for adoption, if the WG Chair has agreed with the request. This state may also be used to identify an I-D that a WG Chair asked an author to write specifically for consideration as a candidate WG item [WGDTSPEC], and/or an I-D that is listed as a 'candidate draft' in the WG's charter.\n\n Under normal conditions, it should not be possible for an I-D to be in the \"Call for Adoption by WG Issued\" state in more than one working group at the same time. This said, it is not uncommon for authors to \"shop\" their I-Ds to more than one WG at a time, with the hope of getting their documents adopted somewhere.\n\n After this state is implemented in the Datatracker, an I-D that is in the \"Call for Adoption by WG Issued\" state will not be able to be \"shopped\" to any other WG without the consent of the WG Chairs and the responsible ADs impacted by the shopping.\n\n Note that Figure 1 includes an arc leading from this state to outside of the WG state machine. This illustrates that some I-Ds that are considered do not get adopted as WG drafts. An I-D that is not adopted as a WG draft will transition out of the WG state machine and revert back to having no stream-specific state; however, the status change history log of the I-D will record that the I-D was previously in the \"Call for Adoption by WG Issued\" state."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.1\" target=\"_blank\">4.2.1. Call for Adoption by WG Issued</a>\n\n The \"Call for Adoption by WG Issued\" state should be used to indicate when an I-D is being considered for adoption by an IETF WG. An I-D that is in this state is actively being considered for adoption and has not yet achieved consensus, preference, or selection in the WG.\n\n This state may be used to describe an I-D that someone has asked a WG to consider for adoption, if the WG Chair has agreed with the request. This state may also be used to identify an I-D that a WG Chair asked an author to write specifically for consideration as a candidate WG item [WGDTSPEC], and/or an I-D that is listed as a 'candidate draft' in the WG's charter.\n\n Under normal conditions, it should not be possible for an I-D to be in the \"Call for Adoption by WG Issued\" state in more than one working group at the same time. This said, it is not uncommon for authors to \"shop\" their I-Ds to more than one WG at a time, with the hope of getting their documents adopted somewhere.\n\n After this state is implemented in the Datatracker, an I-D that is in the \"Call for Adoption by WG Issued\" state will not be able to be \"shopped\" to any other WG without the consent of the WG Chairs and the responsible ADs impacted by the shopping.\n\n Note that Figure 1 includes an arc leading from this state to outside of the WG state machine. This illustrates that some I-Ds that are considered do not get adopted as WG drafts. An I-D that is not adopted as a WG draft will transition out of the WG state machine and revert back to having no stream-specific state; however, the status change history log of the I-D will record that the I-D was previously in the \"Call for Adoption by WG Issued\" state."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 35
|
||||
|
@ -3504,7 +3504,7 @@
|
|||
"slug": "adopt-wg",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 2,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.2\" target=\"_blank\">4.2.2. Adopted by a WG</a>\n\n The \"Adopted by a WG\" state describes an individual submission I-D that an IETF WG has agreed to adopt as one of its WG drafts.\n\n WG Chairs who use this state will be able to clearly indicate when their WGs adopt individual submission I-Ds. This will facilitate the Datatracker's ability to correctly capture \"Replaces\" information for WG drafts and correct \"Replaced by\" information for individual submission I-Ds that have been replaced by WG drafts.\n\n This state is needed because the Datatracker uses the filename of an I-D as a key to search its database for status information about the I-D, and because the filename of a WG I-D is supposed to be different from the filename of an individual submission I-D. The filename of an individual submission I-D will typically be formatted as 'draft-author-wgname-topic-nn'.\n\n The filename of a WG document is supposed to be formatted as 'draft- ietf-wgname-topic-nn'.\n\n An individual I-D that is adopted by a WG may take weeks or months to be resubmitted by the author as a new (version-00) WG draft. If the \"Adopted by a WG\" state is not used, the Datatracker has no way to determine that an I-D has been adopted until a new version of the I-D is submitted to the WG by the author and until the I-D is approved for posting by a WG Chair."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.2\" target=\"_blank\">4.2.2. Adopted by a WG</a>\n\n The \"Adopted by a WG\" state describes an individual submission I-D that an IETF WG has agreed to adopt as one of its WG drafts.\n\n WG Chairs who use this state will be able to clearly indicate when their WGs adopt individual submission I-Ds. This will facilitate the Datatracker's ability to correctly capture \"Replaces\" information for WG drafts and correct \"Replaced by\" information for individual submission I-Ds that have been replaced by WG drafts.\n\n This state is needed because the Datatracker uses the filename of an I-D as a key to search its database for status information about the I-D, and because the filename of a WG I-D is supposed to be different from the filename of an individual submission I-D. The filename of an individual submission I-D will typically be formatted as 'draft-author-wgname-topic-nn'.\n\n The filename of a WG document is supposed to be formatted as 'draft- ietf-wgname-topic-nn'.\n\n An individual I-D that is adopted by a WG may take weeks or months to be resubmitted by the author as a new (version-00) WG draft. If the \"Adopted by a WG\" state is not used, the Datatracker has no way to determine that an I-D has been adopted until a new version of the I-D is submitted to the WG by the author and until the I-D is approved for posting by a WG Chair."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 36
|
||||
|
@ -3517,7 +3517,7 @@
|
|||
"slug": "info",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 3,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.3\" target=\"_blank\">4.2.3. Adopted for WG Info Only</a>\n\n The \"Adopted for WG Info Only\" state describes a document that contains useful information for the WG that adopted it, but the document is not intended to be published as an RFC. The WG will not actively develop the contents of the I-D or progress it for publication as an RFC. The only purpose of the I-D is to provide information for internal use by the WG."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.3\" target=\"_blank\">4.2.3. Adopted for WG Info Only</a>\n\n The \"Adopted for WG Info Only\" state describes a document that contains useful information for the WG that adopted it, but the document is not intended to be published as an RFC. The WG will not actively develop the contents of the I-D or progress it for publication as an RFC. The only purpose of the I-D is to provide information for internal use by the WG."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 37
|
||||
|
@ -3535,7 +3535,7 @@
|
|||
"slug": "wg-doc",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 4,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.4\" target=\"_blank\">4.2.4. WG Document</a>\n\n The \"WG Document\" state describes an I-D that has been adopted by an IETF WG and is being actively developed.\n\n A WG Chair may transition an I-D into the \"WG Document\" state at any time as long as the I-D is not being considered or developed in any other WG.\n\n Alternatively, WG Chairs may rely upon new functionality to be added to the Datatracker to automatically move version-00 drafts into the \"WG Document\" state as described in Section 4.1.\n\n Under normal conditions, it should not be possible for an I-D to be in the \"WG Document\" state in more than one WG at a time. This said, I-Ds may be transferred from one WG to another with the consent of the WG Chairs and the responsible ADs."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.4\" target=\"_blank\">4.2.4. WG Document</a>\n\n The \"WG Document\" state describes an I-D that has been adopted by an IETF WG and is being actively developed.\n\n A WG Chair may transition an I-D into the \"WG Document\" state at any time as long as the I-D is not being considered or developed in any other WG.\n\n Alternatively, WG Chairs may rely upon new functionality to be added to the Datatracker to automatically move version-00 drafts into the \"WG Document\" state as described in Section 4.1.\n\n Under normal conditions, it should not be possible for an I-D to be in the \"WG Document\" state in more than one WG at a time. This said, I-Ds may be transferred from one WG to another with the consent of the WG Chairs and the responsible ADs."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 38
|
||||
|
@ -3550,7 +3550,7 @@
|
|||
"slug": "parked",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 5,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.5\" target=\"_blank\">4.2.5. Parked WG Document</a>\n\n A \"Parked WG Document\" is an I-D that has lost its author or editor, is waiting for another document to be written or for a review to be completed, or cannot be progressed by the working group for some other reason.\n\n Some of the annotation tags described in Section 4.3 may be used in conjunction with this state to indicate why an I-D has been parked, and/or what may need to happen for the I-D to be un-parked.\n\n Parking a WG draft will not prevent it from expiring; however, this state can be used to indicate why the I-D has stopped progressing in the WG.\n\n A \"Parked WG Document\" that is not expired may be transferred from one WG to another with the consent of the WG Chairs and the responsible ADs."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.5\" target=\"_blank\">4.2.5. Parked WG Document</a>\n\n A \"Parked WG Document\" is an I-D that has lost its author or editor, is waiting for another document to be written or for a review to be completed, or cannot be progressed by the working group for some other reason.\n\n Some of the annotation tags described in Section 4.3 may be used in conjunction with this state to indicate why an I-D has been parked, and/or what may need to happen for the I-D to be un-parked.\n\n Parking a WG draft will not prevent it from expiring; however, this state can be used to indicate why the I-D has stopped progressing in the WG.\n\n A \"Parked WG Document\" that is not expired may be transferred from one WG to another with the consent of the WG Chairs and the responsible ADs."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 39
|
||||
|
@ -3565,7 +3565,7 @@
|
|||
"slug": "dead",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 6,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.6\" target=\"_blank\">4.2.6. Dead WG Document</a>\n\n A \"Dead WG Document\" is an I-D that has been abandoned. Note that 'Dead' is not always a final state for a WG I-D. If consensus is subsequently achieved, a \"Dead WG Document\" may be resurrected. A \"Dead WG Document\" that is not resurrected will eventually expire.\n\n Note that an I-D that is declared to be \"Dead\" in one WG and that is not expired may be transferred to a non-dead state in another WG with the consent of the WG Chairs and the responsible ADs."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.6\" target=\"_blank\">4.2.6. Dead WG Document</a>\n\n A \"Dead WG Document\" is an I-D that has been abandoned. Note that 'Dead' is not always a final state for a WG I-D. If consensus is subsequently achieved, a \"Dead WG Document\" may be resurrected. A \"Dead WG Document\" that is not resurrected will eventually expire.\n\n Note that an I-D that is declared to be \"Dead\" in one WG and that is not expired may be transferred to a non-dead state in another WG with the consent of the WG Chairs and the responsible ADs."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 40
|
||||
|
@ -3582,7 +3582,7 @@
|
|||
"slug": "wg-lc",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 7,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.7\" target=\"_blank\">4.2.7. In WG Last Call</a>\n\n A document \"In WG Last Call\" is an I-D for which a WG Last Call (WGLC) has been issued and is in progress.\n\n Note that conducting a WGLC is an optional part of the IETF WG process, per Section 7.4 of RFC 2418 [RFC2418].\n\n If a WG Chair decides to conduct a WGLC on an I-D, the \"In WG Last Call\" state can be used to track the progress of the WGLC. The Chair may configure the Datatracker to send a WGLC message to one or more mailing lists when the Chair moves the I-D into this state. The WG Chair may also be able to select a different set of mailing lists for a different document undergoing a WGLC; some documents may deserve coordination with other WGs.\n\n A WG I-D in this state should remain \"In WG Last Call\" until the WG Chair moves it to another state. The WG Chair may configure the Datatracker to send an e-mail after a specified period of time to remind or 'nudge' the Chair to conclude the WGLC and to determine the next state for the document.\n\n It is possible for one WGLC to lead into another WGLC for the same document. For example, an I-D that completed a WGLC as an \"Informational\" document may need another WGLC if a decision is taken to convert the I-D into a Standards Track document."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.7\" target=\"_blank\">4.2.7. In WG Last Call</a>\n\n A document \"In WG Last Call\" is an I-D for which a WG Last Call (WGLC) has been issued and is in progress.\n\n Note that conducting a WGLC is an optional part of the IETF WG process, per Section 7.4 of RFC 2418 [RFC2418].\n\n If a WG Chair decides to conduct a WGLC on an I-D, the \"In WG Last Call\" state can be used to track the progress of the WGLC. The Chair may configure the Datatracker to send a WGLC message to one or more mailing lists when the Chair moves the I-D into this state. The WG Chair may also be able to select a different set of mailing lists for a different document undergoing a WGLC; some documents may deserve coordination with other WGs.\n\n A WG I-D in this state should remain \"In WG Last Call\" until the WG Chair moves it to another state. The WG Chair may configure the Datatracker to send an e-mail after a specified period of time to remind or 'nudge' the Chair to conclude the WGLC and to determine the next state for the document.\n\n It is possible for one WGLC to lead into another WGLC for the same document. For example, an I-D that completed a WGLC as an \"Informational\" document may need another WGLC if a decision is taken to convert the I-D into a Standards Track document."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 41
|
||||
|
@ -3598,7 +3598,7 @@
|
|||
"slug": "chair-w",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 8,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.8\" target=\"_blank\">4.2.8. Waiting for WG Chair Go-Ahead</a>\n\n A WG Chair may wish to place an I-D that receives a lot of comments during a WGLC into the \"Waiting for WG Chair Go-Ahead\" state. This state describes an I-D that has undergone a WGLC; however, the Chair is not yet ready to call consensus on the document.\n\n If comments from the WGLC need to be responded to, or a revision to the I-D is needed, the Chair may place an I-D into this state until all of the WGLC comments are adequately addressed and the (possibly revised) document is in the I-D repository."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.8\" target=\"_blank\">4.2.8. Waiting for WG Chair Go-Ahead</a>\n\n A WG Chair may wish to place an I-D that receives a lot of comments during a WGLC into the \"Waiting for WG Chair Go-Ahead\" state. This state describes an I-D that has undergone a WGLC; however, the Chair is not yet ready to call consensus on the document.\n\n If comments from the WGLC need to be responded to, or a revision to the I-D is needed, the Chair may place an I-D into this state until all of the WGLC comments are adequately addressed and the (possibly revised) document is in the I-D repository."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 42
|
||||
|
@ -3613,7 +3613,7 @@
|
|||
"slug": "writeupw",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 9,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.9\" target=\"_blank\">4.2.9. WG Consensus: Waiting for Writeup</a>\n\n A document in the \"WG Consensus: Waiting for Writeup\" state has essentially completed its development within the working group, and is nearly ready to be sent to the IESG for publication. The last thing to be done is the preparation of a protocol writeup by a Document Shepherd. The IESG requires that a document shepherd writeup be completed before publication of the I-D is requested. The IETF document shepherding process and the role of a WG Document Shepherd is described in RFC 4858 [RFC4858]\n\n A WG Chair may call consensus on an I-D without a formal WGLC and transition an I-D that was in the \"WG Document\" state directly into this state.\n\n The name of this state includes the words \"Waiting for Writeup\" because a good document shepherd writeup takes time to prepare."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.9\" target=\"_blank\">4.2.9. WG Consensus: Waiting for Writeup</a>\n\n A document in the \"WG Consensus: Waiting for Writeup\" state has essentially completed its development within the working group, and is nearly ready to be sent to the IESG for publication. The last thing to be done is the preparation of a protocol writeup by a Document Shepherd. The IESG requires that a document shepherd writeup be completed before publication of the I-D is requested. The IETF document shepherding process and the role of a WG Document Shepherd is described in RFC 4858 [RFC4858]\n\n A WG Chair may call consensus on an I-D without a formal WGLC and transition an I-D that was in the \"WG Document\" state directly into this state.\n\n The name of this state includes the words \"Waiting for Writeup\" because a good document shepherd writeup takes time to prepare."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 43
|
||||
|
@ -3628,7 +3628,7 @@
|
|||
"slug": "sub-pub",
|
||||
"type": "draft-stream-ietf",
|
||||
"order": 10,
|
||||
"desc": "<a href=\"https://tools.ietf.org/html/rfc6174#section-4.2.10\" target=\"_blank\">4.2.10. Submitted to IESG for Publication</a>\n\n This state describes a WG document that has been submitted to the IESG for publication and that has not been sent back to the working group for revision.\n\n An I-D in this state may be under review by the IESG, it may have been approved and be in the RFC Editor's queue, or it may have been published as an RFC. Other possibilities exist too. The document may be \"Dead\" (in the IESG state machine) or in a \"Do Not Publish\" state."
|
||||
"desc": "<a href=\"http://tools.ietf.org/html/rfc6174#section-4.2.10\" target=\"_blank\">4.2.10. Submitted to IESG for Publication</a>\n\n This state describes a WG document that has been submitted to the IESG for publication and that has not been sent back to the working group for revision.\n\n An I-D in this state may be under review by the IESG, it may have been approved and be in the RFC Editor's queue, or it may have been published as an RFC. Other possibilities exist too. The document may be \"Dead\" (in the IESG state machine) or in a \"Do Not Publish\" state."
|
||||
},
|
||||
"model": "doc.state",
|
||||
"pk": 44
|
||||
|
@ -4326,5 +4326,627 @@
|
|||
},
|
||||
"model": "doc.ballottype",
|
||||
"pk": 3
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The steering group (e.g. IRSG) of a document being reviewed for IETF stream conflicts"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "conflict_review_steering_group"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The stream manager of a document being reviewed for IETF stream conflicts"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "conflict_review_stream_manager"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{% if doc.ad %}{{doc.ad.email_address}}{% endif %}",
|
||||
"desc": "The document's responsible Area Director"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_ad"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The authors of the subject documents of a conflict-review or status-change"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_affecteddoc_authors"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The chairs of groups of the subject documents of a conflict-review or status-change"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_affecteddoc_group_chairs"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The notify field of the subject documents of a conflict-review or status-change"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_affecteddoc_notify"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{% if doc.type_id == \"draft\" %}{{doc.name}}@ietf.org{% endif %}",
|
||||
"desc": "The document's authors"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_authors"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The document's group chairs (if the document is assigned to a working or research group)"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_group_chairs"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The document's group delegates (if the document is assigned to a working or research group)"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_group_delegates"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The list address of the document's group"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_group_mail_list"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{{doc.notify}}",
|
||||
"desc": "The addresses in the document's notify field"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_notify"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{% if doc.shepherd %}{{doc.shepherd.address}}{% endif %}",
|
||||
"desc": "The document's shepherd"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_shepherd"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The manager of the document's stream"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "doc_stream_manager"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{{group.acronym}}-chairs@ietf.org",
|
||||
"desc": "The group's chairs"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "group_chairs"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "{{ group.list_email }}",
|
||||
"desc": "The group's mailing list"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "group_mail_list"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The group's responsible AD(s) or IRTF chair"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "group_responsible_directors"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The group's steering group (IESG or IRSG)"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "group_steering_group"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "<iana@iana.org>",
|
||||
"desc": "IANA"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iana"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "IANA <drafts-approval@icann.org>",
|
||||
"desc": "IANA's draft approval address"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iana_approve"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "IANA <drafts-eval@icann.org>",
|
||||
"desc": "IANA's draft evaluation address"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iana_eval"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "IANA <drafts-lastcall@icann.org>",
|
||||
"desc": "IANA's draft last call address"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iana_last_call"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "The IESG <iesg@ietf.org>",
|
||||
"desc": "The IESG"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iesg"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "<iesg-secretary@ietf.org>",
|
||||
"desc": "The Secretariat"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "iesg_secretary"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "IETF-Announce <ietf-announce@ietf.org>",
|
||||
"desc": "The IETF Announce list"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "ietf_announce"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": "<rfc-editor@rfc-editor.org>",
|
||||
"desc": "The RFC Editor"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "rfc_editor"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"template": null,
|
||||
"desc": "The managers of any related streams"
|
||||
},
|
||||
"model": "mailtoken.recipient",
|
||||
"pk": "stream_managers"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Recipients when a charter is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_charter"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_notify",
|
||||
"group_chairs",
|
||||
"group_mail_list",
|
||||
"group_steering_group"
|
||||
],
|
||||
"desc": "Copied when a charter is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_charter_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"conflict_review_steering_group",
|
||||
"conflict_review_stream_manager",
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_notify"
|
||||
],
|
||||
"desc": "Recipients when a conflict review ballot is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_conflrev"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iana",
|
||||
"iesg",
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Copied when a conflict review ballot is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_conflrev_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Recipients when an IETF stream document ballot is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_ietf_stream"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_ad",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_group_mail_list",
|
||||
"doc_notify",
|
||||
"doc_shepherd",
|
||||
"iesg",
|
||||
"rfc_editor"
|
||||
],
|
||||
"desc": "Copied when an IETF stream document ballot is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_ietf_stream_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iana_approve"
|
||||
],
|
||||
"desc": "Recipients for IANA message when an IETF stream document ballot is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_ietf_stream_iana"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Recipients when a status change is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_status_change"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_notify",
|
||||
"iesg",
|
||||
"rfc_editor"
|
||||
],
|
||||
"desc": "Copied when a status change is approved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_approved_status_change_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"conflict_review_stream_manager",
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_notify",
|
||||
"doc_shepherd",
|
||||
"iesg",
|
||||
"iesg_secretary"
|
||||
],
|
||||
"desc": "Recipients when a ballot is deferred to or undeferred from a future telechat"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_deferred"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iesg"
|
||||
],
|
||||
"desc": "Recipients when a new ballot position (with discusses, other blocking positions, or comments) is saved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_saved"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"conflict_review_stream_manager",
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_shepherd"
|
||||
],
|
||||
"desc": "Copied when a new ballot position (with discusses, other blocking positions, or comments) is saved"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "ballot_saved_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Recipients for a charter external review"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "charter_external_review"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"group_mail_list"
|
||||
],
|
||||
"desc": "Copied on a charter external review"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "charter_external_review_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iesg_secretary"
|
||||
],
|
||||
"desc": "Recipients for a stream manager's request for an IETF conflict review"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "conflrev_requested"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_notify",
|
||||
"iesg"
|
||||
],
|
||||
"desc": "Copied on a stream manager's request for an IETF conflict review"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "conflrev_requested_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iana_eval"
|
||||
],
|
||||
"desc": "Recipients for IANA message when a stream manager requests an IETF conflict review"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "conflrev_requested_iana"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_ad",
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_notify",
|
||||
"doc_shepherd"
|
||||
],
|
||||
"desc": "Recipients when a document's state is manutally edited"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "doc_state_edited"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_notify",
|
||||
"stream_managers"
|
||||
],
|
||||
"desc": "Recipients for notification when a document's stream changes"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "doc_stream_changed"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_group_delegates",
|
||||
"doc_shepherd"
|
||||
],
|
||||
"desc": "Recipients when the stream state of a document is manually edited"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "doc_stream_state_edited"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_notify",
|
||||
"doc_shepherd",
|
||||
"iesg"
|
||||
],
|
||||
"desc": "Recipients when a document's telechat date or other telechat specific details are changed"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "doc_telechat_details_changed"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"group_mail_list"
|
||||
],
|
||||
"desc": "Recipients when the set of approved milestones for a group are edited"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "group_approved_milestones_edited"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"group_chairs",
|
||||
"group_responsible_directors"
|
||||
],
|
||||
"desc": "Recipients when any of a group's milestones are edited"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "group_milestones_edited"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_authors",
|
||||
"doc_notify",
|
||||
"doc_shepherd",
|
||||
"iesg"
|
||||
],
|
||||
"desc": "Recipients when a last call has expired"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_expired"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iesg_secretary"
|
||||
],
|
||||
"desc": "Copied when a last call has expired"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_expired_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"ietf_announce"
|
||||
],
|
||||
"desc": "Recipients when a last call is issued"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_issued"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_ad",
|
||||
"doc_affecteddoc_authors",
|
||||
"doc_affecteddoc_group_chairs",
|
||||
"doc_affecteddoc_notify",
|
||||
"doc_authors",
|
||||
"doc_group_chairs",
|
||||
"doc_notify",
|
||||
"doc_shepherd"
|
||||
],
|
||||
"desc": "Copied when a last call is issued"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_issued_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iana_last_call"
|
||||
],
|
||||
"desc": "Recipients for IANA message when a last call is issued"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_issued_iana"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iesg_secretary"
|
||||
],
|
||||
"desc": "Recipients when AD requests a last call"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_requested"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_ad",
|
||||
"doc_notify",
|
||||
"doc_shepherd"
|
||||
],
|
||||
"desc": "Copied when AD requests a last call"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "last_call_requested_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_ad"
|
||||
],
|
||||
"desc": "Recipients when a draft is submitted to the IESG"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "pubreq_iesg"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"doc_group_chairs",
|
||||
"doc_notify",
|
||||
"doc_shepherd",
|
||||
"iesg_secretary"
|
||||
],
|
||||
"desc": "Copied when a draft is submitted to the IESG"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "pubreq_iesg_cc"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"rfc_editor"
|
||||
],
|
||||
"desc": "Recipients when a non-IETF stream manager requests publication"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "pubreq_rfced"
|
||||
},
|
||||
{
|
||||
"fields": {
|
||||
"recipients": [
|
||||
"iana_approve"
|
||||
],
|
||||
"desc": "Recipients for IANA message when a non-IETF stream manager requests publication"
|
||||
},
|
||||
"model": "mailtoken.mailtoken",
|
||||
"pk": "pubreq_rfced_iana"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -41,5 +41,9 @@ objects += ietf.doc.models.StateType.objects.all()
|
|||
objects += ietf.doc.models.State.objects.all()
|
||||
objects += ietf.doc.models.BallotType.objects.all()
|
||||
|
||||
import ietf.mailtoken.models
|
||||
objects += ietf.mailtoken.models.Recipient.objects.all()
|
||||
objects += ietf.mailtoken.models.MailToken.objects.all()
|
||||
|
||||
output("names", objects)
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from ietf.doc.models import DocEvent, Document, BallotDocEvent, BallotPositionDo
|
|||
from ietf.doc.utils import get_document_content, add_state_change_event
|
||||
from ietf.person.models import Person
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.doc.mails import email_ad, email_state_changed
|
||||
from ietf.doc.mails import email_state_changed
|
||||
from ietf.iesg.models import TelechatDate, TelechatAgendaItem, Telechat
|
||||
from ietf.iesg.agenda import agenda_data, get_doc_section
|
||||
from ietf.ietfauth.utils import role_required
|
||||
|
@ -262,7 +262,6 @@ def doc_detail(request, date, name):
|
|||
doc.save()
|
||||
|
||||
email_state_changed(request, doc, e.desc)
|
||||
email_ad(request, doc, doc.ad, login, e.desc)
|
||||
|
||||
if new_state.slug == "lc-req":
|
||||
request_last_call(request, doc)
|
||||
|
|
|
@ -8,7 +8,7 @@ import urllib2
|
|||
from django.utils.http import urlquote
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.doc.mails import email_ad, email_state_changed
|
||||
from ietf.doc.mails import email_state_changed
|
||||
from ietf.doc.models import Document, DocEvent, State, StateDocEvent, StateType, save_document_in_history
|
||||
from ietf.doc.utils import add_state_change_event
|
||||
from ietf.person.models import Person
|
||||
|
@ -206,7 +206,6 @@ def update_history_with_changes(changes, send_email=True):
|
|||
|
||||
if send_email and (state != prev_state):
|
||||
email_state_changed(None, doc, "IANA %s state changed to %s" % (kind, state.name))
|
||||
email_ad(None, doc, doc.ad, system, "IANA %s state changed to %s" % (kind, state.name))
|
||||
|
||||
if doc.time < timestamp:
|
||||
doc.time = timestamp
|
||||
|
|
|
@ -81,7 +81,8 @@ class IANASyncTests(TestCase):
|
|||
e = draft.latest_event(StateDocEvent, type="changed_state", state_type="draft-iana-action")
|
||||
self.assertEqual(e.desc, "IANA Action state changed to <b>Waiting on RFC Editor</b> from In Progress")
|
||||
# self.assertEqual(e.time, datetime.datetime(2011, 10, 9, 5, 0)) # check timezone handling
|
||||
self.assertEqual(len(outbox), mailbox_before + 3 * 2)
|
||||
self.assertEqual(len(outbox), mailbox_before + 3 )
|
||||
# TODO look sensibly at the message here
|
||||
|
||||
# make sure it doesn't create duplicates
|
||||
added_events, warnings = iana.update_history_with_changes(changes)
|
||||
|
|
|
@ -12,7 +12,6 @@ from ietf.ipr.models import HolderIprDisclosure, IprDocRel, IprDisclosureStateNa
|
|||
from ietf.meeting.models import Meeting
|
||||
from ietf.name.models import StreamName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.mailtoken.models import MailToken, Recipient
|
||||
|
||||
def create_person(group, role_name, name=None, username=None, email_address=None, password=None):
|
||||
"""Add person/user/email and role."""
|
||||
|
@ -331,15 +330,16 @@ def make_test_data():
|
|||
other_doc_factory('minutes','minutes-42-mars')
|
||||
other_doc_factory('slides','slides-42-mars-1')
|
||||
|
||||
# Trying the fixture route instead
|
||||
# EventMail tokens used by the views
|
||||
# This won't allow testing the results of the production configuration - if we want to do that, we'll need to
|
||||
# extract the production data either directly, or as a fixture
|
||||
recipient = Recipient.objects.create(slug='bogus_recipient',desc='Bogus Recipient',template='bogus@example.com')
|
||||
for slug in ['ballot_approved_charter', 'ballot_approved_charter_cc', 'ballot_approved_conflrev', 'ballot_approved_conflrev_cc', 'ballot_approved_ietf_stream', 'ballot_approved_ietf_stream_cc', 'ballot_approved_ietf_stream_iana', 'ballot_approved_status_change', 'ballot_approved_status_change_cc', 'ballot_deferred', 'ballot_saved', 'ballot_saved_cc', 'charter_external_review', 'charter_external_review_cc', 'conflrev_requested', 'conflrev_requested_cc', 'conflrev_requested_iana', 'doc_stream_changed', 'last_call_expired', 'last_call_expired_cc', 'last_call_issued', 'last_call_issued_cc', 'last_call_issued_iana', 'last_call_requested', 'last_call_requested_cc', 'pubreq_iesg', 'pubreq_iesg_cc', 'pubreq_rfced', 'pubreq_rfced_iana']:
|
||||
m = MailToken.objects.create(slug=slug,desc=slug)
|
||||
m.recipients=[recipient]
|
||||
# Well, this isn't working out so well - Recipients that have code backing up their gather sometimes refer to other Recipients...
|
||||
for slug in ['doc_authors','doc_group_chairs','doc_notify','doc_stream_owner','stream_managers']:
|
||||
Recipient.objects.create(slug=slug,desc="Bogus Recipient",template='bogus@example.com')
|
||||
# recipient = Recipient.objects.create(slug='bogus_recipient',desc='Bogus Recipient',template='bogus@example.com')
|
||||
# for slug in ['ballot_approved_charter', 'ballot_approved_charter_cc', 'ballot_approved_conflrev', 'ballot_approved_conflrev_cc', 'ballot_approved_ietf_stream', 'ballot_approved_ietf_stream_cc', 'ballot_approved_ietf_stream_iana', 'ballot_approved_status_change', 'ballot_approved_status_change_cc', 'ballot_deferred', 'ballot_saved', 'ballot_saved_cc', 'charter_external_review', 'charter_external_review_cc', 'conflrev_requested', 'conflrev_requested_cc', 'conflrev_requested_iana', 'doc_stream_changed', 'last_call_expired', 'last_call_expired_cc', 'last_call_issued', 'last_call_issued_cc', 'last_call_issued_iana', 'last_call_requested', 'last_call_requested_cc', 'pubreq_iesg', 'pubreq_iesg_cc', 'pubreq_rfced', 'pubreq_rfced_iana']:
|
||||
# m = MailToken.objects.create(slug=slug,desc=slug)
|
||||
# m.recipients=[recipient]
|
||||
# # Well, this isn't working out so well - Recipients that have code backing up their gather sometimes refer to other Recipients...
|
||||
# for slug in ['doc_authors','doc_group_chairs','doc_notify','doc_stream_owner','stream_managers']:
|
||||
# Recipient.objects.create(slug=slug,desc="Bogus Recipient",template='bogus@example.com')
|
||||
|
||||
return draft
|
||||
|
|
Loading…
Reference in a new issue