Merged in [8293] from rjsparks@nostrum.com:\n XXX: Should what is now captured in the list of STATUSCHANGE_RELATIONS instead be captured in the database in name_docrelationshipname?
Refactored editing the notify field to remove redundant code. Changed the default notification list to include .all for documents, and the wg list for wg documents. Allowed recalculating the notification list for all document types. Improved the calculated notification list value for charters, conflict-reviews, and status-changes. Adds shepherds to the notification list when they are assigned to a document. Adds the working group email list to the notification list when a document is adopted. Fixes #1438 - Legacy-Id: 8385 Note: SVN reference [8293] has been migrated to Git commit 640c5eb52ace8bb6d2c1b3ca6c14ef10ad0f324f
This commit is contained in:
parent
6f7a2cceb6
commit
d4e5f070af
|
@ -34,4 +34,8 @@ class AdForm(forms.Form):
|
|||
self.fields['ad'].choices = list(choices) + [("", "-------"), (ad_pk, Person.objects.get(pk=ad_pk).plain_name())]
|
||||
|
||||
class NotifyForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
|
||||
notify = forms.CharField(max_length=255, help_text="List of email addresses to receive state notifications, separated by comma", label="Notification list", required=False)
|
||||
|
||||
def clean_notify(self):
|
||||
addrspecs = [x.strip() for x in self.cleaned_data["notify"].split(',')]
|
||||
return ', '.join(addrspecs)
|
||||
|
|
|
@ -178,6 +178,8 @@ class DocumentInfo(models.Model):
|
|||
class Meta:
|
||||
abstract = True
|
||||
|
||||
STATUSCHANGE_RELATIONS = ('tops','tois','tohist','toinf','tobcp','toexp')
|
||||
|
||||
class RelatedDocument(models.Model):
|
||||
source = models.ForeignKey('Document')
|
||||
target = models.ForeignKey('DocAlias')
|
||||
|
|
|
@ -181,11 +181,23 @@ class EditCharterTests(TestCase):
|
|||
|
||||
# post
|
||||
self.assertTrue(not charter.notify)
|
||||
r = self.client.post(url, dict(notify="someone@example.com, someoneelse@example.com"))
|
||||
newlist = "someone@example.com, someoneelse@example.com"
|
||||
r = self.client.post(url, dict(notify=newlist,save_addresses="1"))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
charter = Document.objects.get(name=charter.name)
|
||||
self.assertEqual(charter.notify, "someone@example.com, someoneelse@example.com")
|
||||
self.assertEqual(charter.notify, newlist)
|
||||
|
||||
# Ask the form to regenerate the list
|
||||
r = self.client.post(url,dict(regenerate_addresses="1"))
|
||||
self.assertEqual(r.status_code,200)
|
||||
charter= Document.objects.get(name=charter.name)
|
||||
# Regenerate does not save!
|
||||
self.assertEqual(charter.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
formlist = q('form input[name=notify]')[0].value
|
||||
self.assertTrue('marschairman@ietf.org' in formlist)
|
||||
self.assertFalse('someone@example.com' in formlist)
|
||||
|
||||
def test_edit_ad(self):
|
||||
make_test_data()
|
||||
|
|
|
@ -176,12 +176,22 @@ class ConflictReviewTests(TestCase):
|
|||
|
||||
# change notice list
|
||||
newlist = '"Foo Bar" <foo@bar.baz.com>'
|
||||
r = self.client.post(url,dict(notify=newlist))
|
||||
r = self.client.post(url,dict(notify=newlist,save_addresses="1"))
|
||||
self.assertEqual(r.status_code,302)
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Notification list changed'))
|
||||
|
||||
# Ask the form to regenerate the list
|
||||
r = self.client.post(url,dict(regenerate_addresses="1"))
|
||||
self.assertEqual(r.status_code,200)
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
# Regenerate does not save!
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue('draft-imaginary-irtf-submission@tools.ietf.org' in q('form input[name=notify]')[0].value)
|
||||
self.assertTrue('irtf-chair@ietf.org' in q('form input[name=notify]')[0].value)
|
||||
self.assertTrue('foo@bar.baz.com' not in q('form input[name=notify]')[0].value)
|
||||
|
||||
def test_edit_ad(self):
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
|
|
|
@ -841,7 +841,9 @@ class IndividualInfoFormsTests(TestCase):
|
|||
self.assertEqual(r.status_code,302)
|
||||
self.doc = Document.objects.get(name=self.docname)
|
||||
self.assertEqual(self.doc.shepherd,plain)
|
||||
self.assertTrue(self.doc.latest_event(DocEvent,type="added_comment").desc.startswith('Document shepherd changed to Plain Man'))
|
||||
comments = '::'.join([x.desc for x in self.doc.docevent_set.filter(time=self.doc.time,type="added_comment")])
|
||||
self.assertTrue('Document shepherd changed to Plain Man' in comments)
|
||||
self.assertTrue('Notification list changed' in comments)
|
||||
|
||||
ad = Person.objects.get(name='Aread Irector')
|
||||
two_answers = "%s,%s" % (plain_email, ad.email_set.all()[0])
|
||||
|
@ -1021,16 +1023,19 @@ class AdoptDraftTests(TestCase):
|
|||
# adopt in mars WG
|
||||
mailbox_before = len(outbox)
|
||||
events_before = draft.docevent_set.count()
|
||||
mars = Group.objects.get(acronym="mars")
|
||||
r = self.client.post(url,
|
||||
dict(comment="some comment",
|
||||
group=Group.objects.get(acronym="mars").pk,
|
||||
group=mars.pk,
|
||||
weeks="10"))
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
draft = Document.objects.get(pk=draft.pk)
|
||||
self.assertEqual(draft.group.acronym, "mars")
|
||||
self.assertEqual(draft.stream_id, "ietf")
|
||||
self.assertEqual(draft.docevent_set.count() - events_before, 4)
|
||||
self.assertEqual(draft.docevent_set.count() - events_before, 5)
|
||||
self.assertTrue(mars.list_email in draft.notify)
|
||||
self.assertTrue('draft-ietf-mars-test.all@tools.ietf.org' in draft.notify)
|
||||
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]))
|
||||
|
|
|
@ -139,12 +139,28 @@ class StatusChangeTests(TestCase):
|
|||
|
||||
# change notice list
|
||||
newlist = '"Foo Bar" <foo@bar.baz.com>'
|
||||
r = self.client.post(url,dict(notify=newlist))
|
||||
r = self.client.post(url,dict(notify=newlist,save_addresses="1"))
|
||||
self.assertEqual(r.status_code,302)
|
||||
doc = Document.objects.get(name='status-change-imaginary-mid-review')
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Notification list changed'))
|
||||
|
||||
# Some additional setup so there's something to put in a generated notify list
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9999'),relationship_id='tois')
|
||||
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9998'),relationship_id='tohist')
|
||||
|
||||
# Ask the form to regenerate the list
|
||||
r = self.client.post(url,dict(regenerate_addresses="1"))
|
||||
self.assertEqual(r.status_code,200)
|
||||
doc = Document.objects.get(name='status-change-imaginary-mid-review')
|
||||
# Regenerate does not save!
|
||||
self.assertEqual(doc.notify,newlist)
|
||||
q = PyQuery(r.content)
|
||||
formlist = q('form input[name=notify]')[0].value
|
||||
self.assertTrue('draft-ietf-random-thing@ietf.org' in formlist)
|
||||
self.assertTrue('draft-ietf-random-otherthing@ietf.org' in formlist)
|
||||
self.assertFalse('foo@bar.baz.com' in formlist)
|
||||
|
||||
def test_edit_title(self):
|
||||
doc = Document.objects.get(name='status-change-imaginary-mid-review')
|
||||
url = urlreverse('status_change_title',kwargs=dict(name=doc.name))
|
||||
|
|
|
@ -74,7 +74,7 @@ urlpatterns = patterns('',
|
|||
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/stream/$', views_draft.change_stream, name='doc_change_stream'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/replaces/$', views_draft.replaces, name='doc_change_replaces'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/notify/$', views_draft.edit_notices, name='doc_change_notify'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/notify/$', views_doc.edit_notify, name='doc_change_notify'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/status/$', views_draft.change_intention, name='doc_change_intended_status'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_doc.telechat_date, name='doc_change_telechat_date'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/iesgnote/$', views_draft.edit_iesg_note, name='doc_change_iesg_note'),
|
||||
|
|
|
@ -6,7 +6,7 @@ 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_doc.telechat_date", name='charter_telechat_date'),
|
||||
url(r'^notify/$', "ietf.doc.views_charter.edit_notify", name='charter_edit_notify'),
|
||||
url(r'^notify/$', "ietf.doc.views_doc.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"),
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.conf.urls import patterns, url
|
|||
urlpatterns = patterns('ietf.doc.views_conflict_review',
|
||||
url(r'^state/$', "change_state", name='conflict_review_change_state'),
|
||||
url(r'^submit/$', "submit", name='conflict_review_submit'),
|
||||
url(r'^notices/$', "edit_notices", name='conflict_review_notices'),
|
||||
url(r'^ad/$', "edit_ad", name='conflict_review_ad'),
|
||||
url(r'^approve/$', "approve", name='conflict_review_approve'),
|
||||
url(r'^start_conflict_review/$', "start_review", name='conflict_review_start'),
|
||||
|
@ -11,6 +10,7 @@ urlpatterns = patterns('ietf.doc.views_conflict_review',
|
|||
|
||||
urlpatterns += patterns('ietf.doc.views_doc',
|
||||
url(r'^telechat/$', "telechat_date", name='conflict_review_telechat_date'),
|
||||
url(r'^notices/$', "edit_notify", name='conflict_review_notices'),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.conf.urls import patterns, url
|
|||
urlpatterns = patterns('ietf.doc.views_status_change',
|
||||
url(r'^state/$', "change_state", name='status_change_change_state'),
|
||||
url(r'^submit/$', "submit", name='status_change_submit'),
|
||||
url(r'^notices/$', "edit_notices", name='status_change_notices'),
|
||||
url(r'^ad/$', "edit_ad", name='status_change_ad'),
|
||||
url(r'^title/$', "edit_title", name='status_change_title'),
|
||||
url(r'^approve/$', "approve", name='status_change_approve'),
|
||||
|
@ -13,6 +12,7 @@ urlpatterns = patterns('ietf.doc.views_status_change',
|
|||
|
||||
urlpatterns += patterns('ietf.doc.views_doc',
|
||||
url(r'^telechat/$', "telechat_date", name='status_change_telechat_date'),
|
||||
url(r'^notices/$', "edit_notify", name='status_change_notices'),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -5,16 +5,19 @@ import math
|
|||
import datetime
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.db.models.query import EmptyQuerySet
|
||||
from django.forms import ValidationError
|
||||
from django.utils.html import strip_tags
|
||||
from django.utils.html import strip_tags, escape
|
||||
|
||||
from ietf.utils import markup_txt
|
||||
from ietf.doc.models import Document, DocHistory
|
||||
from ietf.doc.models import DocAlias, RelatedDocument, BallotType, DocReminder
|
||||
from ietf.doc.models import DocEvent, BallotDocEvent, NewRevisionDocEvent, StateDocEvent
|
||||
from ietf.doc.models import save_document_in_history, STATUSCHANGE_RELATIONS
|
||||
from ietf.name.models import DocReminderTypeName, DocRelationshipName
|
||||
from ietf.group.models import Role
|
||||
from ietf.person.models import Email
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.utils import draft
|
||||
from ietf.utils.mail import send_mail
|
||||
|
@ -333,6 +336,29 @@ def has_same_ballot(doc, date1, date2=datetime.date.today()):
|
|||
ballot2 = doc.latest_event(BallotDocEvent,type='created_ballot',time__lt=date2+datetime.timedelta(days=1))
|
||||
return ballot1==ballot2
|
||||
|
||||
def make_notify_changed_event(request, doc, by, new_notify, time=None):
|
||||
|
||||
# FOR REVIEW: This preserves the behavior from when
|
||||
# drafts and charters had separate edit_notify
|
||||
# functions. If it should be unified, there should
|
||||
# also be a migration function cause historic
|
||||
# events to match
|
||||
if doc.type.slug=='charter':
|
||||
event_type = 'changed_document'
|
||||
save_document_in_history(doc)
|
||||
else:
|
||||
event_type = 'added_comment'
|
||||
|
||||
e = DocEvent(type=event_type, doc=doc, by=by)
|
||||
e.desc = "Notification list changed to %s" % (escape(new_notify) or "none")
|
||||
if doc.notify:
|
||||
e.desc += " from %s" % escape(doc.notify)
|
||||
if time:
|
||||
e.time = time
|
||||
e.save()
|
||||
|
||||
return e
|
||||
|
||||
def update_telechat(request, doc, by, new_telechat_date, new_returning_item=None):
|
||||
from ietf.doc.models import TelechatDocEvent
|
||||
|
||||
|
@ -447,3 +473,47 @@ def check_common_doc_name_rules(name):
|
|||
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
|
||||
def get_initial_notify(doc,extra=None):
|
||||
# set change state notice to something sensible
|
||||
receivers = []
|
||||
|
||||
if doc.type.slug=='draft':
|
||||
if doc.group.type_id in ("individ", "area"):
|
||||
for a in doc.authors.all():
|
||||
receivers.append(a.address)
|
||||
else:
|
||||
receivers.append("%s-chairs@%s" % (doc.group.acronym, settings.TOOLS_SERVER))
|
||||
for editor in Email.objects.filter(role__name="editor", role__group=doc.group):
|
||||
receivers.append(editor.address)
|
||||
|
||||
if doc.group.list_email:
|
||||
receivers.append(doc.group.list_email)
|
||||
|
||||
receivers.append("%s.all@%s" % (doc.name, settings.TOOLS_SERVER))
|
||||
|
||||
elif doc.type.slug=='charter':
|
||||
receivers.extend([role.person.formatted_email() for role in doc.group.role_set.filter(name__slug__in=['ad','chair','secr','techadv'])])
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
for relation in doc.relateddocument_set.filter(Q(relationship='conflrev')|Q(relationship__in=STATUSCHANGE_RELATIONS)):
|
||||
if relation.relationship.slug=='conflrev':
|
||||
doc_to_review = relation.target.document
|
||||
receivers.extend([x.person.formatted_email() for x in Role.objects.filter(group__acronym=doc_to_review.stream.slug,name='chair')])
|
||||
receivers.append("%s@%s" % (doc_to_review.name, settings.TOOLS_SERVER))
|
||||
elif relation.relationship.slug in STATUSCHANGE_RELATIONS:
|
||||
affected_doc = relation.target.document
|
||||
if affected_doc.notify:
|
||||
receivers.extend(affected_doc.notify.split(','))
|
||||
|
||||
if doc.shepherd:
|
||||
receivers.append(doc.shepherd.email_address())
|
||||
|
||||
if extra:
|
||||
if isinstance(extra,basestring):
|
||||
extra = extra.split(', ')
|
||||
receivers.extend(extra)
|
||||
|
||||
return ", ".join(set([x.strip() for x in receivers]))
|
||||
|
|
|
@ -5,7 +5,6 @@ from django.shortcuts import render_to_response, get_object_or_404, redirect
|
|||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template import RequestContext
|
||||
from django import forms
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
@ -225,48 +224,6 @@ def change_state(request, name, option=None):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class NotifyForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, help_text="List of email addresses to receive state notifications, separated by comma", label="Notification list", required=False)
|
||||
|
||||
def clean_notify(self):
|
||||
return self.cleaned_data["notify"].strip()
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def edit_notify(request, name):
|
||||
doc = get_object_or_404(Document, type="charter", name=name)
|
||||
login = request.user.person
|
||||
|
||||
init = {'notify': doc.notify}
|
||||
|
||||
if request.method == "POST":
|
||||
form = NotifyForm(request.POST, initial=init)
|
||||
if form.is_valid():
|
||||
n = form.cleaned_data["notify"]
|
||||
if n != doc.notify:
|
||||
save_document_in_history(doc)
|
||||
|
||||
e = DocEvent(doc=doc, by=login)
|
||||
e.desc = "Notification list changed to %s" % (escape(n) or "none")
|
||||
if doc.notify:
|
||||
e.desc += " from %s" % escape(doc.notify)
|
||||
e.type = "changed_document"
|
||||
e.save()
|
||||
|
||||
doc.notify = n
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
||||
return redirect("doc_view", name=doc.name)
|
||||
else:
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
return render_to_response('doc/charter/edit_notify.html',
|
||||
dict(doc=doc,
|
||||
form=form,
|
||||
user=request.user,
|
||||
login=login),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class AdForm(forms.Form):
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
|
||||
label="Responsible AD", empty_label="(None)", required=True)
|
||||
|
|
|
@ -13,7 +13,7 @@ from ietf.doc.models import ( BallotDocEvent, BallotPositionDocEvent, DocAlias,
|
|||
from ietf.doc.utils import ( add_state_change_event, close_open_ballots,
|
||||
create_ballot_if_not_open, get_document_content, update_telechat )
|
||||
from ietf.doc.mails import email_iana
|
||||
from ietf.doc.forms import AdForm, NotifyForm
|
||||
from ietf.doc.forms import AdForm
|
||||
from ietf.group.models import Role, Group
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.ietfauth.utils import has_role, role_required, is_authorized_in_doc_stream
|
||||
|
@ -205,41 +205,6 @@ def submit(request, name):
|
|||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def edit_notices(request, name):
|
||||
"""Change the set of email addresses document change notificaitions go to."""
|
||||
|
||||
review = get_object_or_404(Document, type="conflrev", name=name)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = NotifyForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
review.notify = form.cleaned_data['notify']
|
||||
review.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=review, by=login)
|
||||
c.desc = "Notification list changed to : "+review.notify
|
||||
c.save()
|
||||
|
||||
return redirect('doc_view', name=review.name)
|
||||
|
||||
else:
|
||||
|
||||
init = { "notify" : review.notify }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev)
|
||||
return render_to_response('doc/notify.html',
|
||||
{'form': form,
|
||||
'doc': review,
|
||||
'titletext' : titletext
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def edit_ad(request, name):
|
||||
"""Change the shepherding Area Director for this review."""
|
||||
|
|
|
@ -43,20 +43,20 @@ from django import forms
|
|||
|
||||
from ietf.doc.models import ( Document, DocAlias, DocHistory, DocEvent, BallotDocEvent,
|
||||
ConsensusDocEvent, NewRevisionDocEvent, TelechatDocEvent, WriteupDocEvent,
|
||||
IESG_BALLOT_ACTIVE_STATES)
|
||||
IESG_BALLOT_ACTIVE_STATES, STATUSCHANGE_RELATIONS )
|
||||
from ietf.doc.utils import ( add_links_in_new_revision_events, augment_events_with_revision,
|
||||
can_adopt_draft, get_chartering_type, get_document_content, get_tags_for_stream_id,
|
||||
needed_ballot_positions, nice_consensus, prettify_std_name, update_telechat, has_same_ballot)
|
||||
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.doc.views_status_change import RELATION_SLUGS as status_change_relationships
|
||||
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
|
||||
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
|
||||
from ietf.doc.forms import TelechatForm, NotifyForm
|
||||
|
||||
def render_document_top(request, doc, tab, name):
|
||||
tabs = []
|
||||
|
@ -289,7 +289,7 @@ def document_main(request, name, rev=None):
|
|||
# conflict reviews
|
||||
conflict_reviews = [d.document.name for d in doc.related_that("conflrev")]
|
||||
|
||||
status_change_docs = doc.related_that(status_change_relationships)
|
||||
status_change_docs = doc.related_that(STATUSCHANGE_RELATIONS)
|
||||
status_changes = [ rel.document for rel in status_change_docs if rel.document.get_state_slug() in ('appr-sent','appr-pend')]
|
||||
proposed_status_changes = [ rel.document for rel in status_change_docs if rel.document.get_state_slug() in ('needshep','adrev','iesgeval','defer','appr-pr')]
|
||||
|
||||
|
@ -897,3 +897,49 @@ def telechat_date(request, name):
|
|||
prompts=prompts,
|
||||
login=login),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required('Area Director', 'Secretariat')
|
||||
def edit_notify(request, name):
|
||||
"""Change the set of email addresses document change notificaitions go to."""
|
||||
|
||||
login = request.user.person
|
||||
doc = get_object_or_404(Document, name=name)
|
||||
init = { "notify" : doc.notify }
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
if "save_addresses" in request.POST:
|
||||
form = NotifyForm(request.POST)
|
||||
if form.is_valid():
|
||||
new_notify = form.cleaned_data['notify']
|
||||
if set(new_notify.split(',')) != set(doc.notify.split(',')):
|
||||
e = make_notify_changed_event(request, doc, login, new_notify)
|
||||
doc.notify = new_notify
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
elif "regenerate_addresses" in request.POST:
|
||||
init = { "notify" : get_initial_notify(doc) }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
# Protect from handcrufted POST
|
||||
else:
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
else:
|
||||
|
||||
init = { "notify" : doc.notify }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
if doc.type.slug=='conflrev':
|
||||
conflictdoc = doc.relateddocument_set.get(relationship__slug='conflrev').target.document
|
||||
titletext = 'the conflict review of %s' % conflictdoc.canonical_name()
|
||||
else:
|
||||
titletext = '%s' % doc.canonical_name()
|
||||
return render_to_response('doc/edit_notify.html',
|
||||
{'form': form,
|
||||
'doc': doc,
|
||||
'titletext': titletext,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
|
|
@ -21,7 +21,7 @@ from ietf.doc.mails import ( email_ad, email_pulled_from_rfc_queue, email_resurr
|
|||
generate_publication_request, html_to_text )
|
||||
from ietf.doc.utils import ( add_state_change_event, can_adopt_draft,
|
||||
get_tags_for_stream_id, nice_consensus,
|
||||
update_reminder, update_telechat )
|
||||
update_reminder, update_telechat, make_notify_changed_event, get_initial_notify )
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.iesg.models import TelechatDate
|
||||
|
@ -30,7 +30,7 @@ from ietf.ietfauth.utils import role_required
|
|||
from ietf.message.models import Message
|
||||
from ietf.name.models import IntendedStdLevelName, DocTagName, StreamName
|
||||
from ietf.person.forms import EmailsField
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.person.models import Person
|
||||
from ietf.secr.lib.template import jsonapi
|
||||
from ietf.utils.mail import send_mail, send_mail_message
|
||||
from ietf.utils.textupload import get_cleaned_text_file_content
|
||||
|
@ -501,21 +501,6 @@ class EditInfoForm(forms.Form):
|
|||
def clean_note(self):
|
||||
return self.cleaned_data['note'].replace('\r', '').strip()
|
||||
|
||||
|
||||
def get_initial_notify(doc):
|
||||
# set change state notice to something sensible
|
||||
receivers = []
|
||||
if doc.group.type_id in ("individ", "area"):
|
||||
for a in doc.authors.all():
|
||||
receivers.append(a.address)
|
||||
else:
|
||||
receivers.append("%s-chairs@%s" % (doc.group.acronym, settings.TOOLS_SERVER))
|
||||
for editor in Email.objects.filter(role__name="editor", role__group=doc.group):
|
||||
receivers.append(editor.address)
|
||||
|
||||
receivers.append("%s@%s" % (doc.name, settings.TOOLS_SERVER))
|
||||
return ", ".join(receivers)
|
||||
|
||||
def to_iesg(request,name):
|
||||
""" Submit an IETF stream document to the IESG for publication """
|
||||
doc = get_object_or_404(Document, docalias__name=name, stream='ietf')
|
||||
|
@ -831,52 +816,6 @@ def resurrect(request, name):
|
|||
back_url=doc.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class NotifyForm(forms.Form):
|
||||
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
|
||||
|
||||
|
||||
@role_required('Area Director', 'Secretariat')
|
||||
def edit_notices(request, name):
|
||||
"""Change the set of email addresses document change notificaitions go to."""
|
||||
|
||||
doc = get_object_or_404(Document, type="draft", name=name)
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
if "save_addresses" in request.POST:
|
||||
form = NotifyForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
doc.notify = form.cleaned_data['notify']
|
||||
doc.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=doc, by=login)
|
||||
c.desc = "Notification list changed to : "+doc.notify
|
||||
c.save()
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
elif "regenerate_addresses" in request.POST:
|
||||
init = { "notify" : get_initial_notify(doc) }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
# Protect from handcrufted POST
|
||||
else:
|
||||
init = { "notify" : doc.notify }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
else:
|
||||
|
||||
init = { "notify" : doc.notify }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
return render_to_response('doc/draft/change_notify.html',
|
||||
{'form': form,
|
||||
'doc': doc,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
class IESGNoteForm(forms.Form):
|
||||
note = forms.CharField(widget=forms.Textarea, label="IESG note", required=False)
|
||||
|
||||
|
@ -1028,13 +967,23 @@ def edit_shepherd(request, name):
|
|||
doc.shepherd = form.cleaned_data['shepherd'][0].person
|
||||
else:
|
||||
doc.shepherd = None
|
||||
doc.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=doc, by=login)
|
||||
c.desc = "Document shepherd changed to "+ (doc.shepherd.name if doc.shepherd else "(None)")
|
||||
c.save()
|
||||
|
||||
if doc.shepherd.formatted_email() not in doc.notify:
|
||||
addrs = doc.notify
|
||||
if addrs:
|
||||
addrs += ', '
|
||||
addrs += doc.shepherd.formatted_email()
|
||||
e = make_notify_changed_event(request, doc, login, addrs, c.time)
|
||||
doc.notify = addrs
|
||||
|
||||
doc.time = c.time
|
||||
doc.save()
|
||||
|
||||
return redirect('doc_view', name=doc.name)
|
||||
|
||||
else:
|
||||
|
@ -1291,6 +1240,10 @@ def adopt_draft(request, name):
|
|||
e.save()
|
||||
doc.group = group
|
||||
|
||||
new_notify = get_initial_notify(doc,extra=doc.notify)
|
||||
make_notify_changed_event(request, doc, by, new_notify, doc.time)
|
||||
doc.notify = new_notify
|
||||
|
||||
doc.save()
|
||||
|
||||
comment = form.cleaned_data["comment"].strip()
|
||||
|
|
|
@ -10,8 +10,8 @@ from django.conf import settings
|
|||
|
||||
from ietf.doc.models import ( Document, DocAlias, State, DocEvent, BallotDocEvent,
|
||||
BallotPositionDocEvent, NewRevisionDocEvent, WriteupDocEvent,
|
||||
save_document_in_history )
|
||||
from ietf.doc.forms import AdForm, NotifyForm
|
||||
save_document_in_history, STATUSCHANGE_RELATIONS )
|
||||
from ietf.doc.forms import AdForm
|
||||
from ietf.doc.lastcall import request_last_call
|
||||
from ietf.doc.utils import get_document_content, add_state_change_event, update_telechat, close_open_ballots, create_ballot_if_not_open
|
||||
from ietf.doc.views_ballot import LastCallTextForm
|
||||
|
@ -199,38 +199,6 @@ def submit(request, name):
|
|||
},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def edit_notices(request, name):
|
||||
"""Change the set of email addresses document change notificaitions go to."""
|
||||
|
||||
status_change = get_object_or_404(Document, type="statchg", name=name)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = NotifyForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
status_change.notify = form.cleaned_data['notify']
|
||||
status_change.save()
|
||||
|
||||
login = request.user.person
|
||||
c = DocEvent(type="added_comment", doc=status_change, by=login)
|
||||
c.desc = "Notification list changed to : "+status_change.notify
|
||||
c.save()
|
||||
|
||||
return redirect('doc_view', name=status_change.name)
|
||||
|
||||
else:
|
||||
|
||||
init = { "notify" : status_change.notify }
|
||||
form = NotifyForm(initial=init)
|
||||
|
||||
return render_to_response('doc/notify.html',
|
||||
{'form': form,
|
||||
'doc': status_change,
|
||||
'titletext' : '%s-%s.txt' % (status_change.canonical_name(),status_change.rev)
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
class ChangeTitleForm(forms.Form):
|
||||
title = forms.CharField(max_length=255, label="Title", required=True)
|
||||
|
||||
|
@ -390,7 +358,7 @@ def approve(request, name):
|
|||
c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text']
|
||||
c.save()
|
||||
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
|
||||
# Add a document event to each target
|
||||
c = DocEvent(type="added_comment", doc=rel.target.document, by=login)
|
||||
c.desc = "New status of %s approved by the IESG\n%s%s" % (newstatus(rel), settings.IDTRACKER_BASE_URL,reverse('doc_view', kwargs={'name': status_change.name}))
|
||||
|
@ -401,7 +369,7 @@ def approve(request, name):
|
|||
else:
|
||||
|
||||
init = []
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
|
||||
init.append({"announcement_text" : default_approval_text(status_change,rel),
|
||||
"label": "Announcement text for %s to %s"%(rel.target.document.canonical_name(),newstatus(rel)),
|
||||
})
|
||||
|
@ -416,8 +384,6 @@ def approve(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
RELATION_SLUGS = ('tops','tois','tohist','toinf','tobcp','toexp')
|
||||
|
||||
def clean_helper(form, formtype):
|
||||
cleaned_data = super(formtype, form).clean()
|
||||
|
||||
|
@ -449,7 +415,7 @@ def clean_helper(form, formtype):
|
|||
elif not DocAlias.objects.filter(name=key):
|
||||
errors.append(key+" does not exist\n")
|
||||
|
||||
if new_relations[key] not in RELATION_SLUGS:
|
||||
if new_relations[key] not in STATUSCHANGE_RELATIONS:
|
||||
errors.append("Please choose a new status level for "+key+"\n")
|
||||
|
||||
if errors:
|
||||
|
@ -542,7 +508,7 @@ def start_rfc_status_change(request,name):
|
|||
|
||||
login = request.user.person
|
||||
|
||||
relation_slugs = DocRelationshipName.objects.filter(slug__in=RELATION_SLUGS)
|
||||
relation_slugs = DocRelationshipName.objects.filter(slug__in=STATUSCHANGE_RELATIONS)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = StartStatusChangeForm(request.POST)
|
||||
|
@ -598,17 +564,17 @@ def edit_relations(request, name):
|
|||
|
||||
login = request.user.person
|
||||
|
||||
relation_slugs = DocRelationshipName.objects.filter(slug__in=RELATION_SLUGS)
|
||||
relation_slugs = DocRelationshipName.objects.filter(slug__in=STATUSCHANGE_RELATIONS)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = EditStatusChangeForm(request.POST)
|
||||
if 'Submit' in request.POST and form.is_valid():
|
||||
|
||||
old_relations={}
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
|
||||
old_relations[rel.target.document.canonical_name()]=rel.relationship.slug
|
||||
new_relations=form.cleaned_data['relations']
|
||||
status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS).delete()
|
||||
status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS).delete()
|
||||
for key in new_relations:
|
||||
status_change.relateddocument_set.create(target=DocAlias.objects.get(name=key),
|
||||
relationship_id=new_relations[key])
|
||||
|
@ -629,7 +595,7 @@ def edit_relations(request, name):
|
|||
|
||||
else:
|
||||
relations={}
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
|
||||
for rel in status_change.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS):
|
||||
relations[rel.target.document.canonical_name()]=rel.relationship.slug
|
||||
init = { "relations":relations,
|
||||
}
|
||||
|
@ -657,8 +623,8 @@ def generate_last_call_text(request, doc):
|
|||
settings=settings,
|
||||
requester=requester,
|
||||
expiration_date=expiration_date.strftime("%Y-%m-%d"),
|
||||
changes=['%s from %s to %s\n (%s)'%(rel.target.name.upper(),rel.target.document.std_level.name,newstatus(rel),rel.target.document.title) for rel in doc.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS)],
|
||||
urls=[rel.target.document.get_absolute_url() for rel in doc.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS)],
|
||||
changes=['%s from %s to %s\n (%s)'%(rel.target.name.upper(),rel.target.document.std_level.name,newstatus(rel),rel.target.document.title) for rel in doc.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS)],
|
||||
urls=[rel.target.document.get_absolute_url() for rel in doc.relateddocument_set.filter(relationship__slug__in=STATUSCHANGE_RELATIONS)],
|
||||
cc=cc
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Set notification list for {{ doc.name }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.edit-notify td input#id_notify { width: 40em; }
|
||||
form.edit-notify td.actions { padding-top: 1em; }
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% load ietf_filters %}
|
||||
<h1>Set notification list for {{ doc.name }}</h1>
|
||||
|
||||
<form class="edit-notify" action="" method="post">{% csrf_token %}
|
||||
<table>
|
||||
<tr>
|
||||
<th>{{ form.notify.label_tag }}</th>
|
||||
<td>{{ form.notify }}
|
||||
<div class="help">{{ form.notify.help_text }}</div>
|
||||
{{ form.notify.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url "doc_view" name=doc.name %}">Back</a>
|
||||
<input type="submit" value="Save"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -11,11 +11,11 @@ form.edit-info #id_notify {
|
|||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Edit notification addresses for {{ doc.canonical_name }}-{{ doc.rev }}
|
||||
Edit notification addresses for {{titletext}}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Edit notification addresses for {{ doc.canonical_name }}-{{ doc.rev }}</h1>
|
||||
<h1>Edit notification addresses for {{titletext}}</h1>
|
||||
|
||||
<form class="edit-info" action="" enctype="multipart/form-data" method="post">{% csrf_token %}
|
||||
<table>
|
|
@ -1,42 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block morecss %}
|
||||
form.edit-info #id_notify {
|
||||
width: 600px;
|
||||
}
|
||||
.warning {
|
||||
font-weight: bold;
|
||||
color: #a00;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Edit notification addresses for {{titletext}}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Edit notification addresses for {{titletext}}</h1>
|
||||
|
||||
<form class="edit-info" action="" enctype="multipart/form-data" method="post">{% csrf_token %}
|
||||
<table>
|
||||
{% for field in form.visible_fields %}
|
||||
<tr>
|
||||
<th>{{ field.label_tag }}</th>
|
||||
<td>
|
||||
{{ field }}
|
||||
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
|
||||
{{ field.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url "doc_view" name=doc.canonical_name %}">Back</a>
|
||||
<input type="submit" value="Submit"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -299,6 +299,7 @@ def make_test_data():
|
|||
def rfc_for_status_change_test_factory(name,rfc_num,std_level_id):
|
||||
target_rfc = Document.objects.create(name=name, type_id='draft', std_level_id=std_level_id)
|
||||
target_rfc.set_state(State.objects.get(slug='rfc',type__slug='draft'))
|
||||
target_rfc.notify = "%s@ietf.org"%name
|
||||
target_rfc.save()
|
||||
docalias = DocAlias.objects.create(name=name,document=target_rfc)
|
||||
docalias = DocAlias.objects.create(name='rfc%d'%rfc_num,document=target_rfc) # pyflakes:ignore
|
||||
|
|
Loading…
Reference in a new issue