Skip to content

Commit 920b2d2

Browse files
committed
Import IRTF groups, chairs and other roles, port notify-expirations script (and add test)
- Legacy-Id: 3068
1 parent 8762d77 commit 920b2d2

12 files changed

Lines changed: 301 additions & 90 deletions

File tree

ietf/bin/notify-expirations

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,56 +6,11 @@ from ietf import settings
66
from django.core import management
77
management.setup_environ(settings)
88

9-
from ietf.idtracker.models import InternetDraft,IDAuthor,WGChair
10-
from ietf.utils.mail import send_mail_subj
9+
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id
1110

12-
notify_days = 14 # notify about documents that expire within the
13-
# next 2 weeks
1411

15-
start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1)
16-
end_date = start_date + datetime.timedelta(notify_days - 1)
12+
# notify about documents that expire within the next 2 weeks
13+
notify_days = 14
1714

18-
19-
matches = InternetDraft.objects.filter(revision_date__gte=start_date,revision_date__lte=end_date,status__status='Active')
20-
21-
#For development - focus on one draft
22-
#matches = InternetDraft.objects.filter(filename__icontains='geopriv-http-location-delivery')
23-
24-
# Todo:
25-
#second_cutoff = IDDates.objects.get(date_id=2)
26-
#ietf_monday = IDDates.objects.get(date_id=3)
27-
#freeze_delta = ietf_monday - second_cutoff
28-
29-
for draft in matches:
30-
if not draft.can_expire():
31-
# debugging
32-
#print "%s can't expire, skipping" % draft
33-
continue
34-
expiration = draft.expiration()
35-
# # The I-D expiration job doesn't run while submissions are frozen.
36-
# if ietf_monday > expiration > second_cutoff:
37-
# expiration += freeze_delta
38-
authors = draft.authors.all()
39-
to_addrs = [author.email() for author in authors if author.email()]
40-
cc_addrs = None
41-
if draft.group.acronym != 'none':
42-
cc_addrs = [chair.person.email() for chair in WGChair.objects.filter(group_acronym=draft.group)]
43-
44-
#For development debugging
45-
"""
46-
print "filename: "+draft.filename
47-
print "to: ", to_addrs
48-
print "cc: ", cc_addrs
49-
print "expires: ", expiration
50-
print "status: ", draft.status.status, "/", draft.idstate()
51-
print
52-
continue
53-
"""
54-
55-
if to_addrs or cc_addrs:
56-
send_mail_subj(None, to_addrs, None, 'notify_expirations/subject.txt', 'notify_expirations/body.txt',
57-
{
58-
'draft':draft,
59-
'expiration':expiration,
60-
},
61-
cc_addrs)
15+
for doc in get_soon_to_expire_ids(notify_days):
16+
send_expire_warning_for_id(doc)

ietf/idrfc/expire.py

Lines changed: 81 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
import datetime, os, shutil, glob, re
88

9-
from ietf.idtracker.models import InternetDraft, IDDates, IDStatus, IDState, DocumentComment
10-
from ietf.utils.mail import send_mail
9+
from ietf.idtracker.models import InternetDraft, IDDates, IDStatus, IDState, DocumentComment, IDAuthor,WGChair
10+
from ietf.utils.mail import send_mail, send_mail_subj
1111
from ietf.idrfc.utils import log_state_changed, add_document_comment
1212
from doc.models import Document, Event, save_document_in_history
1313
from name.models import IesgDocStateName, DocStateName, DocInfoTagName
@@ -28,6 +28,33 @@ def in_id_expire_freeze(when=None):
2828

2929
return second_cut_off <= when < ietf_monday
3030

31+
def document_expires(doc):
32+
e = doc.latest_event(type__in=("completed_resurrect", "new_revision"))
33+
if e:
34+
return e.time + datetime.timedelta(days=INTERNET_DRAFT_DAYS_TO_EXPIRE)
35+
else:
36+
return None
37+
38+
def expirable_documents():
39+
return Document.objects.filter(state="active").exclude(tags="rfc-rev").filter(Q(iesg_state=None) | Q(iesg_state__order__gte=42))
40+
41+
def get_soon_to_expire_ids(days):
42+
start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1)
43+
end_date = start_date + datetime.timedelta(days - 1)
44+
45+
for d in InternetDraft.objects.filter(revision_date__gte=start_date,revision_date__lte=end_date,status__status='Active'):
46+
if d.can_expire():
47+
yield d
48+
49+
def get_soon_to_expire_idsREDESIGN(days):
50+
start_date = datetime.date.today() - datetime.timedelta(1)
51+
end_date = start_date + datetime.timedelta(days - 1)
52+
53+
for d in expirable_documents():
54+
e = document_expires(d)
55+
if e and start_date <= e.date() <= end_date:
56+
yield d
57+
3158
def get_expired_ids():
3259
cut_off = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE)
3360

@@ -38,14 +65,59 @@ def get_expired_ids():
3865
Q(idinternal=None) | Q(idinternal__cur_state__document_state_id__gte=42))
3966

4067
def get_expired_idsREDESIGN():
41-
cut_off = datetime.date.today() - datetime.timedelta(days=INTERNET_DRAFT_DAYS_TO_EXPIRE)
68+
today = datetime.date.today()
4269

43-
docs = Document.objects.filter(state="active").exclude(tags="rfc-rev").filter(Q(iesg_state=None) | Q(iesg_state__order__gte=42))
44-
for d in docs:
45-
e = d.latest_event(type="new_revision")
46-
if e and e.time.date() <= cut_off:
70+
for d in expirable_documents():
71+
e = document_expires(d)
72+
if e and e.time.date() <= today:
4773
yield d
4874

75+
def send_expire_warning_for_id(doc):
76+
expiration = doc.expiration()
77+
# Todo:
78+
#second_cutoff = IDDates.objects.get(date_id=2)
79+
#ietf_monday = IDDates.objects.get(date_id=3)
80+
#freeze_delta = ietf_monday - second_cutoff
81+
# # The I-D expiration job doesn't run while submissions are frozen.
82+
# if ietf_monday > expiration > second_cutoff:
83+
# expiration += freeze_delta
84+
85+
authors = doc.authors.all()
86+
to_addrs = [author.email() for author in authors if author.email()]
87+
cc_addrs = None
88+
if doc.group.acronym != 'none':
89+
cc_addrs = [chair.person.email() for chair in WGChair.objects.filter(group_acronym=doc.group)]
90+
91+
if to_addrs or cc_addrs:
92+
send_mail_subj(None, to_addrs, None, 'notify_expirations/subject.txt', 'notify_expirations/body.txt',
93+
{
94+
'draft':doc,
95+
'expiration':expiration,
96+
},
97+
cc_addrs)
98+
99+
def send_expire_warning_for_idREDESIGN(doc):
100+
expiration = document_expires(doc).date()
101+
102+
to = [e.formatted_email() for e in doc.authors.all() if not e.address.startswith("unknown-email")]
103+
cc = None
104+
if doc.group.type_id != "individ":
105+
cc = [e.formatted_email() for e in Email.objects.filter(role__group=doc.group, role__name="chair") if not e.address.startswith("unknown-email")]
106+
107+
state = doc.iesg_state.name if doc.iesg_state else "I-D Exists"
108+
109+
frm = None
110+
request = None
111+
if to or cc:
112+
send_mail(request, to, frm,
113+
u"Expiration impending: %s" % doc.file_tag(),
114+
"idrfc/expire_warning_email.txt",
115+
dict(doc=doc,
116+
state=state,
117+
expiration=expiration
118+
),
119+
cc=cc)
120+
49121
def send_expire_notice_for_id(doc):
50122
doc.dunn_sent_date = datetime.date.today()
51123
doc.save()
@@ -242,7 +314,9 @@ def move_file_to(subdir):
242314
move_file_to("unknown_ids")
243315

244316
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
317+
get_soon_to_expire_ids = get_soon_to_expire_idsREDESIGN
245318
get_expired_ids = get_expired_idsREDESIGN
319+
send_expire_warning_for_id = send_expire_warning_for_idREDESIGN
246320
send_expire_notice_for_id = send_expire_notice_for_idREDESIGN
247321
expire_id = expire_idREDESIGN
248322
clean_up_id_files = clean_up_id_filesREDESIGN

ietf/idrfc/fixtures/names.xml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,12 +446,30 @@
446446
</object>
447447
<object pk="ex-ad" model="name.rolename">
448448
<field type="CharField" name="name">Ex-Area Director</field>
449-
<field type="TextField" name="desc">In-active Area Director</field>
449+
<field type="TextField" name="desc">Inactive Area Director</field>
450450
<field type="BooleanField" name="used">1</field>
451451
<field type="IntegerField" name="order">0</field>
452452
</object>
453-
<object pk="wgeditor" model="name.rolename">
454-
<field type="CharField" name="name">Working Group Editor</field>
453+
<object pk="chair" model="name.rolename">
454+
<field type="CharField" name="name">Chair</field>
455+
<field type="TextField" name="desc"></field>
456+
<field type="BooleanField" name="used">1</field>
457+
<field type="IntegerField" name="order">0</field>
458+
</object>
459+
<object pk="editor" model="name.rolename">
460+
<field type="CharField" name="name">Editor</field>
461+
<field type="TextField" name="desc"></field>
462+
<field type="BooleanField" name="used">1</field>
463+
<field type="IntegerField" name="order">0</field>
464+
</object>
465+
<object pk="secr" model="name.rolename">
466+
<field type="CharField" name="name">Secretary</field>
467+
<field type="TextField" name="desc"></field>
468+
<field type="BooleanField" name="used">1</field>
469+
<field type="IntegerField" name="order">0</field>
470+
</object>
471+
<object pk="techadv" model="name.rolename">
472+
<field type="CharField" name="name">Tech Advisor</field>
455473
<field type="TextField" name="desc"></field>
456474
<field type="BooleanField" name="used">1</field>
457475
<field type="IntegerField" name="order">0</field>

ietf/idrfc/tests.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,34 @@ def test_in_id_expire_freeze(self):
774774
self.assertTrue(in_id_expire_freeze(datetime.datetime(2010, 7, 12, 10, 0)))
775775
self.assertTrue(in_id_expire_freeze(datetime.datetime(2010, 7, 25, 0, 0)))
776776
self.assertTrue(not in_id_expire_freeze(datetime.datetime(2010, 7, 26, 0, 0)))
777+
778+
def test_warn_expirable_ids(self):
779+
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id
780+
781+
# hack into almost expirable state
782+
draft = InternetDraft.objects.get(filename="draft-ietf-mipshop-pfmipv6")
783+
draft.status = IDStatus.objects.get(status="Active")
784+
draft.review_by_rfc_editor = 0
785+
draft.revision_date = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE - 7)
786+
draft.idinternal.cur_state_id = IDState.AD_WATCHING
787+
draft.idinternal.save()
788+
draft.save()
789+
790+
author = PersonOrOrgInfo.objects.all()[0]
791+
IDAuthor.objects.create(document=draft, person=author, author_order=1)
792+
EmailAddress.objects.create(person_or_org=author, type="I-D", priority=draft.pk, address="author@example.com")
793+
794+
# test query
795+
documents = list(get_soon_to_expire_ids(14))
796+
self.assertEquals(len(documents), 1)
797+
798+
# test send warning
799+
mailbox_before = len(mail_outbox)
800+
801+
send_expire_warning_for_id(documents[0])
802+
803+
self.assertEquals(len(mail_outbox), mailbox_before + 1)
804+
self.assertTrue("author@example.com" in str(mail_outbox[-1]))
777805

778806
def test_expire_ids(self):
779807
from ietf.idrfc.expire import get_expired_ids, send_expire_notice_for_id, expire_id

ietf/idrfc/testsREDESIGN.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ def make_test_data():
7474

7575
# persons
7676
Email.objects.get_or_create(address="(System)")
77-
77+
78+
# ad
7879
p = Person.objects.create(
7980
name="Aread Irector",
8081
ascii="Aread Irector",
@@ -137,6 +138,21 @@ def make_test_data():
137138
person=porg,
138139
)
139140

141+
# group chair
142+
p = Person.objects.create(
143+
name="WG Chair Man",
144+
ascii="WG Chair Man",
145+
)
146+
wgchair = Email.objects.create(
147+
address="wgchairman@ietf.org",
148+
person=p)
149+
Role.objects.create(
150+
name=RoleName.objects.get(slug="chair"),
151+
group=group,
152+
email=wgchair,
153+
)
154+
155+
# secretary
140156
p = Person.objects.create(
141157
name="Sec Retary",
142158
ascii="Sec Retary",
@@ -187,14 +203,20 @@ def make_test_data():
187203
name=draft.name,
188204
)
189205

206+
DocumentAuthor.objects.create(
207+
document=draft,
208+
author=Email.objects.get(address="aread@ietf.org"),
209+
order=1
210+
)
211+
190212
# draft has only one event
191213
Event.objects.create(
192214
type="started_iesg_process",
193215
by=ad,
194216
doc=draft,
195217
desc="Added draft",
196218
)
197-
219+
198220
# telechat dates
199221
t = datetime.date.today()
200222
dates = TelechatDates(date1=t,
@@ -1002,6 +1024,38 @@ def test_in_id_expire_freeze(self):
10021024
self.assertTrue(in_id_expire_freeze(datetime.datetime(2010, 7, 25, 0, 0)))
10031025
self.assertTrue(not in_id_expire_freeze(datetime.datetime(2010, 7, 26, 0, 0)))
10041026

1027+
def test_warn_expirable_ids(self):
1028+
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id, INTERNET_DRAFT_DAYS_TO_EXPIRE
1029+
1030+
draft = make_test_data()
1031+
1032+
self.assertEquals(len(list(get_soon_to_expire_ids(14))), 0)
1033+
1034+
# hack into expirable state
1035+
draft.iesg_state = None
1036+
draft.save()
1037+
1038+
NewRevisionEvent.objects.create(
1039+
type="new_revision",
1040+
by=Email.objects.get(address="aread@ietf.org"),
1041+
doc=draft,
1042+
desc="New revision",
1043+
time=datetime.datetime.now() - datetime.timedelta(days=INTERNET_DRAFT_DAYS_TO_EXPIRE - 7),
1044+
rev="01"
1045+
)
1046+
1047+
self.assertEquals(len(list(get_soon_to_expire_ids(14))), 1)
1048+
1049+
# test send warning
1050+
mailbox_before = len(mail_outbox)
1051+
1052+
send_expire_warning_for_id(draft)
1053+
1054+
print mail_outbox[-1]
1055+
self.assertEquals(len(mail_outbox), mailbox_before + 1)
1056+
self.assertTrue("aread@ietf.org" in str(mail_outbox[-1])) # author
1057+
self.assertTrue("wgchairman@ietf.org" in str(mail_outbox[-1]))
1058+
10051059
def test_expire_ids(self):
10061060
from ietf.idrfc.expire import get_expired_ids, send_expire_notice_for_id, expire_id, INTERNET_DRAFT_DAYS_TO_EXPIRE
10071061

ietf/idrfc/views_edit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ def get_initial_notify(doc):
441441
receivers.append(e.address)
442442
else:
443443
receivers.append("%s-chairs@%s" % (doc.group.acronym, settings.TOOLS_SERVER))
444-
for editor in Email.objects.filter(role__name="wgeditor", role__group=doc.group):
444+
for editor in Email.objects.filter(role__name="editor", role__group=doc.group):
445445
receivers.append(e.address)
446446

447447
receivers.append("%s@%s" % (doc.name, settings.TOOLS_SERVER))
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
The following draft will expire soon:
2+
3+
Name: {{ doc.name }}
4+
Title: {{ doc.title}}
5+
State: {{ state }}
6+
Expires: {{ expiration }} (in {{ expiration|timeuntil }})

ietf/utils/mail.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def send_mail_text(request, to, frm, subject, txt, cc=None, extra=None, toUser=N
128128
else:
129129
msg = MIMEText(txt)
130130

131-
send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=None, bcc=None)
131+
send_mail_mime(request, to, frm, subject, msg, cc, extra, toUser, bcc)
132132

133133
def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=None, bcc=None):
134134
"""Send MIME message with content already filled in."""
@@ -143,6 +143,7 @@ def send_mail_mime(request, to, frm, subject, msg, cc=None, extra=None, toUser=N
143143
msg['To'] = to
144144
if cc:
145145
msg['Cc'] = cc
146+
print cc
146147
msg['Subject'] = subject
147148
msg['X-Test-IDTracker'] = (settings.SERVER_MODE == 'production') and 'no' or 'yes'
148149
if extra:

redesign/doc/proxy.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ def idinternal(self):
209209
# reverse relationship
210210
@property
211211
def authors(self):
212-
from person.models import Person
213212
return IDAuthor.objects.filter(document=self)
214213

215214
# methods from InternetDraft

0 commit comments

Comments
 (0)