Merged in [13996] from rcross@amsl.com:
Move Announcement app From addresses out of code and into database table. Fixes #1681. - Legacy-Id: 14006 Note: SVN reference [13996] has been migrated to Git commit d49787a0f6060e7db64f5a0e684bf1d980f85290
This commit is contained in:
parent
5c66ec25f2
commit
868427a645
|
@ -1,6 +1,6 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from ietf.message.models import Message, SendQueue
|
||||
from ietf.message.models import Message, SendQueue, AnnouncementFrom
|
||||
|
||||
class MessageAdmin(admin.ModelAdmin):
|
||||
list_display = ["subject", "by", "time", "groups"]
|
||||
|
@ -19,5 +19,8 @@ class SendQueueAdmin(admin.ModelAdmin):
|
|||
search_fields = ["message__body"]
|
||||
raw_id_fields = ["by", "message"]
|
||||
ordering = ["-time"]
|
||||
|
||||
admin.site.register(SendQueue, SendQueueAdmin)
|
||||
|
||||
class AnnouncementFromAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'group', 'address', ]
|
||||
admin.site.register(AnnouncementFrom, AnnouncementFromAdmin)
|
||||
|
|
27
ietf/message/migrations/0005_announcementfrom.py
Normal file
27
ietf/message/migrations/0005_announcementfrom.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2017-07-28 11:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('group', '0011_auto_20170301_0332'),
|
||||
('name', '0024_merge_20170606_1320'),
|
||||
('message', '0004_change_msgid_default'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AnnouncementFrom',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('address', models.EmailField(max_length=254)),
|
||||
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='group.Group')),
|
||||
('name', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='name.RoleName')),
|
||||
],
|
||||
),
|
||||
]
|
88
ietf/message/migrations/0006_add_announcement_from.py
Normal file
88
ietf/message/migrations/0006_add_announcement_from.py
Normal file
|
@ -0,0 +1,88 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.7 on 2017-07-05 16:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(apps, schema_editor):
|
||||
AnnouncementFrom = apps.get_model('message', 'AnnouncementFrom')
|
||||
Group = apps.get_model('group', 'Group')
|
||||
RoleName = apps.get_model('name', 'RoleName')
|
||||
|
||||
chair = RoleName.objects.get(slug='chair')
|
||||
admdir = RoleName.objects.get(slug='admdir')
|
||||
execdir = RoleName.objects.get(slug='execdir')
|
||||
ceo = RoleName.objects.get(slug='ceo')
|
||||
secr = RoleName.objects.get(slug='secr')
|
||||
|
||||
# IETF Chair
|
||||
ietf = Group.objects.get(acronym='ietf')
|
||||
AnnouncementFrom.objects.create(name=chair,group=ietf,address='IETF Chair <chair@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=chair,group=ietf,address='The IESG <iesg@ietf.org>')
|
||||
|
||||
# IAB Chair
|
||||
iab = Group.objects.get(acronym='iab')
|
||||
AnnouncementFrom.objects.create(name=chair,group=iab,address='IAB Chair <iab-chair@ietf.org>')
|
||||
|
||||
# IAB Execdir
|
||||
AnnouncementFrom.objects.create(name=execdir,group=iab,address='IAB Executive Administrative Manager <execd@iab.org>')
|
||||
AnnouncementFrom.objects.create(name=execdir,group=iab,address='IAB Chair <iab-chair@ietf.org>')
|
||||
|
||||
# IAD
|
||||
AnnouncementFrom.objects.create(name=admdir,group=ietf,address='IETF Administrative Director <iad@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=admdir,group=ietf,address='The IETF Trust <ietf-trust@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=admdir,group=ietf,address='ISOC CEO <ceo@isoc.org>')
|
||||
AnnouncementFrom.objects.create(name=admdir,group=ietf,address='IAOC Chair <iaoc-chair@ietf.org>')
|
||||
|
||||
# RSOC Chair
|
||||
rsoc = Group.objects.get(acronym='rsoc')
|
||||
AnnouncementFrom.objects.create(name=chair,group=rsoc,address='RSOC Chair <rsoc-chair@iab.org>')
|
||||
|
||||
# IAOC Chair
|
||||
iaoc = Group.objects.get(acronym='iaoc')
|
||||
AnnouncementFrom.objects.create(name=chair,group=iaoc,address='IAOC Chair <iaoc-chair@ietf.org>')
|
||||
|
||||
# RSE Chair
|
||||
rse = Group.objects.get(acronym='rse')
|
||||
AnnouncementFrom.objects.create(name=chair,group=rse,address='RFC Series Editor <rse@rfc-editor.org>')
|
||||
|
||||
# Mentor Chair
|
||||
mentor = Group.objects.get(acronym='mentor')
|
||||
AnnouncementFrom.objects.create(name=chair,group=mentor,address='IETF Mentoring Program <mentoring@ietf.org>')
|
||||
|
||||
# ISOC CEO
|
||||
isoc = Group.objects.get(acronym='isoc')
|
||||
AnnouncementFrom.objects.create(name=ceo,group=isoc,address='ISOC CEO <ceo@isoc.org>')
|
||||
|
||||
# ISOC BOARD OF TRUSTEES
|
||||
isocbot = Group.objects.get(acronym='isocbot')
|
||||
AnnouncementFrom.objects.create(name=chair,group=isocbot,address='ISOC Board of Trustees <bob.hinden@gmail.com>')
|
||||
|
||||
# IETF TRUST
|
||||
ietftrust = Group.objects.get(acronym='ietf-trust')
|
||||
AnnouncementFrom.objects.create(name=chair,group=ietftrust,address='The IETF Trust <ietf-trust@ietf.org>')
|
||||
|
||||
# Misc
|
||||
secretariat = Group.objects.get(acronym='secretariat')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IETF Secretariat <ietf-secretariat@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IESG Secretary <iesg-secretary@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='Internet-Drafts Administrator <internet-drafts@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IETF Agenda <agenda@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IETF Registrar <ietf-registrar@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IETF Executive Director <exec-director@ietf.org>')
|
||||
|
||||
def backwards(apps, schema_editor):
|
||||
AnnouncementFrom = apps.get_model('announcement', "AnnouncementFrom")
|
||||
AnnouncementFrom.objects.all().delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('message', '0005_announcementfrom'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards, backwards),
|
||||
]
|
|
@ -8,6 +8,7 @@ import debug # pyflakes:ignore
|
|||
from ietf.person.models import Person
|
||||
from ietf.group.models import Group
|
||||
from ietf.doc.models import Document
|
||||
from ietf.name.models import RoleName
|
||||
|
||||
class Message(models.Model):
|
||||
time = models.DateTimeField(default=datetime.datetime.now)
|
||||
|
@ -61,3 +62,16 @@ class SendQueue(models.Model):
|
|||
|
||||
def __unicode__(self):
|
||||
return u"'%s' %s -> %s (sent at %s)" % (self.message.subject, self.message.frm, self.message.to, self.sent_at or "<not yet>")
|
||||
|
||||
|
||||
class AnnouncementFrom(models.Model):
|
||||
name = models.ForeignKey(RoleName)
|
||||
group = models.ForeignKey(Group)
|
||||
address = models.EmailField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.address
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural='Announcement From addresses'
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ from tastypie.cache import SimpleCache
|
|||
|
||||
from ietf import api
|
||||
|
||||
from ietf.message.models import Message, SendQueue, MessageAttachment
|
||||
from ietf.message.models import Message, SendQueue, MessageAttachment, AnnouncementFrom
|
||||
from ietf.person.resources import PersonResource
|
||||
from ietf.group.resources import GroupResource
|
||||
from ietf.doc.resources import DocumentResource
|
||||
|
@ -76,3 +76,22 @@ class MessageAttachmentResource(ModelResource):
|
|||
}
|
||||
api.message.register(MessageAttachmentResource())
|
||||
|
||||
|
||||
|
||||
from ietf.group.resources import GroupResource
|
||||
from ietf.name.resources import RoleNameResource
|
||||
class AnnouncementFromResource(ModelResource):
|
||||
name = ToOneField(RoleNameResource, 'name')
|
||||
group = ToOneField(GroupResource, 'group')
|
||||
class Meta:
|
||||
queryset = AnnouncementFrom.objects.all()
|
||||
serializer = api.Serializer()
|
||||
cache = SimpleCache()
|
||||
#resource_name = 'announcementfrom'
|
||||
filtering = {
|
||||
"id": ALL,
|
||||
"address": ALL,
|
||||
"name": ALL_WITH_RELATIONS,
|
||||
"group": ALL_WITH_RELATIONS,
|
||||
}
|
||||
api.message.register(AnnouncementFromResource())
|
||||
|
|
|
@ -2,40 +2,13 @@ from django import forms
|
|||
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.message.models import Message
|
||||
from ietf.secr.utils.group import current_nomcom
|
||||
from ietf.message.models import Message, AnnouncementFrom
|
||||
from ietf.utils.fields import MultiEmailField
|
||||
|
||||
# ---------------------------------------------
|
||||
# Globals
|
||||
# ---------------------------------------------
|
||||
|
||||
ANNOUNCE_FROM_GROUPS = ['ietf','rsoc','iab']
|
||||
if current_nomcom():
|
||||
ANNOUNCE_FROM_GROUPS += [ current_nomcom().acronym ]
|
||||
ANNOUNCE_TO_GROUPS= ['ietf']
|
||||
|
||||
# this list isn't currently available as a Role query so it's hardcoded
|
||||
FROM_LIST = ('IETF Secretariat <ietf-secretariat@ietf.org>',
|
||||
'IESG Secretary <iesg-secretary@ietf.org>',
|
||||
'The IESG <iesg@ietf.org>',
|
||||
'Internet-Drafts Administrator <internet-drafts@ietf.org>',
|
||||
'IETF Agenda <agenda@ietf.org>',
|
||||
'IETF Chair <chair@ietf.org>',
|
||||
'IAB Chair <iab-chair@ietf.org> ',
|
||||
'NomCom Chair <nomcom-chair@ietf.org>',
|
||||
'IETF Registrar <ietf-registrar@ietf.org>',
|
||||
'IETF Administrative Director <iad@ietf.org>',
|
||||
'IETF Executive Director <exec-director@ietf.org>',
|
||||
'IAOC Chair <iaoc-chair@ietf.org>',
|
||||
'The IETF Trust <ietf-trust@ietf.org>',
|
||||
'RSOC Chair <rsoc-chair@iab.org>',
|
||||
'ISOC Board of Trustees <bob.hinden@gmail.com>',
|
||||
'RFC Series Editor <rse@rfc-editor.org>',
|
||||
'IAB Executive Administrative Manager <execd@iab.org>',
|
||||
'IETF Mentoring Program <mentoring@ietf.org>',
|
||||
'ISOC CEO <ceo@isoc.org>')
|
||||
|
||||
TO_LIST = ('IETF Announcement List <ietf-announce@ietf.org>',
|
||||
'I-D Announcement List <i-d-announce@ietf.org>',
|
||||
'The IESG <iesg@ietf.org>',
|
||||
|
@ -53,85 +26,48 @@ def get_from_choices(user):
|
|||
all the Announced From choices. Including
|
||||
leadership chairs and other entities.
|
||||
'''
|
||||
person = user.person
|
||||
f = []
|
||||
addresses = []
|
||||
if has_role(user,'Secretariat'):
|
||||
f = FROM_LIST
|
||||
elif has_role(user,'IETF Chair'):
|
||||
f = (FROM_LIST[2],FROM_LIST[5])
|
||||
elif has_role(user,'IAB Chair'):
|
||||
f = (FROM_LIST[6],)
|
||||
elif has_role(user,'IAD'):
|
||||
f = (FROM_LIST[9],FROM_LIST[12],FROM_LIST[18],FROM_LIST[11],)
|
||||
#RSOC Chair, IAOC Chair aren't supported by has_role()
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='rsoc',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[13],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='iaoc',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[11],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='rse',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[15],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='iab',
|
||||
name='execdir'):
|
||||
f = (FROM_LIST[6],FROM_LIST[16])
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='mentor',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[17],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='isoc',
|
||||
name="ceo"):
|
||||
f = (FROM_LIST[18],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='isocbot',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[14],)
|
||||
elif Role.objects.filter(person=person,
|
||||
group__acronym='ietf-trust',
|
||||
name="chair"):
|
||||
f = (FROM_LIST[12],)
|
||||
addresses = AnnouncementFrom.objects.values_list('address', flat=True).order_by('address').distinct()
|
||||
else:
|
||||
for role in user.person.role_set.all():
|
||||
addresses.extend(AnnouncementFrom.objects.filter(name=role.name, group=role.group).values_list('address', flat=True).order_by('address'))
|
||||
|
||||
# NomCom
|
||||
nomcom_choices = get_nomcom_choices(user)
|
||||
if nomcom_choices:
|
||||
addresses = list(addresses) + nomcom_choices
|
||||
|
||||
return zip(addresses, addresses)
|
||||
|
||||
|
||||
def get_nomcom_choices(user):
|
||||
'''
|
||||
Returns the list of nomcom email addresses for given user
|
||||
'''
|
||||
nomcoms = Role.objects.filter(name="chair",
|
||||
group__acronym__startswith="nomcom",
|
||||
group__state="active",
|
||||
group__type="nomcom",
|
||||
person=person)
|
||||
if nomcoms:
|
||||
year = nomcoms[0].group.acronym[-4:]
|
||||
alias = 'NomCom Chair %s <nomcom-chair-%s@ietf.org>' % (year,year)
|
||||
f = (alias,)
|
||||
person=user.person)
|
||||
addresses = []
|
||||
for nomcom in nomcoms:
|
||||
year = nomcom.group.acronym[-4:]
|
||||
addresses.append('NomCom Chair %s <nomcom-chair-%s@ietf.org>' % (year,year))
|
||||
|
||||
return zip(f,f)
|
||||
return addresses
|
||||
|
||||
|
||||
def get_to_choices():
|
||||
#groups = Group.objects.filter(acronym__in=ANNOUNCE_TO_GROUPS)
|
||||
#roles = Role.objects.filter(group__in=(groups),name="Announce")
|
||||
#choices = [ (r.email, r.person.name) for r in roles ]
|
||||
#choices.append(('Other...','Other...'),)
|
||||
return zip(TO_LIST,TO_LIST)
|
||||
|
||||
# ---------------------------------------------
|
||||
# Select Choices
|
||||
# ---------------------------------------------
|
||||
TO_CHOICES = get_to_choices()
|
||||
#FROM_CHOICES = get_from_choices()
|
||||
|
||||
# ---------------------------------------------
|
||||
# Forms
|
||||
# ---------------------------------------------
|
||||
|
||||
class AnnounceForm(forms.ModelForm):
|
||||
#nomcom = forms.BooleanField(required=False)
|
||||
nomcom = forms.ModelChoiceField(queryset=Group.objects.filter(acronym__startswith='nomcom',type='nomcom',state='active'),required=False)
|
||||
to_custom = MultiEmailField(required=False,label='')
|
||||
#cc = MultiEmailField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Message
|
||||
|
@ -145,7 +81,7 @@ class AnnounceForm(forms.ModelForm):
|
|||
user = kwargs.pop('user')
|
||||
person = user.person
|
||||
super(AnnounceForm, self).__init__(*args, **kwargs)
|
||||
self.fields['to'].widget = forms.Select(choices=TO_CHOICES)
|
||||
self.fields['to'].widget = forms.Select(choices=get_to_choices())
|
||||
self.fields['to'].help_text = 'Select name OR select Other... and enter email below'
|
||||
self.fields['cc'].help_text = 'Use comma separated lists for emails (Cc, Bcc, Reply To)'
|
||||
self.fields['frm'].widget = forms.Select(choices=get_from_choices(user))
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
from django.db import connection
|
||||
from django.urls import reverse
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
@ -6,8 +5,10 @@ from pyquery import PyQuery
|
|||
from ietf.utils.test_utils import TestCase
|
||||
from ietf.group.models import Group
|
||||
from ietf.message.models import Message
|
||||
from ietf.name.models import RoleName
|
||||
from ietf.nomcom.test_data import nomcom_test_data
|
||||
from ietf.person.models import Person
|
||||
from ietf.message.models import AnnouncementFrom
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.mail import outbox, empty_outbox
|
||||
|
||||
|
@ -16,17 +17,49 @@ WG_USER=''
|
|||
AD_USER=''
|
||||
|
||||
class SecrAnnouncementTestCase(TestCase):
|
||||
# ------- Test View -------- #
|
||||
def setUp(self):
|
||||
make_test_data()
|
||||
chair = RoleName.objects.get(slug='chair')
|
||||
secr = RoleName.objects.get(slug='secr')
|
||||
ietf = Group.objects.get(acronym='ietf')
|
||||
iab = Group.objects.get(acronym='iab')
|
||||
secretariat = Group.objects.get(acronym='secretariat')
|
||||
AnnouncementFrom.objects.create(name=secr,group=secretariat,address='IETF Secretariat <ietf-secretariat@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=chair,group=ietf,address='IETF Chair <chair@ietf.org>')
|
||||
AnnouncementFrom.objects.create(name=chair,group=iab,address='IAB Chair <iab-chair@ietf.org>')
|
||||
|
||||
def test_main(self):
|
||||
"Main Test"
|
||||
make_test_data()
|
||||
url = reverse('ietf.secr.announcement.views.main')
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_main_announce_from(self):
|
||||
url = reverse('ietf.secr.announcement.views.main')
|
||||
|
||||
class DummyCase(TestCase):
|
||||
name = connection.settings_dict['NAME']
|
||||
# Secretariat
|
||||
self.client.login(username="secretary", password="secretary+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#id_frm option')),3)
|
||||
|
||||
# IAB Chair
|
||||
self.client.login(username="iab-chair", password="iab-chair+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#id_frm option')),1)
|
||||
self.assertTrue('<iab-chair@ietf.org>' in q('#id_frm option').val())
|
||||
|
||||
# IETF Chair
|
||||
self.client.login(username="ietf-chair", password="ietf-chair+password")
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('#id_frm option')),1)
|
||||
self.assertTrue('<chair@ietf.org>' in q('#id_frm option').val())
|
||||
|
||||
class UnauthorizedAnnouncementCase(TestCase):
|
||||
def test_unauthorized(self):
|
||||
|
|
Loading…
Reference in a new issue