Skip to content

Commit 1654c1a

Browse files
committed
First cut at a scrubber for the notify field
- Legacy-Id: 10069
1 parent e5306ed commit 1654c1a

1 file changed

Lines changed: 160 additions & 0 deletions

File tree

2015-08-28-scrub-notify.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env python
2+
3+
import os, sys, re
4+
5+
from copy import copy
6+
7+
# boilerplate
8+
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../web/"))
9+
sys.path = [ basedir ] + sys.path
10+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ietf.settings")
11+
12+
import django
13+
14+
django.setup()
15+
16+
from django.db.models import F
17+
from django.template import Template,Context
18+
from ietf.doc.models import Document, DocEvent
19+
from ietf.person.models import Person
20+
from ietf.utils.mail import send_mail_text
21+
22+
def message_body_template():
23+
return Template("""{% filter wordwrap:72 %}The Notify field for the document{{ count|pluralize }} listed at the end of this message {% if count > 1 %}were{% else %}was{% endif %} changed by removing the chair, shepherd, author, and similar addresses (in direct or alias form) to the point they could be identified.
24+
25+
The Datatracker now includes those addresses explicitly in each message it sends as appropriate. You can review where the datatracker sends messages for a given action in general using <https://datatracker.ietf.org/mailtoken/token>. You can review the expansions for a specific document by the new Email expansions tab on the document's page. Note that the addresses included for any given action are much more comprehensive than they were before this release.
26+
27+
Please review each new Notify field, and help remove any remaining addresses that will normally be copied per the configuration shown at https://datatracker.ietf.org/mailtoken/token. The field should now only contain exceptional addresses - parties you wish to be notified that aren't part of the new normal recipient set.
28+
29+
You can see exactly how the Notify field was changed for a given document by looking in the document's history.{% endfilter %}
30+
31+
{% if non_empty%}The document{{non_empty|length|pluralize }} with non-empty new Notify fields are:{% for doc in non_empty %}
32+
https://datatracker.ietf.org{{doc.get_absolute_url}}{% endfor %}{% endif %}
33+
34+
{% if empty%}The document{{non_empty|length|pluralize }} with empty new Notify fields are:{% for doc in empty %}
35+
https://datatracker.ietf.org{{doc.get_absolute_url}}{% endfor %}{% endif %}
36+
37+
""")
38+
39+
def other_addrs(addr):
40+
person = Person.objects.filter(email__address__iexact=addr).first()
41+
if not person:
42+
return None
43+
return [x.lower() for x in person.email_set.values_list('address',flat=True)]
44+
45+
def prep(item):
46+
retval = item.lower()
47+
if '<' in retval:
48+
if not '>' in retval:
49+
raise "Bad item: "+item
50+
start=retval.index('<')+1
51+
stop=retval.index('>')
52+
retval = retval[start:stop]
53+
return retval
54+
55+
def is_management(item, doc):
56+
57+
item = prep(item)
58+
59+
if any([
60+
item == '%s.chairs@ietf.org'%doc.name,
61+
item == '%s.ad@ietf.org'%doc.name,
62+
item == '%s.shepherd@ietf.org'%doc.name,
63+
item == '%s.chairs@tools.ietf.org'%doc.name,
64+
item == '%s.ad@tools.ietf.org'%doc.name,
65+
item == '%s.shepherd@tools.ietf.org'%doc.name,
66+
doc.ad and item == doc.ad.email_address().lower(),
67+
doc.shepherd and item == doc.shepherd.address.lower(),
68+
]):
69+
return True
70+
71+
if doc.group:
72+
if any([
73+
item == '%s-chairs@ietf.org'%doc.group.acronym,
74+
item == '%s-ads@ietf.org'%doc.group.acronym,
75+
item == '%s-chairs@tools.ietf.org'%doc.group.acronym,
76+
item == '%s-ads@tools.ietf.org'%doc.group.acronym,
77+
]):
78+
return True
79+
for addr in doc.group.role_set.filter(name__in=['chair','ad','delegate']).values_list('email__address',flat=True):
80+
other = other_addrs(addr)
81+
if item == addr.lower() or item in other:
82+
return True
83+
if doc.group.parent:
84+
if item == '%s-ads@ietf.org'%doc.group.parent.acronym or item == '%s-ads@tools.ietf.org'%doc.group.parent.acronym:
85+
return True
86+
87+
return False
88+
89+
def is_author(item, doc):
90+
item = prep(item)
91+
92+
if item == '%s@ietf.org' % doc.name or item == '%s@tools.ietf.org' % doc.name:
93+
return True
94+
95+
for addr in doc.authors.values_list('address',flat=True):
96+
other = other_addrs(addr)
97+
if item == addr.lower() or item in other:
98+
return True
99+
100+
return False
101+
102+
msg_template = message_body_template()
103+
by = Person.objects.get(name="(System)")
104+
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active", role__group__type="area"))
105+
106+
affected = set()
107+
empty = dict()
108+
non_empty = dict()
109+
changed = 0
110+
emptied = 0
111+
112+
qs = Document.objects.exclude(notify__isnull=True).exclude(notify='')
113+
for doc in qs:
114+
doc.notify = doc.notify.replace(';', ',')
115+
items = set([ i.strip() for i in doc.notify.split(',') if i.strip() and '@' in i])
116+
original_items = copy(items)
117+
for item in original_items:
118+
if any([
119+
doc.group and doc.group.list_email and item.lower() == doc.group.list_email.lower(),
120+
is_management(item,doc),
121+
is_author(item,doc),
122+
]):
123+
items.discard(item)
124+
if original_items != items:
125+
changed += 1
126+
if len(list(items))==0:
127+
emptied += 1
128+
129+
to = []
130+
if doc.ad and doc.ad in active_ads:
131+
to.append(doc.ad.email_address())
132+
if doc.group and doc.group.state_id=='active':
133+
to.extend(doc.group.role_set.filter(name__in=['chair','ad']).values_list('email__address',flat=True))
134+
if not to:
135+
to = ['iesg@ietf.org']
136+
137+
to = ", ".join(sorted(to))
138+
affected.add(to)
139+
empty.setdefault(to,[])
140+
non_empty.setdefault(to,[])
141+
if len(list(items))==0:
142+
empty[to].append(doc)
143+
else:
144+
non_empty[to].append(doc)
145+
original_notify = doc.notify
146+
new_notify = ', '.join(list(items))
147+
doc.notify = new_notify
148+
doc.save()
149+
e = DocEvent(type="added_comment",doc=doc,time=doc.time,by=by)
150+
e.desc = "Notify list changed from %s to %s"% (original_notify, new_notify if new_notify else '(None)')
151+
e.save()
152+
153+
for a in list(affected):
154+
155+
txt = msg_template.render(Context({'count':len(empty[a])+len(non_empty[a]),'empty':empty[a],'non_empty':non_empty[a]}))
156+
send_mail_text(None, to=a, frm=None, subject='Document Notify fields changed to match new Datatracker addressing defaults',txt =txt)
157+
158+
print "Changed",changed,"documents.",emptied,"of those had their notify field emptied"
159+
print "Sent email to ",len(affected),"different sets of addresses"
160+

0 commit comments

Comments
 (0)