Skip to content

Commit c7d198f

Browse files
committed
Merged from log:branch/yaco/liaison@2570: Yaco's port and rewrite of the Liaison Statement Management Tool.
- Legacy-Id: 2572
2 parents dc41ea6 + de72df1 commit c7d198f

67 files changed

Lines changed: 4843 additions & 75 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

changelog

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,70 @@
1+
ietfdb (3.07)
2+
3+
From esanchez@yaco.es:
4+
5+
* Merged in Yaco's Liaison Management Tool Port & Rewrite. Enjoy!
6+
7+
Note: Deploying this release requires additional steps; to verify
8+
that liaison related settings in settings.py are correct, and to create
9+
new tables and update existing tables and table content. The latter
10+
is done as South migrations (see http://south.aeracode.org/ for more
11+
info on the South app). More extensiive documentation about the actions
12+
needed are provided in the user manual (doc/LSMT_user_manual.pdf in
13+
the release). The brief version follows:
14+
15+
# 8<----------
16+
# First the regular checkout and prepare:
17+
18+
cd /a/www/ietf-datatracker
19+
svn co http://svn.tools.ietf.org/svn/tools/ietfdb/tags/3.07
20+
cp web/ietf/settings_local.py 3.07/ietf/
21+
cd 3.07
22+
23+
# Verify that the new variables in settings.py are correct; if not,
24+
# add the correct settings in settings_local.py and inform the release
25+
# manager of the correct settings so they can be incorporated in the
26+
# next release. The variables in question are (as set in the release):
27+
#
28+
# # The email address from wich all liaison emails come:
29+
# LIAISON_UNIVERSAL_FROM = 'Liaison Statement Management Tool <lsmt@' + IETF_DOMAIN + '>'
30+
#
31+
# # The filesystem path where the liaison attachments will be saved:
32+
# LIAISON_ATTACH_PATH = '/a/www/ietf-datatracker/documents/LIAISON/'
33+
#
34+
# # The url from where the webserver serves the liaison attachments
35+
# LIAISON_ATTACH_URL = '/documents/LIAISON/'
36+
37+
# Next, the changes to the MySQL tables will be done.
38+
# You can list the table migrations which will be applied if desired,
39+
# this should list migrations from 0001_... to 0009_... under liaisons:
40+
41+
PYTHONPATH=$PWD ietf/manage.py migrate --list
42+
43+
# Apply the migrations:
44+
45+
PYTHONPATH=$PWD ietf/manage.py migrate
46+
47+
# Then carry on with the usual actions:
48+
49+
cd ../
50+
rm ./web; ln -s 3.07 web
51+
sudo /etc/init.d/apache restart
52+
53+
# 8<----------
54+
55+
Once the datatracker is up and running with the new liaison tool in
56+
place, liaison role assignments have to be done as described in
57+
the LSMT user manual (in doc/LSMT_user_manual.pdf) page 14, summarized
58+
by Patrik on the yaco-liaison-tool mailing list:
59+
60+
1. Add the IAB and IETF chairs, wg chairs, area directors etc as
61+
apropriate (as described in the document).
62+
63+
2. Add the liaisons in the IETF assigned and named on the IAB list of
64+
liaisons.
65+
66+
-- Henrik Levkowetz <henrik@levkowetz.com> 22 Oct 2010 13:59:04 +0200
67+
168
ietfdb (3.06)
269

370
From rjsparks@nostrum.com:

doc/LSMT_user_manual.pdf

1.17 MB
Binary file not shown.

ietf/ietfauth/auth.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939

4040
from ietf.utils import log
4141

42+
AUTOMATIC_GROUPS = ["Area_Director", "Secretariat", "IETF_Chair",
43+
"IAB_Chair", "IRTF_Chair", ]
44+
4245
class IetfUserBackend(RemoteUserBackend):
4346

4447
def find_groups(username):
@@ -56,6 +59,8 @@ def find_groups(username):
5659
Session_Chair chairing a non-WG session in IETF meeting
5760
Ex_Area_Director past AD
5861
"""
62+
# Any group name added by this method should be added to the
63+
# AUTOMATIC_GROUPS list
5964
groups = []
6065
try:
6166
login = IESGLogin.objects.get(login_name=username)
@@ -94,9 +99,12 @@ def authenticate(self, remote_user):
9499
profile = IetfUserProfile(user=user)
95100
profile.save()
96101

102+
# Remove any automatic groups, the proper ones will be retrieved by
103+
# find_groups
104+
groups = [group for group in user.groups.exclude(name__in=AUTOMATIC_GROUPS)]
105+
97106
# Update group memberships
98107
group_names = IetfUserBackend.find_groups(user.username)
99-
groups = []
100108
for group_name in group_names:
101109
# Create groups as needed
102110
group,created = Group.objects.get_or_create(name=group_name)
@@ -105,4 +113,3 @@ def authenticate(self, remote_user):
105113
groups.append(group)
106114
user.groups = groups
107115
return user
108-

ietf/liaisons/accounts.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
from ietf.idtracker.models import Role, PersonOrOrgInfo
2+
3+
4+
LIAISON_EDIT_GROUPS = ['Liaison_Manager', 'Secretariat']
5+
6+
def get_ietf_chair():
7+
person = PersonOrOrgInfo.objects.filter(role=Role.IETF_CHAIR)
8+
return person and person[0] or None
9+
10+
11+
def get_iesg_chair():
12+
return get_ietf_chair()
13+
14+
15+
def get_iab_chair():
16+
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_CHAIR)
17+
return person and person[0] or None
18+
19+
20+
def get_iab_executive_director():
21+
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_EXCUTIVE_DIRECTOR)
22+
return person and person[0] or None
23+
24+
25+
def get_person_for_user(user):
26+
try:
27+
return user.get_profile().person()
28+
except:
29+
return None
30+
31+
32+
def is_areadirector(person):
33+
return bool(person.areadirector_set.all())
34+
35+
36+
def is_wgchair(person):
37+
return bool(person.wgchair_set.all())
38+
39+
40+
def is_wgsecretary(person):
41+
return bool(person.wgsecretary_set.all())
42+
43+
44+
def has_role(person, role):
45+
return bool(person.role_set.filter(pk=role))
46+
47+
48+
def is_ietfchair(person):
49+
return has_role(person, Role.IETF_CHAIR)
50+
51+
52+
def is_iabchair(person):
53+
return has_role(person, Role.IAB_CHAIR)
54+
55+
56+
def is_iab_executive_director(person):
57+
return has_role(person, Role.IAB_EXCUTIVE_DIRECTOR)
58+
59+
60+
def can_add_outgoing_liaison(user):
61+
person = get_person_for_user(user)
62+
if not person:
63+
return False
64+
65+
if (is_areadirector(person) or is_wgchair(person) or
66+
is_wgsecretary(person) or is_ietfchair(person) or
67+
is_iabchair(person) or is_iab_executive_director(person) or
68+
is_ietf_liaison_manager(user)):
69+
return True
70+
return False
71+
72+
73+
def is_sdo_liaison_manager(person):
74+
return bool(person.liaisonmanagers_set.all())
75+
76+
77+
def is_sdo_authorized_individual(person):
78+
return bool(person.sdoauthorizedindividual_set.all())
79+
80+
81+
def is_ietf_liaison_manager(user):
82+
return bool(user.groups.filter(name='Liaison_Manager'))
83+
84+
85+
def can_add_incoming_liaison(user):
86+
person = get_person_for_user(user)
87+
if not person:
88+
return False
89+
90+
if (is_sdo_liaison_manager(person) or
91+
is_sdo_authorized_individual(person) or
92+
is_ietf_liaison_manager(user)):
93+
return True
94+
return False
95+
96+
97+
def can_add_liaison(user):
98+
return can_add_incoming_liaison(user) or can_add_outgoing_liaison(user)

ietf/liaisons/admin.py

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,123 @@
11
#coding: utf-8
2+
from django import template
23
from django.contrib import admin
3-
from ietf.liaisons.models import *
4-
4+
from django.contrib.admin.util import unquote
5+
from django.core.exceptions import PermissionDenied
6+
from django.core.management import load_command_class
7+
from django.http import Http404
8+
from django.shortcuts import render_to_response
9+
from django.utils.encoding import force_unicode
10+
from django.utils.functional import update_wrapper
11+
from django.utils.html import escape
12+
from django.utils.translation import ugettext as _
13+
14+
from ietf.liaisons.models import (FromBodies, LiaisonDetail, LiaisonPurpose,
15+
SDOs, LiaisonManagers, SDOAuthorizedIndividual)
16+
17+
518
class FromBodiesAdmin(admin.ModelAdmin):
619
pass
7-
admin.site.register(FromBodies, FromBodiesAdmin)
20+
821

922
class LiaisonDetailAdmin(admin.ModelAdmin):
10-
pass
11-
admin.site.register(LiaisonDetail, LiaisonDetailAdmin)
23+
ordering = ('title', )
24+
fields = ('title', 'body','submitted_date', 'last_modified_date', 'to_email', 'cc1', 'cc2', 'to_poc',
25+
'response_contact', 'technical_contact', 'purpose', 'purpose_text', 'deadline_date', 'taken_care',
26+
'related_to')
27+
raw_id_fields=['related_to']
1228

1329
class LiaisonPurposeAdmin(admin.ModelAdmin):
14-
pass
15-
admin.site.register(LiaisonPurpose, LiaisonPurposeAdmin)
30+
ordering = ('purpose_text', )
31+
32+
33+
class LiaisonManagersInline(admin.TabularInline):
34+
model = LiaisonManagers
35+
raw_id_fields=['person']
36+
37+
38+
class SDOAuthorizedIndividualInline(admin.TabularInline):
39+
model = SDOAuthorizedIndividual
40+
raw_id_fields=['person']
41+
42+
43+
class LiaisonManagersAdmin(admin.ModelAdmin):
44+
ordering = ('person__first_name', 'person__last_name' )
45+
fields = ('person', 'sdo')
46+
raw_id_fields=['person']
47+
48+
49+
class SDOAuthorizedIndividualAdmin(admin.ModelAdmin):
50+
raw_id_fields=['person']
51+
1652

53+
class SDOsAdmin(admin.ModelAdmin):
54+
inlines = [LiaisonManagersInline, SDOAuthorizedIndividualInline]
55+
56+
def get_urls(self):
57+
from django.conf.urls.defaults import patterns, url
58+
59+
def wrap(view):
60+
def wrapper(*args, **kwargs):
61+
return self.admin_site.admin_view(view)(*args, **kwargs)
62+
return update_wrapper(wrapper, view)
63+
64+
info = self.model._meta.app_label, self.model._meta.module_name
65+
66+
urls = patterns('',
67+
url(r'^reminder/$',
68+
wrap(self.send_reminder),
69+
name='%s_%s_reminder' % info),
70+
url(r'^(.+)/reminder/$',
71+
wrap(self.send_one_reminder),
72+
name='%s_%s_one_reminder' % info),
73+
)
74+
urls += super(SDOsAdmin, self).get_urls()
75+
return urls
76+
77+
def send_reminder(self, request, sdo=None):
78+
opts = self.model._meta
79+
app_label = opts.app_label
80+
81+
output = None
82+
sdo_pk = sdo and sdo.pk or None
83+
if request.method == 'POST' and request.POST.get('send', False):
84+
command = load_command_class('ietf.liaisons', 'remind_update_sdo_list')
85+
output=command.handle(return_output=True, sdo_pk=sdo_pk)
86+
output='\n'.join(output)
87+
88+
context = {
89+
'opts': opts,
90+
'has_change_permission': self.has_change_permission(request),
91+
'app_label': app_label,
92+
'output': output,
93+
'sdo': sdo,
94+
}
95+
return render_to_response('admin/liaisons/sdos/send_reminder.html',
96+
context,
97+
context_instance = template.RequestContext(request, current_app=self.admin_site.name),
98+
)
99+
100+
def send_one_reminder(self, request, object_id):
101+
model = self.model
102+
opts = model._meta
103+
104+
try:
105+
obj = self.queryset(request).get(pk=unquote(object_id))
106+
except model.DoesNotExist:
107+
obj = None
108+
109+
if not self.has_change_permission(request, obj):
110+
raise PermissionDenied
111+
112+
if obj is None:
113+
raise Http404(_('%(name)s object with primary key %(key)r does not exist.') % {'name': force_unicode(opts.verbose_name), 'key': escape(object_id)})
114+
115+
return self.send_reminder(request, sdo=obj)
116+
117+
118+
#admin.site.register(FromBodies, FromBodiesAdmin)
119+
admin.site.register(LiaisonDetail, LiaisonDetailAdmin)
120+
admin.site.register(LiaisonPurpose, LiaisonPurposeAdmin)
121+
admin.site.register(SDOs, SDOsAdmin)
122+
admin.site.register(LiaisonManagers, LiaisonManagersAdmin)
123+
admin.site.register(SDOAuthorizedIndividual, SDOAuthorizedIndividualAdmin)

ietf/liaisons/decorators.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from ietf.ietfauth.decorators import _CheckLogin403
2+
from ietf.liaisons.accounts import can_add_liaison
3+
4+
5+
def can_submit_liaison(view_func=None):
6+
7+
def decorate(view_func):
8+
return _CheckLogin403(
9+
view_func,
10+
lambda u: can_add_liaison(u),
11+
"Restricted to participants who are authorized to submit liaison statements on behalf of the various IETF entities")
12+
if view_func:
13+
return decorate(view_func)
14+
return decorate

0 commit comments

Comments
 (0)