Skip to content

Commit 0cf3a7f

Browse files
committed
Update automatically POC and CC fields for incoming liaison. See ietf-tools#345
- Legacy-Id: 2349
1 parent 9084150 commit 0cf3a7f

File tree

11 files changed

+580
-37
lines changed

11 files changed

+580
-37
lines changed

ietf/liaisons/accounts.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
1-
from ietf.idtracker.models import Role
1+
from ietf.idtracker.models import Role, PersonOrOrgInfo
2+
3+
4+
def get_ietf_chair():
5+
person = PersonOrOrgInfo.objects.filter(role=Role.IETF_CHAIR)
6+
return person and person[0] or None
7+
8+
9+
def get_iesg_chair():
10+
return get_ietf_chair()
11+
12+
13+
def get_iab_chair():
14+
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_CHAIR)
15+
return person and person[0] or None
16+
17+
18+
def get_iab_executive_director():
19+
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_EXCUTIVE_DIRECTOR)
20+
return person and person[0] or None
221

322

423
def get_person_for_user(user):

ietf/liaisons/forms.py

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,40 @@
11
from django import forms
22
from django.template.loader import render_to_string
33

4-
from ietf.liaisons.models import LiaisonDetail
54
from ietf.liaisons.accounts import (can_add_outgoing_liaison, can_add_incoming_liaison,
65
get_person_for_user)
6+
from ietf.liaisons.models import LiaisonDetail
7+
from ietf.liaisons.utils import IETFHierarchyManager
8+
from ietf.liaisons.widgets import FromWidget, ReadOnlyWidget
79

810

911
class LiaisonForm(forms.ModelForm):
1012

11-
from_field = forms.ChoiceField()
12-
organization = forms.CharField()
13-
14-
fieldsets = ((None, ('from_field', 'replyto', 'organization', 'to_poc',
15-
'cc1', 'response_contact', 'technical_contact',
16-
'purpose', 'purpose_text', 'deadline_date', 'body',
17-
)
18-
),
13+
from_field = forms.ChoiceField(widget=FromWidget, label=u'From')
14+
replyto = forms.CharField(label=u'Reply to')
15+
organization = forms.ChoiceField()
16+
to_poc = forms.CharField(widget=ReadOnlyWidget, label="POC")
17+
cc1 = forms.CharField(widget=ReadOnlyWidget, label="CC")
18+
19+
fieldsets = (('From', ('from_field', 'replyto')),
20+
('To', ('organization', 'to_poc')),
21+
('Other email addresses', ('response_contact', 'technical_contact', 'cc1')),
22+
('Purpose', ('purpose', 'purpose_text', 'deadline_date')),
23+
('Body', ('body', )),
1924
)
2025

2126
class Meta:
2227
model = LiaisonDetail
2328

29+
class Media:
30+
js = ("/js/jquery-1.4.2.min.js",
31+
"/js/liaisons.js", )
32+
33+
css = {'all': ("/css/liaisons.css", )}
34+
2435
def __init__(self, user, *args, **kwargs):
2536
super(LiaisonForm, self).__init__(*args, **kwargs)
37+
self.hm = IETFHierarchyManager()
2638
self.person = get_person_for_user(user)
2739
self.set_from_field()
2840
self.set_replyto_field()
@@ -65,12 +77,11 @@ def set_from_field(self):
6577
sdo_managed = [i.sdo for i in self.person.liaisonmanagers_set.all()]
6678
sdo_authorized = [i.sdo for i in self.person.sdoauthorizedindividual_set.all()]
6779
sdos = set(sdo_managed).union(sdo_authorized)
68-
self.fields['from_field'].choices = [(i.pk, '%s (%s)' % (i.sdo_name, self.person)) for i in sdos]
80+
self.fields['from_field'].choices = [(i.pk, i.sdo_name) for i in sdos]
81+
self.fields['from_field'].widget.submitter = unicode(self.person)
6982

7083
def set_organization_field(self):
71-
organizations = ['The IETF', 'The IESG', 'The IAB']
72-
organizations.append('-- IETF Areas ---')
73-
organizations.append('-- IETF Working Groups ---')
84+
self.fields['organization'].choices = self.hm.get_all_entities()
7485

7586

7687
class OutgoingLiaisonForm(LiaisonForm):

ietf/liaisons/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,6 @@
2323

2424
urlpatterns += patterns('ietf.liaisons.views',
2525
url(r'^add/$', 'add_liaison', name='add_liaison'),
26+
url(r'^ajax/get_poc_for_incoming/$', 'get_poc_for_incoming', name='get_poc_for_incoming'),
27+
url(r'^ajax/get_cc_for_incoming/$', 'get_cc_for_incoming', name='get_cc_for_incoming'),
2628
)

ietf/liaisons/utils.py

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
from ietf.idtracker.models import Area, IETFWG
2+
3+
IETFCHAIR = {'name': u'The IETF Chair', 'address': u'chair@ietf.org'}
4+
IESG = {'name': u'The IESG', 'address': u'iesg@ietf.org'}
5+
IAB = {'name': u'The IAB', 'address': u'iab@iab.org'}
6+
IABCHAIR = {'name': u'The IAB Chair', 'address': u'iab-chair@iab.org'}
7+
IABEXECUTIVEDIRECTOR = {'name': u'The IAB Executive Director', 'address': u'execd@iab.org'}
8+
9+
10+
class FakePerson(object):
11+
12+
def __init__(self, name, address):
13+
self.name = name
14+
self.address = address
15+
16+
def email(self):
17+
return (self.name, self.address)
18+
19+
20+
class IETFEntity(object):
21+
22+
def __init__(self, name, poc=None, obj=None, cc=None):
23+
self.name = name
24+
self.poc = poc
25+
self.cc = cc
26+
self.obj = obj
27+
28+
def get_poc(self):
29+
if not isinstance(self.poc, list):
30+
return [self.poc]
31+
return self.poc
32+
33+
def get_cc(self):
34+
if not isinstance(self.cc, list):
35+
return [self.cc]
36+
return self.cc
37+
38+
39+
class AreaEntity(IETFEntity):
40+
41+
def get_poc(self):
42+
return [i.person for i in self.obj.areadirector_set.all()]
43+
44+
def get_cc(self):
45+
return [FakePerson(**IETFCHAIR)]
46+
47+
48+
class WGEntity(IETFEntity):
49+
50+
def get_poc(self):
51+
return [i.person for i in self.obj.wgchair_set.all()]
52+
53+
def get_cc(self):
54+
result = [i.person for i in self.obj.area_directors()]
55+
if self.obj.email_address:
56+
result.append(FakePerson(name ='%s Discussion List' % self.obj.group_acronym.name,
57+
address = self.obj.email_address))
58+
return result
59+
60+
61+
class IETFEntityManager(object):
62+
63+
def __init__(self, pk=None, name=None, queryset=None, poc=None, cc=None):
64+
self.pk = pk
65+
self.name = name
66+
self.queryset = queryset
67+
self.poc = poc
68+
self.cc = cc
69+
70+
def get_entity(self, pk=None):
71+
return IETFEntity(name=self.name, poc=self.poc, cc=self.cc)
72+
73+
def get_managed_list(self):
74+
return [(self.pk, self.name)]
75+
76+
77+
class AreaEntityManager(IETFEntityManager):
78+
79+
def __init__(self, pk=None, name=None, queryset=None, poc=None):
80+
super(AreaEntityManager, self).__init__(pk, name, queryset, poc)
81+
if self.queryset == None:
82+
self.queryset = Area.active_areas()
83+
84+
def get_managed_list(self):
85+
return [(u'%s_%s' % (self.pk, i.pk), i.area_acronym.name) for i in self.queryset]
86+
87+
def get_entity(self, pk=None):
88+
if not pk:
89+
return None
90+
try:
91+
obj = self.queryset.get(pk=pk)
92+
except self.queryset.model.DoesNotExist:
93+
return None
94+
return AreaEntity(name=obj.area_acronym.name, obj=obj)
95+
96+
97+
class WGEntityManager(IETFEntityManager):
98+
99+
def __init__(self, pk=None, name=None, queryset=None, poc=None):
100+
super(WGEntityManager, self).__init__(pk, name, queryset, poc)
101+
if self.queryset == None:
102+
self.queryset = IETFWG.objects.filter(group_type=1, status=IETFWG.ACTIVE, areagroup__area__status=Area.ACTIVE)
103+
104+
def get_managed_list(self):
105+
return [(u'%s_%s' % (self.pk, i.pk), i.group_acronym.name) for i in self.queryset]
106+
107+
def get_entity(self, pk=None):
108+
if not pk:
109+
return None
110+
try:
111+
obj = self.queryset.get(pk=pk)
112+
except self.queryset.model.DoesNotExist:
113+
return None
114+
return WGEntity(name=obj.group_acronym.name, obj=obj)
115+
116+
117+
class IETFHierarchyManager(object):
118+
119+
def __init__(self):
120+
self.managers = {'ietf': IETFEntityManager(pk='ietf', name=u'The IETF',
121+
poc=FakePerson(**IETFCHAIR),
122+
cc=FakePerson(**IESG)),
123+
'iesg': IETFEntityManager(pk='iesg', name=u'The IESG',
124+
poc=FakePerson(**IETFCHAIR),
125+
cc=FakePerson(**IESG)),
126+
'iab': IETFEntityManager(pk='iab', name=u'The IAB',
127+
poc=[FakePerson(**IABCHAIR),
128+
FakePerson(**IABEXECUTIVEDIRECTOR)],
129+
cc=FakePerson(**IAB)),
130+
'area': AreaEntityManager(pk='area'),
131+
'wg': WGEntityManager(pk='wg'),
132+
}
133+
134+
def get_entity_by_key(self, entity_id):
135+
id_list = entity_id.split('_', 1)
136+
key = id_list[0]
137+
pk = None
138+
if len(id_list)==2:
139+
pk = id_list[1]
140+
if key not in self.managers.keys():
141+
return None
142+
return self.managers[key].get_entity(pk)
143+
144+
def get_all_entities(self):
145+
entities = []
146+
for manager in self.managers.values():
147+
entities += manager.get_managed_list()
148+
return entities

ietf/liaisons/views.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Copyright The IETF Trust 2007, All Rights Reserved
22
from django.shortcuts import render_to_response
3+
from django.http import HttpResponse
34
from django.template import RequestContext
5+
from django.utils import simplejson
46

57
from ietf.liaisons.decorators import can_submit_liaison
68
from ietf.liaisons.forms import liaison_form_factory
9+
from ietf.liaisons.utils import IETFHierarchyManager
710

811

912
@can_submit_liaison
@@ -15,3 +18,33 @@ def add_liaison(request):
1518
{'form': form},
1619
context_instance=RequestContext(request),
1720
)
21+
22+
23+
@can_submit_liaison
24+
def get_poc_for_incoming(request):
25+
entity_id = request.GET.get('entity_id', None)
26+
if not entity_id:
27+
result = {'poc': None, 'error': 'No entity id'}
28+
else:
29+
entity = IETFHierarchyManager().get_entity_by_key(entity_id)
30+
if not entity:
31+
result = {'poc': None, 'error': 'Invalid entity id'}
32+
else:
33+
result = {'error': False, 'poc': [i.email() for i in entity.get_poc()]}
34+
json_result = simplejson.dumps(result)
35+
return HttpResponse(json_result, mimetype='text/javascript')
36+
37+
38+
@can_submit_liaison
39+
def get_cc_for_incoming(request):
40+
entity_id = request.GET.get('to_entity_id', None)
41+
if not entity_id:
42+
result = {'cc': None, 'error': 'No entity id'}
43+
else:
44+
entity = IETFHierarchyManager().get_entity_by_key(entity_id)
45+
if not entity:
46+
result = {'cc': None, 'error': 'Invalid entity id'}
47+
else:
48+
result = {'error': False, 'cc': [i.email() for i in entity.get_cc()]}
49+
json_result = simplejson.dumps(result)
50+
return HttpResponse(json_result, mimetype='text/javascript')

ietf/liaisons/widgets.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from django.forms.widgets import Select, Widget
2+
from django.utils.safestring import mark_safe
3+
4+
5+
class FromWidget(Select):
6+
7+
def render(self, name, value, attrs=None, choices=()):
8+
all_choices = list(self.choices) + list(choices)
9+
if len(all_choices)!=1:
10+
base = super(FromWidget, self).render(name, value, attrs, choices)
11+
else:
12+
base = u'<input type="hidden" value="%s" />%s' % all_choices[0]
13+
base += u' (<a class="from_mailto" href="">' + self.submitter + u'</a>)'
14+
return mark_safe(base)
15+
16+
17+
class ReadOnlyWidget(Widget):
18+
19+
def render(self, name, value, attrs=None):
20+
html = u'<div id="id_%s">%s</div>' % (name, value or '')
21+
return mark_safe(html)

ietf/templates/liaisons/liaisondetail_edit.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
{% block title %}Liaison Statement: {% include 'liaisons/liaison_title.html' %}{% endblock %}
55

66
{% block pagehead %}
7-
<meta name="description" content="Liaison Statement from {{ object.from_body }}{% if not object.by_secretariat %} to {{object.to_body}}{% endif %} ({{ object.submitted_date|date:"Y" }})" />
7+
{{ form.media }}
88
{% endblock %}
99

1010
{% block content %}
11-
<h1>Liaison Statement: {% include 'liaisons/liaison_title.html' %}</h1>
11+
<h1>Send Liaison Statement</h1>
1212

13-
<table>
1413
{{ form }}
15-
</table>
1614

1715
{% endblock %}
Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,46 @@
11
{% load i18n %}
2-
{% block content %}
2+
3+
<form class="liaisonform" method="post" action="">
4+
5+
<div class="formconfig" style="display: none;">
6+
{% block formconfig %}
7+
<span class="poc_update_url">{% url get_poc_for_incoming %}</span>
8+
<span class="cc_update_url">{% url get_cc_for_incoming %}</span>
9+
{% endblock %}
10+
</div>
311

412
<div class="baseform">
513
{% for fieldset in form.get_fieldsets %}
6-
{% if fieldset.name %}
7-
<fieldset>
8-
<legend>{{ fieldset.name }}</legend>
9-
{% endif %}
10-
{% for field in fieldset.fields %}
11-
<div id="baseform-fieldname-{{ field.html_name }}" class="{% if field.errors %}error {% endif %}field BaseFormStringWidget{% if field.field.column_style %} {{ field.field.column_style }}{% endif %}">
12-
<label for="id_{{ field.html_name }}">{{ field.label }}</label>
13-
{% if field.field.required %}
14-
<span class="fieldRequired" title="Required"></span>
14+
{% if fieldset.name %}
15+
<div class="fieldset">
16+
<h2>{{ fieldset.name }}</h2>
17+
{% endif %}
18+
19+
{% for field in fieldset.fields %}
20+
<div id="baseform-fieldname-{{ field.html_name }}"
21+
class="{% if field.errors %}error {% endif %}field BaseFormStringWidget{% if field.field.column_style %} {{ field.field.column_style }}{% endif %}">
22+
<label for="id_{{ field.html_name }}">{{ field.label }}</label>
23+
{% if field.field.required %}
24+
<span class="fieldRequired" title="Required"></span>
25+
{% endif %}
26+
<div class="fieldWidget">
27+
{{ field.errors }}
28+
<div id="{{ field.html_name }}_help" class="formHelp"> {{ field.help_text }}</div>
29+
{{ field }}
30+
</div>
31+
<div class="endfield"></div>
32+
</div>
33+
{% endfor %}
34+
35+
{% if fieldset.name %}
36+
</div>
1537
{% endif %}
16-
{{ field.errors }}
17-
<div id="{{ field.html_name }}_help" class="formHelp"> {{ field.help_text }}</div>
18-
{{ field }}
19-
</div>
20-
{% endfor %}
21-
{% if fieldset.name %}
22-
</fieldset>
23-
{% endif %}
2438
{% endfor %}
25-
{% endblock %}
39+
40+
</div>
41+
42+
<div class="submitrow">
43+
<input type="submit" value="Send and Post" name="send" />
44+
<input type="submit" value="Post Only" name="post_only" />
2645
</div>
46+
</form>

0 commit comments

Comments
 (0)