Skip to content

Commit d70fb9b

Browse files
committed
Delete dead code, rename id-something to draft-something, make the "is
this eligible for expiration" logic clearer - Legacy-Id: 5606
1 parent 619b1d8 commit d70fb9b

4 files changed

Lines changed: 91 additions & 251 deletions

File tree

ietf/bin/expire-ids

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ syslog.openlog(os.path.basename(__file__), syslog.LOG_PID, syslog.LOG_LOCAL0)
1111

1212
from ietf.idrfc.expire import *
1313

14-
if not in_id_expire_freeze():
15-
for doc in get_expired_ids():
16-
send_expire_notice_for_id(doc)
17-
expire_id(doc)
18-
syslog.syslog("Expired %s (id=%s)%s" % (doc.file_tag(), doc.pk, " in the ID Tracker" if doc.latest_event(type="started_iesg_process") else ""))
14+
if not in_draft_expire_freeze():
15+
for doc in get_expired_drafts():
16+
send_expire_notice_for_draft(doc)
17+
expire_draft(doc)
18+
syslog.syslog("Expired draft %s-%s" % (doc.name, doc.rev))
1919

20-
clean_up_id_files()
20+
syslog.syslog("Cleaning up draft files")
21+
clean_up_draft_files()

ietf/bin/notify-expirations

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

9-
from ietf.idrfc.expire import get_soon_to_expire_ids, send_expire_warning_for_id
9+
from ietf.idrfc.expire import get_soon_to_expire_drafts, send_expire_warning_for_draft
1010

1111

1212
# notify about documents that expire within the next 2 weeks
13-
notify_days = 14
13+
notify_days = 14
1414

15-
for doc in get_soon_to_expire_ids(notify_days):
16-
send_expire_warning_for_id(doc)
15+
for doc in get_soon_to_expire_drafts(notify_days):
16+
send_expire_warning_for_draft(doc)

ietf/idrfc/expire.py

Lines changed: 45 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -6,105 +6,64 @@
66

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

9-
from ietf.idtracker.models import InternetDraft, IDDates, IDStatus, IDState, DocumentComment, IDAuthor, WGChair
109
from ietf.utils.mail import send_mail, send_mail_subj
11-
from ietf.idrfc.utils import log_state_changed, add_document_comment
12-
from ietf.doc.models import Document, DocEvent, save_document_in_history, State
13-
from ietf.name.models import DocTagName
10+
from ietf.idrfc.utils import log_state_changed
11+
from ietf.doc.models import Document, DocEvent, State, save_document_in_history, IESG_SUBSTATE_TAGS
1412
from ietf.person.models import Person, Email
1513
from ietf.meeting.models import Meeting
1614

17-
def in_id_expire_freeze(when=None):
18-
if when == None:
19-
when = datetime.datetime.now()
20-
21-
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
22-
d = Meeting.get_second_cut_off()
23-
else:
24-
d = IDDates.objects.get(id=IDDates.SECOND_CUT_OFF).date
25-
# for some reason, the old Perl code started at 9 am
26-
second_cut_off = datetime.datetime.combine(d, datetime.time(9, 0))
27-
28-
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
29-
d = Meeting.get_ietf_monday()
30-
else:
31-
d = IDDates.objects.get(id=IDDates.IETF_MONDAY).date
32-
ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0))
33-
34-
return second_cut_off <= when < ietf_monday
35-
36-
def expirable_documents():
15+
def expirable_draft(draft):
16+
"""Return whether draft is in an expirable state or not. This is
17+
the single draft version of the logic in expirable_drafts. These
18+
two functions need to be kept in sync."""
19+
return (draft.expires and draft.get_state_slug() == "active"
20+
and draft.get_state_slug("draft-iesg") in (None, "watching", "dead")
21+
and draft.get_state_slug("draft-stream-%s" % draft.stream_id) not in ("rfc-edit", "pub")
22+
and not draft.tags.filter(slug="rfc-rev"))
23+
24+
def expirable_drafts():
25+
"""Return a queryset with expirable drafts."""
3726
# the general rule is that each active draft is expirable, unless
3827
# it's in a state where we shouldn't touch it
39-
40-
d = Document.objects.filter(states__type="draft", states__slug="active").exclude(tags="rfc-rev")
28+
d = Document.objects.filter(states__type="draft", states__slug="active").exclude(expires=None)
4129

4230
nonexpirable_states = []
4331
# all IESG states except AD Watching and Dead block expiry
4432
nonexpirable_states += list(State.objects.filter(type="draft-iesg").exclude(slug__in=("watching", "dead")))
45-
# Sent to RFC Editor and RFC Published block expiry (the latter
33+
# sent to RFC Editor and RFC Published block expiry (the latter
4634
# shouldn't be possible for an active draft, though)
4735
nonexpirable_states += list(State.objects.filter(type__in=("draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"), slug__in=("rfc-edit", "pub")))
4836

49-
return d.exclude(states__in=nonexpirable_states).distinct()
37+
d = d.exclude(states__in=nonexpirable_states)
5038

51-
def get_soon_to_expire_ids(days):
52-
start_date = datetime.date.today() - datetime.timedelta(InternetDraft.DAYS_TO_EXPIRE - 1)
53-
end_date = start_date + datetime.timedelta(days - 1)
54-
55-
for d in InternetDraft.objects.filter(revision_date__gte=start_date,revision_date__lte=end_date,status__status='Active'):
56-
if d.can_expire():
57-
yield d
39+
# under review by the RFC Editor blocks expiry
40+
d = d.exclude(tags="rfc-rev")
41+
42+
return d.distinct()
5843

59-
def get_soon_to_expire_idsREDESIGN(days):
44+
def get_soon_to_expire_drafts(days_of_warning):
6045
start_date = datetime.date.today() - datetime.timedelta(1)
61-
end_date = start_date + datetime.timedelta(days - 1)
46+
end_date = start_date + datetime.timedelta(days_of_warning)
47+
48+
return expirable_drafts().filter(expires__gte=start_date, expires__lt=end_date)
49+
50+
def get_expired_drafts():
51+
return expirable_drafts().filter(expires__lt=datetime.date.today() + datetime.timedelta(1))
52+
53+
def in_draft_expire_freeze(when=None):
54+
if when == None:
55+
when = datetime.datetime.now()
56+
57+
d = Meeting.get_second_cut_off()
58+
# for some reason, the old Perl code started at 9 am
59+
second_cut_off = datetime.datetime.combine(d, datetime.time(9, 0))
6260

63-
for d in expirable_documents():
64-
if d.expires and start_date <= d.expires.date() <= end_date:
65-
yield d
66-
67-
def get_expired_ids():
68-
cut_off = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE)
69-
70-
return InternetDraft.objects.filter(
71-
revision_date__lte=cut_off,
72-
status__status="Active",
73-
review_by_rfc_editor=0).filter(
74-
Q(idinternal=None) | Q(idinternal__cur_state__document_state_id__gte=42))
75-
76-
def get_expired_idsREDESIGN():
77-
today = datetime.date.today()
78-
79-
for d in expirable_documents():
80-
if d.expires and d.expires.date() <= today:
81-
yield d
82-
83-
def send_expire_warning_for_id(doc):
84-
expiration = doc.expiration()
85-
# Todo:
86-
#second_cutoff = IDDates.objects.get(date_id=2)
87-
#ietf_monday = IDDates.objects.get(date_id=3)
88-
#freeze_delta = ietf_monday - second_cutoff
89-
# # The I-D expiration job doesn't run while submissions are frozen.
90-
# if ietf_monday > expiration > second_cutoff:
91-
# expiration += freeze_delta
61+
d = Meeting.get_ietf_monday()
62+
ietf_monday = datetime.datetime.combine(d, datetime.time(0, 0))
9263

93-
authors = doc.authors.all()
94-
to_addrs = [author.email() for author in authors if author.email()]
95-
cc_addrs = None
96-
if doc.group.acronym != 'none':
97-
cc_addrs = [chair.person.email() for chair in WGChair.objects.filter(group_acronym=doc.group)]
98-
99-
if to_addrs or cc_addrs:
100-
send_mail_subj(None, to_addrs, None, 'notify_expirations/subject.txt', 'notify_expirations/body.txt',
101-
{
102-
'draft':doc,
103-
'expiration':expiration,
104-
},
105-
cc_addrs)
106-
107-
def send_expire_warning_for_idREDESIGN(doc):
64+
return second_cut_off <= when < ietf_monday
65+
66+
def send_expire_warning_for_draft(doc):
10867
if doc.get_state_slug("draft-iesg") == "dead":
10968
return # don't warn about dead documents
11069

@@ -130,23 +89,7 @@ def send_expire_warning_for_idREDESIGN(doc):
13089
),
13190
cc=cc)
13291

133-
def send_expire_notice_for_id(doc):
134-
doc.dunn_sent_date = datetime.date.today()
135-
doc.save()
136-
137-
if not doc.idinternal:
138-
return
139-
140-
request = None
141-
to = u"%s <%s>" % doc.idinternal.job_owner.person.email()
142-
send_mail(request, to,
143-
"I-D Expiring System <ietf-secretariat-reply@ietf.org>",
144-
u"I-D was expired %s" % doc.file_tag(),
145-
"idrfc/id_expired_email.txt",
146-
dict(doc=doc,
147-
state=doc.idstate()))
148-
149-
def send_expire_notice_for_idREDESIGN(doc):
92+
def send_expire_notice_for_draft(doc):
15093
if not doc.ad or doc.get_state_slug("draft-iesg") == "dead":
15194
return
15295

@@ -163,42 +106,6 @@ def send_expire_notice_for_idREDESIGN(doc):
163106
state=state,
164107
))
165108

166-
def expire_id(doc):
167-
def move_file(f):
168-
src = os.path.join(settings.INTERNET_DRAFT_PATH, f)
169-
dst = os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR, f)
170-
171-
if os.path.exists(src):
172-
shutil.move(src, dst)
173-
174-
move_file("%s-%s.txt" % (doc.filename, doc.revision_display()))
175-
move_file("%s-%s.txt.p7s" % (doc.filename, doc.revision_display()))
176-
move_file("%s-%s.ps" % (doc.filename, doc.revision_display()))
177-
move_file("%s-%s.pdf" % (doc.filename, doc.revision_display()))
178-
179-
new_revision = "%02d" % (int(doc.revision) + 1)
180-
181-
new_file = open(os.path.join(settings.INTERNET_DRAFT_PATH, "%s-%s.txt" % (doc.filename, new_revision)), 'w')
182-
txt = render_to_string("idrfc/expire_text.txt",
183-
dict(doc=doc,
184-
authors=[a.person.email() for a in doc.authors.all()],
185-
expire_days=InternetDraft.DAYS_TO_EXPIRE))
186-
new_file.write(txt)
187-
new_file.close()
188-
189-
doc.revision = new_revision
190-
doc.expiration_date = datetime.date.today()
191-
doc.last_modified_date = datetime.date.today()
192-
doc.status = IDStatus.objects.get(status="Expired")
193-
doc.save()
194-
195-
if doc.idinternal:
196-
if doc.idinternal.cur_state_id != IDState.DEAD:
197-
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.DEAD), None)
198-
log_state_changed(None, doc, "system")
199-
200-
add_document_comment(None, doc, "Document is expired by system")
201-
202109
def move_draft_files_to_archive(doc, rev):
203110
def move_file(f):
204111
src = os.path.join(settings.INTERNET_DRAFT_PATH, f)
@@ -211,7 +118,7 @@ def move_file(f):
211118
for t in file_types:
212119
move_file("%s-%s.%s" % (doc.name, rev, t))
213120

214-
def expire_idREDESIGN(doc):
121+
def expire_draft(doc):
215122
# clean up files
216123
move_draft_files_to_archive(doc, doc.rev)
217124

@@ -222,7 +129,7 @@ def expire_idREDESIGN(doc):
222129
if doc.latest_event(type='started_iesg_process'):
223130
dead_state = State.objects.get(type="draft-iesg", slug="dead")
224131
prev = doc.get_state("draft-iesg")
225-
prev_tag = doc.tags.filter(slug__in=('point', 'ad-f-up', 'need-rev', 'extpty'))
132+
prev_tag = doc.tags.filter(slug__in=IESG_SUBSTATE_TAGS)
226133
prev_tag = prev_tag[0] if prev_tag else None
227134
if prev != dead_state:
228135
doc.set_state(dead_state)
@@ -239,67 +146,7 @@ def expire_idREDESIGN(doc):
239146
doc.time = datetime.datetime.now()
240147
doc.save()
241148

242-
def clean_up_id_files():
243-
"""Move unidentified and old files out of the Internet Draft directory."""
244-
cut_off = datetime.date.today() - datetime.timedelta(days=InternetDraft.DAYS_TO_EXPIRE)
245-
246-
pattern = os.path.join(settings.INTERNET_DRAFT_PATH, "draft-*.*")
247-
files = []
248-
filename_re = re.compile('^(.*)-(\d\d)$')
249-
250-
def splitext(fn):
251-
"""
252-
Split the pathname path into a pair (root, ext) such that root + ext
253-
== path, and ext is empty or begins with a period and contains all
254-
periods in the last path component.
255-
256-
This differs from os.path.splitext in the number of periods in the ext
257-
parts when the final path component containt more than one period.
258-
"""
259-
s = fn.rfind("/")
260-
if s == -1:
261-
s = 0
262-
i = fn[s:].find(".")
263-
if i == -1:
264-
return fn, ''
265-
else:
266-
return fn[:s+i], fn[s+i:]
267-
268-
for path in glob.glob(pattern):
269-
basename = os.path.basename(path)
270-
stem, ext = splitext(basename)
271-
match = filename_re.search(stem)
272-
if not match:
273-
filename, revision = ("UNKNOWN", "00")
274-
else:
275-
filename, revision = match.groups()
276-
277-
def move_file_to(subdir):
278-
shutil.move(path,
279-
os.path.join(settings.INTERNET_DRAFT_ARCHIVE_DIR, subdir, basename))
280-
281-
try:
282-
doc = InternetDraft.objects.get(filename=filename, revision=revision)
283-
284-
if doc.status_id == 3: # RFC
285-
if ext != ".txt":
286-
move_file_to("unknown_ids")
287-
elif doc.status_id in (2, 4, 5, 6) and doc.expiration_date and doc.expiration_date < cut_off:
288-
# Expired, Withdrawn by Auth, Replaced, Withdrawn by IETF,
289-
# and expired more than DAYS_TO_EXPIRE ago
290-
if os.path.getsize(path) < 1500:
291-
move_file_to("deleted_tombstones")
292-
# revert version after having deleted tombstone
293-
doc.revision = "%02d" % (int(revision) - 1)
294-
doc.expired_tombstone = True
295-
doc.save()
296-
else:
297-
move_file_to("expired_without_tombstone")
298-
299-
except InternetDraft.DoesNotExist:
300-
move_file_to("unknown_ids")
301-
302-
def clean_up_id_filesREDESIGN():
149+
def clean_up_draft_files():
303150
"""Move unidentified and old files out of the Internet Draft directory."""
304151
cut_off = datetime.date.today()
305152

@@ -314,7 +161,7 @@ def splitext(fn):
314161
periods in the last path component.
315162
316163
This differs from os.path.splitext in the number of periods in the ext
317-
parts when the final path component containt more than one period.
164+
parts when the final path component contains more than one period.
318165
"""
319166
s = fn.rfind("/")
320167
if s == -1:
@@ -357,11 +204,3 @@ def move_file_to(subdir):
357204

358205
except Document.DoesNotExist:
359206
move_file_to("unknown_ids")
360-
361-
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
362-
get_soon_to_expire_ids = get_soon_to_expire_idsREDESIGN
363-
get_expired_ids = get_expired_idsREDESIGN
364-
send_expire_warning_for_id = send_expire_warning_for_idREDESIGN
365-
send_expire_notice_for_id = send_expire_notice_for_idREDESIGN
366-
expire_id = expire_idREDESIGN
367-
clean_up_id_files = clean_up_id_filesREDESIGN

0 commit comments

Comments
 (0)