chore: Drop alias generation mgmt commands (#7082)
* chore: Remove generate_draft_aliases.py Also remove test and update some now-stale help strings. These are not very helpful, but will not exist for long in their updated incarnation. * chore: Remove generate_group_aliases.py ... and its test. * chore: Remove unused import * chore: Remove unused import
This commit is contained in:
parent
10cd14f174
commit
c696a715c0
|
@ -42,14 +42,14 @@ def check_group_email_aliases_exists(app_configs, **kwargs):
|
||||||
if not ok:
|
if not ok:
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"Found no aliases in the group email aliases file\n'%s'."%settings.GROUP_ALIASES_PATH,
|
"Found no aliases in the group email aliases file\n'%s'."%settings.GROUP_ALIASES_PATH,
|
||||||
hint="Please run the generate_group_aliases management command to generate them.",
|
hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.",
|
||||||
obj=None,
|
obj=None,
|
||||||
id="datatracker.E0002",
|
id="datatracker.E0002",
|
||||||
))
|
))
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"Could not read group email aliases:\n %s" % e,
|
"Could not read group email aliases:\n %s" % e,
|
||||||
hint="Please run the generate_group_aliases management command to generate them.",
|
hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.",
|
||||||
obj=None,
|
obj=None,
|
||||||
id="datatracker.E0003",
|
id="datatracker.E0003",
|
||||||
))
|
))
|
||||||
|
@ -69,14 +69,14 @@ def check_doc_email_aliases_exists(app_configs, **kwargs):
|
||||||
if not ok:
|
if not ok:
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"Found no aliases in the document email aliases file\n'%s'."%settings.DRAFT_VIRTUAL_PATH,
|
"Found no aliases in the document email aliases file\n'%s'."%settings.DRAFT_VIRTUAL_PATH,
|
||||||
hint="Please run the generate_draft_aliases management command to generate them.",
|
hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.",
|
||||||
obj=None,
|
obj=None,
|
||||||
id="datatracker.E0004",
|
id="datatracker.E0004",
|
||||||
))
|
))
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"Could not read document email aliases:\n %s" % e,
|
"Could not read document email aliases:\n %s" % e,
|
||||||
hint="Please run the generate_draft_aliases management command to generate them.",
|
hint="These should be created by the infrastructure using ietf/bin/aliases-from-json.py.",
|
||||||
obj=None,
|
obj=None,
|
||||||
id="datatracker.E0005",
|
id="datatracker.E0005",
|
||||||
))
|
))
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
# 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)
|
|
||||||
|
|
||||||
|
|
|
@ -2181,152 +2181,6 @@ class GenerateDraftAliasesTests(TestCase):
|
||||||
os.unlink(self.doc_virtual_file.name)
|
os.unlink(self.doc_virtual_file.name)
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
def testManagementCommand(self):
|
|
||||||
a_month_ago = (timezone.now() - datetime.timedelta(30)).astimezone(RPC_TZINFO)
|
|
||||||
a_month_ago = a_month_ago.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
||||||
ad = RoleFactory(
|
|
||||||
name_id="ad", group__type_id="area", group__state_id="active"
|
|
||||||
).person
|
|
||||||
shepherd = PersonFactory()
|
|
||||||
author1 = PersonFactory()
|
|
||||||
author2 = PersonFactory()
|
|
||||||
author3 = PersonFactory()
|
|
||||||
author4 = PersonFactory()
|
|
||||||
author5 = PersonFactory()
|
|
||||||
author6 = PersonFactory()
|
|
||||||
mars = GroupFactory(type_id="wg", acronym="mars")
|
|
||||||
marschairman = PersonFactory(user__username="marschairman")
|
|
||||||
mars.role_set.create(
|
|
||||||
name_id="chair", person=marschairman, email=marschairman.email()
|
|
||||||
)
|
|
||||||
doc1 = IndividualDraftFactory(
|
|
||||||
authors=[author1], shepherd=shepherd.email(), ad=ad
|
|
||||||
)
|
|
||||||
doc2 = WgDraftFactory(
|
|
||||||
name="draft-ietf-mars-test", group__acronym="mars", authors=[author2], ad=ad
|
|
||||||
)
|
|
||||||
doc3 = WgDraftFactory.create(
|
|
||||||
name="draft-ietf-mars-finished",
|
|
||||||
group__acronym="mars",
|
|
||||||
authors=[author3],
|
|
||||||
ad=ad,
|
|
||||||
std_level_id="ps",
|
|
||||||
states=[("draft", "rfc"), ("draft-iesg", "pub")],
|
|
||||||
time=a_month_ago,
|
|
||||||
)
|
|
||||||
rfc3 = WgRfcFactory()
|
|
||||||
DocEventFactory.create(doc=rfc3, type="published_rfc", time=a_month_ago)
|
|
||||||
doc3.relateddocument_set.create(
|
|
||||||
relationship_id="became_rfc", target=rfc3
|
|
||||||
)
|
|
||||||
doc4 = WgDraftFactory.create(
|
|
||||||
authors=[author4, author5],
|
|
||||||
ad=ad,
|
|
||||||
std_level_id="ps",
|
|
||||||
states=[("draft", "rfc"), ("draft-iesg", "pub")],
|
|
||||||
time=datetime.datetime(2010, 10, 10, tzinfo=ZoneInfo(settings.TIME_ZONE)),
|
|
||||||
)
|
|
||||||
rfc4 = WgRfcFactory()
|
|
||||||
DocEventFactory.create(
|
|
||||||
doc=rfc4,
|
|
||||||
type="published_rfc",
|
|
||||||
time=datetime.datetime(2010, 10, 10, tzinfo=RPC_TZINFO),
|
|
||||||
)
|
|
||||||
doc4.relateddocument_set.create(
|
|
||||||
relationship_id="became_rfc", target=rfc4
|
|
||||||
)
|
|
||||||
doc5 = IndividualDraftFactory(authors=[author6])
|
|
||||||
|
|
||||||
args = []
|
|
||||||
kwargs = {}
|
|
||||||
out = io.StringIO()
|
|
||||||
call_command("generate_draft_aliases", *args, **kwargs, stdout=out, stderr=out)
|
|
||||||
self.assertFalse(out.getvalue())
|
|
||||||
|
|
||||||
with open(settings.DRAFT_ALIASES_PATH) as afile:
|
|
||||||
acontent = afile.read()
|
|
||||||
for x in [
|
|
||||||
"xfilter-" + doc1.name,
|
|
||||||
"xfilter-" + doc1.name + ".ad",
|
|
||||||
"xfilter-" + doc1.name + ".authors",
|
|
||||||
"xfilter-" + doc1.name + ".shepherd",
|
|
||||||
"xfilter-" + doc1.name + ".all",
|
|
||||||
"xfilter-" + doc2.name,
|
|
||||||
"xfilter-" + doc2.name + ".ad",
|
|
||||||
"xfilter-" + doc2.name + ".authors",
|
|
||||||
"xfilter-" + doc2.name + ".chairs",
|
|
||||||
"xfilter-" + doc2.name + ".all",
|
|
||||||
"xfilter-" + doc3.name,
|
|
||||||
"xfilter-" + doc3.name + ".ad",
|
|
||||||
"xfilter-" + doc3.name + ".authors",
|
|
||||||
"xfilter-" + doc3.name + ".chairs",
|
|
||||||
"xfilter-" + doc5.name,
|
|
||||||
"xfilter-" + doc5.name + ".authors",
|
|
||||||
"xfilter-" + doc5.name + ".all",
|
|
||||||
]:
|
|
||||||
self.assertIn(x, acontent)
|
|
||||||
|
|
||||||
for x in [
|
|
||||||
"xfilter-" + doc1.name + ".chairs",
|
|
||||||
"xfilter-" + doc2.name + ".shepherd",
|
|
||||||
"xfilter-" + doc3.name + ".shepherd",
|
|
||||||
"xfilter-" + doc4.name,
|
|
||||||
"xfilter-" + doc5.name + ".shepherd",
|
|
||||||
"xfilter-" + doc5.name + ".ad",
|
|
||||||
]:
|
|
||||||
self.assertNotIn(x, acontent)
|
|
||||||
|
|
||||||
with open(settings.DRAFT_VIRTUAL_PATH) as vfile:
|
|
||||||
vcontent = vfile.read()
|
|
||||||
for x in [
|
|
||||||
ad.email_address(),
|
|
||||||
shepherd.email_address(),
|
|
||||||
marschairman.email_address(),
|
|
||||||
author1.email_address(),
|
|
||||||
author2.email_address(),
|
|
||||||
author3.email_address(),
|
|
||||||
author6.email_address(),
|
|
||||||
]:
|
|
||||||
self.assertIn(x, vcontent)
|
|
||||||
|
|
||||||
for x in [
|
|
||||||
author4.email_address(),
|
|
||||||
author5.email_address(),
|
|
||||||
]:
|
|
||||||
self.assertNotIn(x, vcontent)
|
|
||||||
|
|
||||||
for x in [
|
|
||||||
"xfilter-" + doc1.name,
|
|
||||||
"xfilter-" + doc1.name + ".ad",
|
|
||||||
"xfilter-" + doc1.name + ".authors",
|
|
||||||
"xfilter-" + doc1.name + ".shepherd",
|
|
||||||
"xfilter-" + doc1.name + ".all",
|
|
||||||
"xfilter-" + doc2.name,
|
|
||||||
"xfilter-" + doc2.name + ".ad",
|
|
||||||
"xfilter-" + doc2.name + ".authors",
|
|
||||||
"xfilter-" + doc2.name + ".chairs",
|
|
||||||
"xfilter-" + doc2.name + ".all",
|
|
||||||
"xfilter-" + doc3.name,
|
|
||||||
"xfilter-" + doc3.name + ".ad",
|
|
||||||
"xfilter-" + doc3.name + ".authors",
|
|
||||||
"xfilter-" + doc3.name + ".chairs",
|
|
||||||
"xfilter-" + doc3.name + ".all",
|
|
||||||
"xfilter-" + doc5.name,
|
|
||||||
"xfilter-" + doc5.name + ".authors",
|
|
||||||
"xfilter-" + doc5.name + ".all",
|
|
||||||
]:
|
|
||||||
self.assertIn(x, vcontent)
|
|
||||||
|
|
||||||
for x in [
|
|
||||||
"xfilter-" + doc1.name + ".chairs",
|
|
||||||
"xfilter-" + doc2.name + ".shepherd",
|
|
||||||
"xfilter-" + doc3.name + ".shepherd",
|
|
||||||
"xfilter-" + doc4.name,
|
|
||||||
"xfilter-" + doc5.name + ".shepherd",
|
|
||||||
"xfilter-" + doc5.name + ".ad",
|
|
||||||
]:
|
|
||||||
self.assertNotIn(x, vcontent)
|
|
||||||
|
|
||||||
@override_settings(TOOLS_SERVER="tools.example.org", DRAFT_ALIAS_DOMAIN="draft.example.org")
|
@override_settings(TOOLS_SERVER="tools.example.org", DRAFT_ALIAS_DOMAIN="draft.example.org")
|
||||||
def test_generator_class(self):
|
def test_generator_class(self):
|
||||||
"""The DraftAliasGenerator should generate the same lists as the old mgmt cmd"""
|
"""The DraftAliasGenerator should generate the same lists as the old mgmt cmd"""
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
# 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 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.group.models import Group
|
|
||||||
from ietf.group.utils import get_group_ad_emails, get_group_role_emails, get_child_group_role_emails
|
|
||||||
from ietf.name.models import GroupTypeName
|
|
||||||
from ietf.utils.aliases import dump_sublist
|
|
||||||
|
|
||||||
DEFAULT_YEARS = 5
|
|
||||||
ACTIVE_STATES=['active', 'bof', 'proposed']
|
|
||||||
GROUP_TYPES=['wg', 'rg', 'rag', 'dir', 'team', 'review', 'program', 'rfcedtyp', 'edappr', 'edwg'] # This should become groupfeature driven...
|
|
||||||
NO_AD_GROUP_TYPES=['rg', 'rag', 'team', 'program', 'rfcedtyp', 'edappr', 'edwg']
|
|
||||||
IETF_DOMAIN=['ietf.org', ]
|
|
||||||
IRTF_DOMAIN=['irtf.org', ]
|
|
||||||
IAB_DOMAIN=['iab.org', ]
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
|
||||||
help = ('Generate the group-aliases and group-virtual files for Internet-Draft '
|
|
||||||
'mail aliases, placing them in the file configured in '
|
|
||||||
'settings.GROUP_ALIASES_PATH and settings.GROUP_VIRTUAL_PATH, '
|
|
||||||
'respectively. The generation includes aliases for groups 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.GROUP_VIRTUAL_DOMAIN)
|
|
||||||
|
|
||||||
# Loop through each group type and build -ads and -chairs entries
|
|
||||||
for g in GROUP_TYPES:
|
|
||||||
domains = []
|
|
||||||
domains += IETF_DOMAIN
|
|
||||||
if g in ('rg', 'rag'):
|
|
||||||
domains += IRTF_DOMAIN
|
|
||||||
if g == 'program':
|
|
||||||
domains += IAB_DOMAIN
|
|
||||||
|
|
||||||
entries = Group.objects.filter(type=g).all()
|
|
||||||
active_entries = entries.filter(state__in=ACTIVE_STATES)
|
|
||||||
inactive_recent_entries = entries.exclude(state__in=ACTIVE_STATES).filter(time__gte=show_since)
|
|
||||||
interesting_entries = active_entries | inactive_recent_entries
|
|
||||||
|
|
||||||
for e in interesting_entries.distinct().iterator():
|
|
||||||
name = e.acronym
|
|
||||||
|
|
||||||
# Research groups, teams, and programs do not have -ads lists
|
|
||||||
if not g in NO_AD_GROUP_TYPES:
|
|
||||||
dump_sublist(afile, vfile, name+'-ads', domains, settings.GROUP_VIRTUAL_DOMAIN, get_group_ad_emails(e))
|
|
||||||
# All group types have -chairs lists
|
|
||||||
dump_sublist(afile, vfile, name+'-chairs', domains, settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(e, ['chair', 'secr']))
|
|
||||||
|
|
||||||
# The area lists include every chair in active working groups in the area
|
|
||||||
areas = Group.objects.filter(type='area').all()
|
|
||||||
active_areas = areas.filter(state__in=ACTIVE_STATES)
|
|
||||||
for area in active_areas:
|
|
||||||
name = area.acronym
|
|
||||||
area_ad_emails = get_group_role_emails(area, ['pre-ad', 'ad', 'chair'])
|
|
||||||
dump_sublist(afile, vfile, name+'-ads', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, area_ad_emails)
|
|
||||||
dump_sublist(afile, vfile, name+'-chairs', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, (get_child_group_role_emails(area, ['chair', 'secr']) | area_ad_emails))
|
|
||||||
|
|
||||||
# Other groups with chairs that require Internet-Draft submission approval
|
|
||||||
gtypes = GroupTypeName.objects.values_list('slug', flat=True)
|
|
||||||
special_groups = Group.objects.filter(type__features__req_subm_approval=True, acronym__in=gtypes, state='active')
|
|
||||||
for group in special_groups:
|
|
||||||
dump_sublist(afile, vfile, group.acronym+'-chairs', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(group, ['chair', 'delegate']))
|
|
||||||
|
|
||||||
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.GROUP_ALIASES_PATH)
|
|
||||||
shutil.move(vname, settings.GROUP_VIRTUAL_PATH)
|
|
|
@ -1,14 +1,12 @@
|
||||||
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
# Copyright The IETF Trust 2013-2020, All Rights Reserved
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import io
|
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
from django.core.management import call_command
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.urls import reverse as urlreverse
|
from django.urls import reverse as urlreverse
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
@ -146,108 +144,6 @@ class GenerateGroupAliasesTests(TestCase):
|
||||||
os.unlink(self.doc_virtual_file.name)
|
os.unlink(self.doc_virtual_file.name)
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
def testManagementCommand(self):
|
|
||||||
a_month_ago = timezone.now() - datetime.timedelta(30)
|
|
||||||
a_decade_ago = timezone.now() - datetime.timedelta(3650)
|
|
||||||
role1 = RoleFactory(name_id='ad', group__type_id='area', group__acronym='myth', group__state_id='active')
|
|
||||||
area = role1.group
|
|
||||||
ad = role1.person
|
|
||||||
mars = GroupFactory(type_id='wg', acronym='mars', parent=area)
|
|
||||||
marschair = PersonFactory(user__username='marschair')
|
|
||||||
mars.role_set.create(name_id='chair', person=marschair, email=marschair.email())
|
|
||||||
marssecr = PersonFactory(user__username='marssecr')
|
|
||||||
mars.role_set.create(name_id='secr', person=marssecr, email=marssecr.email())
|
|
||||||
ames = GroupFactory(type_id='wg', acronym='ames', parent=area)
|
|
||||||
ameschair = PersonFactory(user__username='ameschair')
|
|
||||||
ames.role_set.create(name_id='chair', person=ameschair, email=ameschair.email())
|
|
||||||
recent = GroupFactory(type_id='wg', acronym='recent', parent=area, state_id='conclude', time=a_month_ago)
|
|
||||||
recentchair = PersonFactory(user__username='recentchair')
|
|
||||||
recent.role_set.create(name_id='chair', person=recentchair, email=recentchair.email())
|
|
||||||
wayold = GroupFactory(type_id='wg', acronym='wayold', parent=area, state_id='conclude', time=a_decade_ago)
|
|
||||||
wayoldchair = PersonFactory(user__username='wayoldchair')
|
|
||||||
wayold.role_set.create(name_id='chair', person=wayoldchair, email=wayoldchair.email())
|
|
||||||
role2 = RoleFactory(name_id='ad', group__type_id='area', group__acronym='done', group__state_id='conclude')
|
|
||||||
done = role2.group
|
|
||||||
done_ad = role2.person
|
|
||||||
irtf = Group.objects.get(acronym='irtf')
|
|
||||||
testrg = GroupFactory(type_id='rg', acronym='testrg', parent=irtf)
|
|
||||||
testrgchair = PersonFactory(user__username='testrgchair')
|
|
||||||
testrg.role_set.create(name_id='chair', person=testrgchair, email=testrgchair.email())
|
|
||||||
testrag = GroupFactory(type_id='rg', acronym='testrag', parent=irtf)
|
|
||||||
testragchair = PersonFactory(user__username='testragchair')
|
|
||||||
testrag.role_set.create(name_id='chair', person=testragchair, email=testragchair.email())
|
|
||||||
individual = PersonFactory()
|
|
||||||
|
|
||||||
args = [ ]
|
|
||||||
kwargs = { }
|
|
||||||
out = io.StringIO()
|
|
||||||
call_command("generate_group_aliases", *args, **kwargs, stdout=out, stderr=out)
|
|
||||||
self.assertFalse(out.getvalue())
|
|
||||||
|
|
||||||
with open(settings.GROUP_ALIASES_PATH) as afile:
|
|
||||||
acontent = afile.read()
|
|
||||||
self.assertTrue('xfilter-' + area.acronym + '-ads' in acontent)
|
|
||||||
self.assertTrue('xfilter-' + area.acronym + '-chairs' in acontent)
|
|
||||||
self.assertTrue('xfilter-' + mars.acronym + '-ads' in acontent)
|
|
||||||
self.assertTrue('xfilter-' + mars.acronym + '-chairs' in acontent)
|
|
||||||
self.assertTrue('xfilter-' + ames.acronym + '-ads' in acontent)
|
|
||||||
self.assertTrue('xfilter-' + ames.acronym + '-chairs' in acontent)
|
|
||||||
self.assertTrue(all([x in acontent for x in [
|
|
||||||
'xfilter-' + area.acronym + '-ads',
|
|
||||||
'xfilter-' + area.acronym + '-chairs',
|
|
||||||
'xfilter-' + mars.acronym + '-ads',
|
|
||||||
'xfilter-' + mars.acronym + '-chairs',
|
|
||||||
'xfilter-' + ames.acronym + '-ads',
|
|
||||||
'xfilter-' + ames.acronym + '-chairs',
|
|
||||||
'xfilter-' + recent.acronym + '-ads',
|
|
||||||
'xfilter-' + recent.acronym + '-chairs',
|
|
||||||
]]))
|
|
||||||
self.assertFalse(all([x in acontent for x in [
|
|
||||||
'xfilter-' + done.acronym + '-ads',
|
|
||||||
'xfilter-' + done.acronym + '-chairs',
|
|
||||||
'xfilter-' + wayold.acronym + '-ads',
|
|
||||||
'xfilter-' + wayold.acronym + '-chairs',
|
|
||||||
]]))
|
|
||||||
|
|
||||||
with open(settings.GROUP_VIRTUAL_PATH) as vfile:
|
|
||||||
vcontent = vfile.read()
|
|
||||||
self.assertTrue(all([x in vcontent for x in [
|
|
||||||
ad.email_address(),
|
|
||||||
marschair.email_address(),
|
|
||||||
marssecr.email_address(),
|
|
||||||
ameschair.email_address(),
|
|
||||||
recentchair.email_address(),
|
|
||||||
testrgchair.email_address(),
|
|
||||||
testragchair.email_address(),
|
|
||||||
]]))
|
|
||||||
self.assertFalse(any([x in vcontent for x in [
|
|
||||||
done_ad.email_address(),
|
|
||||||
wayoldchair.email_address(),
|
|
||||||
individual.email_address(),
|
|
||||||
]]))
|
|
||||||
self.assertTrue(all([x in vcontent for x in [
|
|
||||||
'xfilter-' + area.acronym + '-ads',
|
|
||||||
'xfilter-' + area.acronym + '-chairs',
|
|
||||||
'xfilter-' + mars.acronym + '-ads',
|
|
||||||
'xfilter-' + mars.acronym + '-chairs',
|
|
||||||
'xfilter-' + ames.acronym + '-ads',
|
|
||||||
'xfilter-' + ames.acronym + '-chairs',
|
|
||||||
'xfilter-' + recent.acronym + '-ads',
|
|
||||||
'xfilter-' + recent.acronym + '-chairs',
|
|
||||||
'xfilter-' + testrg.acronym + '-chairs',
|
|
||||||
'xfilter-' + testrag.acronym + '-chairs',
|
|
||||||
testrg.acronym + '-chairs@ietf.org',
|
|
||||||
testrg.acronym + '-chairs@irtf.org',
|
|
||||||
testrag.acronym + '-chairs@ietf.org',
|
|
||||||
testrag.acronym + '-chairs@irtf.org',
|
|
||||||
]]))
|
|
||||||
self.assertFalse(all([x in vcontent for x in [
|
|
||||||
'xfilter-' + done.acronym + '-ads',
|
|
||||||
'xfilter-' + done.acronym + '-chairs',
|
|
||||||
'xfilter-' + wayold.acronym + '-ads',
|
|
||||||
'xfilter-' + wayold.acronym + '-chairs',
|
|
||||||
]]))
|
|
||||||
|
|
||||||
def test_generator_class(self):
|
def test_generator_class(self):
|
||||||
"""The GroupAliasGenerator should generate the same lists as the old mgmt cmd"""
|
"""The GroupAliasGenerator should generate the same lists as the old mgmt cmd"""
|
||||||
# clean out test fixture group roles we don't need for this test
|
# clean out test fixture group roles we don't need for this test
|
||||||
|
|
Loading…
Reference in a new issue