email expansions for groups

- Legacy-Id: 10058
This commit is contained in:
Robert Sparks 2015-08-25 18:10:51 +00:00
parent 46c5b3ff64
commit e5a6ab4385
7 changed files with 128 additions and 48 deletions

View file

@ -57,6 +57,7 @@ from ietf.group.utils import get_charter_text, can_manage_group_type, milestone_
from ietf.group.utils import can_manage_materials, get_group_or_404
from ietf.utils.pipe import pipe
from ietf.settings import MAILING_LIST_INFO_URL
from ietf.mailtoken.utils import gather_relevant_expansions
def roles(group, role_name):
return Role.objects.filter(group=group, name=role_name).select_related("email", "person")
@ -296,6 +297,7 @@ def construct_group_menu_context(request, group, selected, group_type, others):
entries.append(("About", urlreverse("group_about", kwargs=kwargs)))
if group.features.has_materials and get_group_materials(group).exists():
entries.append(("Materials", urlreverse("ietf.group.info.materials", kwargs=kwargs)))
entries.append(("Email expansions", urlreverse("ietf.group.info.email", kwargs=kwargs)))
entries.append(("History", urlreverse("ietf.group.info.history", kwargs=kwargs)))
if group.features.has_documents:
entries.append((mark_safe("Dependency graph »"), urlreverse("ietf.group.info.dependencies_pdf", kwargs=kwargs)))
@ -444,6 +446,34 @@ def group_about(request, acronym, group_type=None):
"can_manage": can_manage,
}))
def get_email_aliases(acronym, group_type):
if acronym:
pattern = re.compile('expand-(%s)(-\w+)@.*? +(.*)$'%acronym)
else:
pattern = re.compile('expand-(.*?)(-\w+)@.*? +(.*)$')
aliases = []
with open(settings.GROUP_VIRTUAL_PATH,"r") as virtual_file:
for line in virtual_file.readlines():
m = pattern.match(line)
if m:
if acronym or not group_type or Group.objects.filter(acronym=m.group(1),type__slug=group_type):
aliases.append({'acronym':m.group(1),'alias_type':m.group(2),'expansion':m.group(3)})
return aliases
def email(request, acronym, group_type=None):
group = get_group_or_404(acronym, group_type)
aliases = get_email_aliases(acronym, group_type)
expansions = gather_relevant_expansions(group=group)
return render(request, 'group/email.html',
construct_group_menu_context(request, group, "email expansions", group_type, {
'expansions':expansions,
'aliases':aliases,
'group':group,
'ietf_domain':settings.IETF_DOMAIN,
}))
def history(request, acronym, group_type=None):
group = get_group_or_404(acronym, group_type)
@ -638,22 +668,13 @@ def dependencies_pdf(request, acronym, group_type=None):
def email_aliases(request, acronym=None, group_type=None):
group = get_group_or_404(acronym,group_type) if acronym else None
if acronym:
pattern = re.compile('expand-(%s)(-\w+)@.*? +(.*)$'%acronym)
else:
if not acronym:
# require login for the overview page, but not for the group-specific
# pages handled above
# pages
if not request.user.is_authenticated():
return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
pattern = re.compile('expand-(.*?)(-\w+)@.*? +(.*)$')
aliases = []
with open(settings.GROUP_VIRTUAL_PATH,"r") as virtual_file:
for line in virtual_file.readlines():
m = pattern.match(line)
if m:
if acronym or not group_type or Group.objects.filter(acronym=m.group(1),type__slug=group_type):
aliases.append({'acronym':m.group(1),'alias_type':m.group(2),'expansion':m.group(3)})
aliases = get_email_aliases(acronym, group_type)
return render(request,'group/email_aliases.html',{'aliases':aliases,'ietf_domain':settings.IETF_DOMAIN,'group':group})

View file

@ -1009,25 +1009,36 @@ expand-ames-chairs@virtual.ietf.org mars_chair@ietf
def tearDown(self):
os.unlink(self.group_alias_file.name)
def testNothing(self):
url = urlreverse('ietf.group.info.email_aliases', kwargs=dict(acronym="mars"))
def testAliases(self):
url = urlreverse('old_group_email_aliases', kwargs=dict(acronym="mars"))
r = self.client.get(url)
self.assertTrue(all([x in r.content for x in ['mars-ads@','mars-chairs@']]))
self.assertFalse(any([x in r.content for x in ['ames-ads@','ames-chairs@']]))
self.assertEqual(r.status_code, 302)
url = urlreverse('ietf.group.info.email_aliases', kwargs=dict())
login_testing_unauthorized(self, "plain", url)
r = self.client.get(url)
self.assertTrue(r.status_code,200)
self.assertTrue(all([x in r.content for x in ['mars-ads@','mars-chairs@','ames-ads@','ames-chairs@']]))
url = urlreverse('ietf.group.info.email_aliases', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code,200)
self.assertTrue('mars-ads@' in r.content)
url = urlreverse('ietf.group.info.email_aliases', kwargs=dict(group_type="rg"))
r = self.client.get(url)
self.assertEqual(r.status_code,200)
self.assertFalse('mars-ads@' in r.content)
def testExpansions(self):
url = urlreverse('ietf.group.info.email', kwargs=dict(acronym="mars"))
r = self.client.get(url)
self.assertEqual(r.status_code,200)
self.assertTrue('Email Aliases' in r.content)
self.assertTrue('mars-ads@ietf.org' in r.content)
self.assertTrue('group_personnel_change' in r.content)
class AjaxTests(TestCase):
def test_group_menu_data(self):

View file

@ -1,6 +1,8 @@
# Copyright The IETF Trust 2007, All Rights Reserved
from django.conf.urls import patterns
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^groupmenu.json', 'ietf.group.ajax.group_menu_data', None, "group_menu_data"),
@ -15,6 +17,7 @@ urlpatterns = patterns('',
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/$', 'ietf.group.info.group_home', None, "group_home"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/documents/$', 'ietf.group.info.group_documents', None, "group_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/charter/$', 'ietf.group.info.group_about', None, 'group_charter'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/email/$', 'ietf.group.info.email'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/history/$', 'ietf.group.info.history'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/deps/dot/$', 'ietf.group.info.dependencies_dot'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/deps/pdf/$', 'ietf.group.info.dependencies_pdf'),
@ -30,7 +33,6 @@ urlpatterns = patterns('',
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/$', 'ietf.group.info.materials', None, "group_materials"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/$', 'ietf.doc.views_material.choose_material_type'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/(?P<doc_type>[\w-]+)/$', 'ietf.doc.views_material.edit_material', { 'action': "new" }, "group_new_material"),
(r'^(?P<acronym>[A-Za-z0-9._+-]+)/email-aliases/$', 'ietf.group.info.email_aliases'),
url(r'^(?P<acronym>[A-Za-z0-9._+-]+)/email-aliases/$', RedirectView.as_view(pattern_name='ietf.group.info.email',permanent=False),name='old_group_email_aliases'),
)

View file

@ -1,6 +1,6 @@
# Copyright The IETF Trust 2008, All Rights Reserved
from django.conf.urls import patterns
from django.conf.urls import patterns, url
from django.views.generic import RedirectView
from ietf.group import info, edit, milestones
@ -23,6 +23,7 @@ urlpatterns = patterns('',
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/$', info.group_home, None, "group_home"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/documents/$', info.group_documents, None, "group_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/charter/$', info.group_about, None, 'group_charter'),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/email/$', info.email),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/history/$', info.history),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/deps/dot/$', info.dependencies_dot),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/deps/pdf/$', info.dependencies_pdf),
@ -33,5 +34,5 @@ urlpatterns = patterns('',
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "group_edit_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "group_reset_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/workflow/$', edit.customize_workflow),
(r'^(?P<acronym>[A-Za-z0-9._+-]+)/email-aliases/$', 'ietf.group.info.email_aliases'),
url(r'^(?P<acronym>[A-Za-z0-9._+-]+)/email-aliases/$', RedirectView.as_view(pattern_name='ietf.group.info.email',permanent=False),name='old_group_email_aliases'),
)

View file

@ -1,5 +1,6 @@
from collections import namedtuple
from ietf.mailtoken.models import MailToken, Recipient
from ietf.submit.models import Submission
class AddrLists(namedtuple('AddrLists',['to','cc'])):
@ -29,6 +30,10 @@ def gather_address_lists(slug, **kwargs):
return AddrLists(to=list(to),cc=list(cc))
def gather_relevant_expansions(**kwargs):
def starts_with(prefix):
return MailToken.objects.filter(slug__startswith=prefix).values_list('slug',flat=True)
relevant = set()
if 'doc' in kwargs:
@ -38,25 +43,41 @@ def gather_relevant_expansions(**kwargs):
relevant.update(['doc_state_edited','doc_telechat_details_changed','ballot_deferred','ballot_saved'])
if doc.type_id in ['draft','statchg']:
relevant.update(MailToken.objects.filter(slug__startswith='last_call_').values_list('slug',flat=True))
relevant.update(starts_with('last_call_'))
if doc.type_id == 'draft':
relevant.update(MailToken.objects.filter(slug__startswith='doc_').values_list('slug',flat=True))
relevant.update(starts_with('doc_'))
relevant.update(starts_with('resurrection_'))
relevant.update(['ipr_posted_on_doc',])
if doc.stream_id == 'ietf':
relevant.update(['ballot_approved_ietf_stream'])
relevant.update(['ballot_approved_ietf_stream','pubreq_iesg'])
else:
relevant.update(['pubreq_rfced'])
last_submission = Submission.objects.filter(name=doc.name,state='posted').order_by('-rev').first()
if last_submission and 'submission' not in kwargs:
kwargs['submission'] = last_submission
if doc.type_id == 'conflrev':
relevant.update(['conflrev_requested','ballot_approved_conflrev'])
if doc.type_id == 'charter':
relevant.update(['charter_external_review','ballot_approved_charter'])
if 'group' in kwargs:
relevant.update(starts_with('group_'))
relevant.update(starts_with('milestones_'))
relevant.update(starts_with('session_'))
relevant.update(['charter_external_review',])
if 'submission' in kwargs:
relevant.update(starts_with('sub_'))
rule_list = []
for mailtoken in MailToken.objects.filter(slug__in=relevant):
addrs = gather_address_lists(mailtoken.slug,**kwargs)
rule_list.append((mailtoken.slug,mailtoken.desc,addrs.to,addrs.cc))
if addrs.to or addrs.cc:
rule_list.append((mailtoken.slug,mailtoken.desc,addrs.to,addrs.cc))
return sorted(rule_list)
def get_base_ipr_request_address():

View file

@ -46,27 +46,4 @@
{% endfor %}
</tbody>
</table>
{% comment %}
<table class="table table-condensed table-striped ietf">
<thead>
<tr>
<th>Date</th>
<th>Rev.</th>
<th>By</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for e in events %}
<tr class="anchor-target" id="history-{{ e.pk }}">
<td class="text-nowrap">{{ e.time|date:"Y-m-d" }}</td>
<td class="text-center">{{ e.rev }}</td>
<td>{{ e.by|escape }}</td>
<td>{{ e.desc|format_history_text|safe }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endcomment %}
{% endblock content %}

View file

@ -0,0 +1,47 @@
{% extends "group/group_base.html" %}
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}
{% load ietf_filters %}
{% load future %}
{% block group_content %}
{% origin %}
{% if aliases %}
<h2>Email Aliases</h2>
<table class="table table-condensed table-striped ietf">
<tbody>
{% for alias in aliases %}
<tr>
<td>{{ group.acronym }}{{ alias.alias_type|default:''}}@{{ietf_domain}}</td>
<td>{{ alias.expansion }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<h2>Recipient Expansions</h2>
<table class="table table-condensed table-striped ietf">
<thead>
<tr>
<th>MailToken</th>
<th>To</th>
<th>Cc</th>
</tr>
</thead>
<tbody>
{% for token,desc,to,cc in expansions %}
<tr>
<td><a href="{% url 'ietf.mailtoken.views.show_tokens' token %}"
title="{{desc}}">{{token}}</a></td>
<td> {{to|join:', '}}</td>
<td> {{cc|join:', '}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}