datatracker/ietf/doc/management/commands/generate_draft_aliases.py

183 lines
7.2 KiB
Python
Executable file

# Copyright The IETF Trust 2012-2021, All Rights Reserved
# -*- coding: utf-8 -*-
# This was written as a script by Markus Stenberg <markus.stenberg@iki.fi>.
# It was turned into a management command by Russ Housley <housley@vigisec.com>.
import datetime
import io
import os
import re
import shutil
import stat
import time
from tempfile import mkstemp
from django.conf import settings
from django.core.management.base import BaseCommand
from django.utils import timezone
import debug # pyflakes:ignore
from ietf.doc.models import Document
from ietf.group.utils import get_group_role_emails, get_group_ad_emails
from ietf.utils.aliases import dump_sublist
from utils.mail import parseaddr
from ietf.utils import log
DEFAULT_YEARS = 2
def get_draft_ad_emails(doc):
"""Get AD email addresses for the given draft, if any."""
ad_emails = set()
# If working group document, return current WG ADs
if doc.group and doc.group.acronym != 'none':
ad_emails.update(get_group_ad_emails(doc.group))
# Document may have an explicit AD set
if doc.ad:
ad_emails.add(doc.ad.email_address())
return ad_emails
def get_draft_chair_emails(doc):
"""Get chair email addresses for the given draft, if any."""
chair_emails = set()
if doc.group:
chair_emails.update(get_group_role_emails(doc.group, ['chair', 'secr']))
return chair_emails
def get_draft_shepherd_email(doc):
"""Get shepherd email addresses for the given draft, if any."""
shepherd_email = set()
if doc.shepherd:
shepherd_email.add(doc.shepherd.email_address())
return shepherd_email
def get_draft_authors_emails(doc):
"""Get list of authors for the given draft."""
author_emails = set()
for author in doc.documentauthor_set.all():
if author.email and author.email.email_address():
author_emails.add(author.email.email_address())
return author_emails
def get_draft_notify_emails(doc):
"""Get list of email addresses to notify for the given draft."""
ad_email_alias_regex = r"^%s.ad@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER)
all_email_alias_regex = r"^%s.all@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER)
author_email_alias_regex = r"^%s@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER)
notify_email_alias_regex = r"^%s.notify@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER)
shepherd_email_alias_regex = r"^%s.shepherd@(%s|%s)$" % (doc.name, settings.DRAFT_ALIAS_DOMAIN, settings.TOOLS_SERVER)
notify_emails = set()
if doc.notify:
for e in doc.notify.split(','):
e = e.strip()
if re.search(ad_email_alias_regex, e):
notify_emails.update(get_draft_ad_emails(doc))
elif re.search(author_email_alias_regex, e):
notify_emails.update(get_draft_authors_emails(doc))
elif re.search(shepherd_email_alias_regex, e):
notify_emails.update(get_draft_shepherd_email(doc))
elif re.search(all_email_alias_regex, e):
notify_emails.update(get_draft_ad_emails(doc))
notify_emails.update(get_draft_authors_emails(doc))
notify_emails.update(get_draft_shepherd_email(doc))
elif re.search(notify_email_alias_regex, e):
pass
else:
(name, email) = parseaddr(e)
notify_emails.add(email)
return notify_emails
class Command(BaseCommand):
help = ('Generate the draft-aliases and draft-virtual files for Internet-Draft '
'mail aliases, placing them in the files configured in '
'settings.DRAFT_ALIASES_PATH and settings.DRAFT_VIRTUAL_PATH, '
'respectively. The generation includes aliases for Internet-Drafts '
'that have seen activity in the last %s years.' % (DEFAULT_YEARS))
def handle(self, *args, **options):
show_since = timezone.now() - datetime.timedelta(DEFAULT_YEARS*365)
date = time.strftime("%Y-%m-%d_%H:%M:%S")
signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date)
ahandle, aname = mkstemp()
os.close(ahandle)
afile = io.open(aname,"w")
vhandle, vname = mkstemp()
os.close(vhandle)
vfile = io.open(vname,"w")
afile.write(signature)
vfile.write(signature)
vfile.write("%s anything\n" % settings.DRAFT_VIRTUAL_DOMAIN)
# Internet-Drafts with active status or expired within DEFAULT_YEARS
drafts = Document.objects.filter(type_id="draft")
active_drafts = drafts.filter(states__slug='active')
inactive_recent_drafts = drafts.exclude(states__slug='active').filter(expires__gte=show_since)
interesting_drafts = active_drafts | inactive_recent_drafts
alias_domains = ['ietf.org', ]
for draft in interesting_drafts.distinct().iterator():
# Omit drafts that became RFCs, unless they were published in the last DEFAULT_YEARS
if draft.get_state_slug()=="rfc":
rfc = draft.became_rfc()
log.assertion("rfc is not None")
if rfc.latest_event(type='published_rfc').time < show_since:
continue
alias = draft.name
all = set()
# no suffix and .authors are the same list
emails = get_draft_authors_emails(draft)
all.update(emails)
dump_sublist(afile, vfile, alias, alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
dump_sublist(afile, vfile, alias+'.authors', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
# .chairs = group chairs
emails = get_draft_chair_emails(draft)
if emails:
all.update(emails)
dump_sublist(afile, vfile, alias+'.chairs', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
# .ad = sponsoring AD / WG AD (WG document)
emails = get_draft_ad_emails(draft)
if emails:
all.update(emails)
dump_sublist(afile, vfile, alias+'.ad', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
# .notify = notify email list from the Document
emails = get_draft_notify_emails(draft)
if emails:
all.update(emails)
dump_sublist(afile, vfile, alias+'.notify', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
# .shepherd = shepherd email from the Document
emails = get_draft_shepherd_email(draft)
if emails:
all.update(emails)
dump_sublist(afile, vfile, alias+'.shepherd', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, emails)
# .all = everything from above
dump_sublist(afile, vfile, alias+'.all', alias_domains, settings.DRAFT_VIRTUAL_DOMAIN, all)
afile.close()
vfile.close()
os.chmod(aname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
os.chmod(vname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
shutil.move(aname, settings.DRAFT_ALIASES_PATH)
shutil.move(vname, settings.DRAFT_VIRTUAL_PATH)