Skip to content

Commit b9e1753

Browse files
committed
Port and proxy liaison views to new schema and add a bunch of tests
- Legacy-Id: 3350
1 parent bbe9596 commit b9e1753

16 files changed

Lines changed: 423 additions & 151 deletions

ietf/liaisons/accountsREDESIGN.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
from redesign.person.models import Person
22
from redesign.group.models import Role
3-
3+
from ietf.liaisons.proxy import proxy_personify_role
44

55
LIAISON_EDIT_GROUPS = ['Secretariat'] # this is not working anymore, refers to old auth model
66

77

88
def get_ietf_chair():
99
try:
10-
return Person.objects.get(email__role__name="chair", email__role__group__acronym="ietf")
11-
except Person.DoesNotExist:
10+
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="ietf"))
11+
except Role.DoesNotExist:
1212
return None
1313

1414

@@ -18,14 +18,14 @@ def get_iesg_chair():
1818

1919
def get_iab_chair():
2020
try:
21-
return Person.objects.get(email__role__name="chair", email__role__group__acronym="iab")
22-
except Person.DoesNotExist:
21+
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="iab"))
22+
except Role.DoesNotExist:
2323
return None
2424

2525

2626
def get_iab_executive_director():
2727
try:
28-
return Person.objects.get(email__role__name="execdir", email__role__group__acronym="iab")
28+
return proxy_personify_role(Role.objects.get(name="execdir", group__acronym="iab"))
2929
except Person.DoesNotExist:
3030
return None
3131

ietf/liaisons/feeds.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Copyright The IETF Trust 2007, All Rights Reserved
22

3+
from django.conf import settings
34
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
45
from django.utils.feedgenerator import Atom1Feed
56
from django.db.models import Q
@@ -8,6 +9,9 @@
89
from datetime import datetime, time
910
import re
1011

12+
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
13+
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
14+
1115
# A slightly funny feed class, the 'object' is really
1216
# just a dict with some parameters that items() uses
1317
# to construct a queryset.
@@ -24,6 +28,15 @@ def get_object(self, bits):
2428
if bits[0] == 'from':
2529
if len(bits) != 2:
2630
raise FeedDoesNotExist
31+
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
32+
from redesign.group.models import Group
33+
try:
34+
group = Group.objects.get(acronym=bits[1])
35+
obj['filter'] = { 'from_group': group }
36+
obj['title'] = u'Liaison Statements from %s' % group.name
37+
return obj
38+
except Group.DoesNotExist:
39+
raise FeedDoesNotExist
2740
try:
2841
acronym = Acronym.objects.get(acronym=bits[1])
2942
obj['filter'] = {'from_id': acronym.acronym_id}
@@ -49,16 +62,22 @@ def get_object(self, bits):
4962
if bits[0] == 'to':
5063
if len(bits) != 2:
5164
raise FeedDoesNotExist
52-
# The schema uses two different fields for the same
53-
# basic purpose, depending on whether it's a Secretariat-submitted
54-
# or Liaison-tool-submitted document.
55-
obj['q'] = [ (Q(by_secretariat=0) & Q(to_body__icontains=bits[1])) | (Q(by_secretariat=1) & Q(submitter_name__icontains=bits[1])) ]
65+
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
66+
obj['filter'] = dict(to_name__icontains=bits[1])
67+
else:
68+
# The schema uses two different fields for the same
69+
# basic purpose, depending on whether it's a Secretariat-submitted
70+
# or Liaison-tool-submitted document.
71+
obj['q'] = [ (Q(by_secretariat=0) & Q(to_body__icontains=bits[1])) | (Q(by_secretariat=1) & Q(submitter_name__icontains=bits[1])) ]
5672
obj['title'] = 'Liaison Statements where to matches %s' % bits[1]
5773
return obj
5874
if bits[0] == 'subject':
5975
if len(bits) != 2:
6076
raise FeedDoesNotExist
61-
obj['q'] = [ Q(title__icontains=bits[1]) | Q(uploads__file_title__icontains=bits[1]) ]
77+
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
78+
obj['q'] = [ Q(title__icontains=bits[1]) | Q(attachments__title__icontains=bits[1]) ]
79+
else:
80+
obj['q'] = [ Q(title__icontains=bits[1]) | Q(uploads__file_title__icontains=bits[1]) ]
6281
obj['title'] = 'Liaison Statements where subject matches %s' % bits[1]
6382
return obj
6483
raise FeedDoesNotExist

ietf/liaisons/formsREDESIGN.py

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import datetime
1+
import datetime, os
22
from email.utils import parseaddr
33

44
from django import forms
@@ -14,11 +14,14 @@
1414
from ietf.liaisons.widgets import (FromWidget, ReadOnlyWidget, ButtonWidget,
1515
ShowAttachmentsWidget, RelatedLiaisonWidget)
1616
from ietf.liaisons.models import LiaisonStatement, LiaisonStatementPurposeName
17+
from ietf.liaisons.proxy import LiaisonDetailProxy
1718
from redesign.group.models import Group
1819
from redesign.person.models import Person
20+
from redesign.doc.models import Document
1921

2022

2123
class LiaisonForm(forms.Form):
24+
person = forms.ModelChoiceField(Person.objects.all())
2225
from_field = forms.ChoiceField(widget=FromWidget, label=u'From')
2326
replyto = forms.CharField(label=u'Reply to')
2427
organization = forms.ChoiceField()
@@ -64,15 +67,16 @@ def __init__(self, user, *args, **kwargs):
6467
self.fake_person = None
6568
self.person = get_person_for_user(user)
6669
if kwargs.get('data', None):
67-
kwargs['data'].update({'person': self.person.pk})
6870
if is_secretariat(self.user) and 'from_fake_user' in kwargs['data'].keys():
6971
self.fake_person = Person.objects.get(pk=kwargs['data']['from_fake_user'])
7072
kwargs['data'].update({'person': self.fake_person.pk})
73+
else:
74+
kwargs['data'].update({'person': self.person.pk})
7175

7276
self.instance = kwargs.pop("instance", None)
7377

7478
super(LiaisonForm, self).__init__(*args, **kwargs)
75-
79+
7680
# now copy in values from instance, like a ModelForm
7781
if self.instance:
7882
for name, field in self.fields.iteritems():
@@ -120,8 +124,7 @@ def set_from_field(self):
120124
assert NotImplemented
121125

122126
def set_replyto_field(self):
123-
email = self.person.email_address()
124-
self.fields['replyto'].initial = email
127+
self.fields['replyto'].initial = self.person.email()[1]
125128

126129
def set_organization_field(self):
127130
assert NotImplemented
@@ -193,7 +196,7 @@ def get_to_entity(self):
193196
return self.hm.get_entity_by_key(organization_key)
194197

195198
def get_poc(self, organization):
196-
return ', '.join([i.email_address() for i in organization.get_poc()])
199+
return ', '.join(u"%s <%s>" % i.email() for i in organization.get_poc())
197200

198201
def clean_cc1(self):
199202
value = self.cleaned_data.get('cc1', '')
@@ -223,7 +226,7 @@ def get_cc(self, from_entity, to_entity):
223226
def save(self, *args, **kwargs):
224227
l = self.instance
225228
if not l:
226-
l = LiaisonStatement()
229+
l = LiaisonDetailProxy()
227230

228231
l.title = self.cleaned_data["title"]
229232
l.purpose = LiaisonStatementPurposeName.objects.get(order=self.cleaned_data["purpose"])
@@ -238,35 +241,31 @@ def save(self, *args, **kwargs):
238241

239242
l.modified = now
240243
l.submitted = datetime.datetime.combine(self.cleaned_data["submitted_date"], now.time())
241-
if self.cleaned_data.get("approval"): # FIXME
242-
if not l.approved:
243-
l.approved = now
244+
if not l.approved:
245+
l.approved = now
244246

245247
self.save_extra_fields(l)
248+
246249
l.save() # we have to save here to make sure we get an id for the attachments
247250
self.save_attachments(l)
248251

249252
return l
250253

251254
def save_extra_fields(self, liaison):
252255
from_entity = self.get_from_entity()
253-
print from_entity, type(from_entity)
254-
print self.cleaned_data.get("from_field")
255-
liason.from_name = from_entity.name
256-
print from_entity.obj # FIXME? c.get("from_field")
257-
liason.from_group = from_entity.obj
258-
liason.from_contact = self.person # FIXME?
256+
liaison.from_name = from_entity.name
257+
liaison.from_group = from_entity.obj
258+
liaison.from_contact = self.cleaned_data["person"].email_address()
259259

260260
organization = self.get_to_entity()
261-
liason.to_name = organization.name
262-
print organization.obj # FIXME? self.cleaned_data.get('organization')
263-
liason.to_group = organization.obj
264-
liason.to_contact = self.get_poc(organization)
265-
261+
liaison.to_name = organization.name
262+
liaison.to_group = organization.obj
263+
liaison.to_contact = self.get_poc(organization)
264+
266265
liaison.cc = self.get_cc(from_entity, organization)
267266

268267
def save_attachments(self, instance):
269-
return # FIXME
268+
written = instance.attachments.all().count()
270269
for key in self.files.keys():
271270
title_key = key.replace('file', 'title')
272271
if not key.startswith('attach_file_') or not title_key in self.data.keys():
@@ -277,13 +276,16 @@ def save_attachments(self, instance):
277276
extension = '.' + extension[1]
278277
else:
279278
extension = ''
280-
attach = Uploads.objects.create(
281-
file_title = self.data.get(title_key),
282-
person = self.person,
283-
detail = instance,
284-
file_extension = extension,
279+
written += 1
280+
name = instance.name() + ("-attachment-%s" % written)
281+
attach = Document.objects.create(
282+
title = self.data.get(title_key),
283+
type_id = "liaison",
284+
name = name,
285+
external_url = name + extension, # strictly speaking not necessary, but just for the time being ...
285286
)
286-
attach_file = open('%sfile%s%s' % (settings.LIAISON_ATTACH_PATH, attach.pk, attach.file_extension), 'w')
287+
instance.attachments.add(attach)
288+
attach_file = open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'w')
287289
attach_file.write(attached_file.read())
288290
attach_file.close()
289291

@@ -380,21 +382,13 @@ def get_poc(self, organization):
380382
return self.cleaned_data['to_poc']
381383

382384
def save_extra_fields(self, liaison):
383-
raise NotImplemented
384385
super(OutgoingLiaisonForm, self).save_extra_fields(liaison)
385386
from_entity = self.get_from_entity()
386387
needs_approval = from_entity.needs_approval(self.person)
387388
if not needs_approval or self.cleaned_data.get('approved', False):
388-
approved = True
389-
approval_date = datetime.datetime.now()
389+
liaison.approved = datetime.datetime.now()
390390
else:
391-
approved = False
392-
approval_date = None
393-
approval = OutgoingLiaisonApproval.objects.create(
394-
approved = approved,
395-
approval_date = approval_date)
396-
liaison.approval = approval
397-
liaison.save()
391+
liaison.approved = None
398392

399393
def clean_to_poc(self):
400394
value = self.cleaned_data.get('to_poc', None)

ietf/liaisons/mails.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from django.conf import settings
2+
from django.template.loader import render_to_string
3+
from django.core.urlresolvers import reverse as urlreverse
4+
5+
from ietf.liaisons.mail import IETFEmailMessage
6+
7+
def send_liaison_by_email(liaison, fake=False):
8+
if not liaison.is_pending(): # this conditional should definitely be at the caller, not here
9+
return notify_pending_by_email(liaison, fake)
10+
11+
subject = u'New Liaison Statement, "%s"' % (liaison.title)
12+
from_email = settings.LIAISON_UNIVERSAL_FROM
13+
to_email = liaison.to_poc.split(',')
14+
cc = liaison.cc1.split(',')
15+
if liaison.technical_contact:
16+
cc += liaison.technical_contact.split(',')
17+
if liaison.response_contact:
18+
cc += liaison.response_contact.split(',')
19+
bcc = ['statements@ietf.org']
20+
body = render_to_string('liaisons/liaison_mail.txt',
21+
{'liaison': liaison,
22+
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk))
23+
})
24+
mail = IETFEmailMessage(subject=subject,
25+
to=to_email,
26+
from_email=from_email,
27+
cc = cc,
28+
bcc = bcc,
29+
body = body)
30+
# rather than this fake stuff, it's probably better to start a
31+
# debug SMTP server as explained in the Django docs
32+
if not fake:
33+
mail.send()
34+
return mail
35+
36+
def notify_pending_by_email(liaison, fake):
37+
from ietf.liaisons.utils import IETFHM
38+
39+
from_entity = IETFHM.get_entity_by_key(liaison.from_raw_code)
40+
if not from_entity:
41+
return None
42+
to_email = []
43+
for person in from_entity.can_approve():
44+
to_email.append('%s <%s>' % person.email())
45+
subject = u'New Liaison Statement, "%s" needs your approval' % (liaison.title)
46+
from_email = settings.LIAISON_UNIVERSAL_FROM
47+
body = render_to_string('liaisons/pending_liaison_mail.txt',
48+
{'liaison': liaison,
49+
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk)),
50+
'approve_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk))
51+
})
52+
mail = IETFEmailMessage(subject=subject,
53+
to=to_email,
54+
from_email=from_email,
55+
body = body)
56+
if not fake:
57+
mail.send()
58+
return mail
59+

ietf/liaisons/models.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from django.db import models
66
from django.template.loader import render_to_string
77
from django.contrib.auth.models import User
8+
from django.core.urlresolvers import reverse as urlreverse
89
from ietf.idtracker.models import Acronym, PersonOrOrgInfo, Area, IESGLogin
910
from ietf.liaisons.mail import IETFEmailMessage
1011
from ietf.ietfauth.models import LegacyLiaisonUser
@@ -143,6 +144,7 @@ def notify_pending_by_email(self, fake):
143144
from_email = settings.LIAISON_UNIVERSAL_FROM
144145
body = render_to_string('liaisons/pending_liaison_mail.txt',
145146
{'liaison': self,
147+
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk))
146148
})
147149
mail = IETFEmailMessage(subject=subject,
148150
to=to_email,
@@ -166,6 +168,8 @@ def send_by_email(self, fake=False):
166168
bcc = ['statements@ietf.org']
167169
body = render_to_string('liaisons/liaison_mail.txt',
168170
{'liaison': self,
171+
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk)),
172+
'approve_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk))
169173
})
170174
mail = IETFEmailMessage(subject=subject,
171175
to=to_email,
@@ -289,6 +293,8 @@ class Uploads(models.Model):
289293
detail = models.ForeignKey(LiaisonDetail)
290294
def __str__(self):
291295
return self.file_title
296+
def filename(self):
297+
return "file%s%s" % (self.file_id, self.file_extension)
292298
class Meta:
293299
db_table = 'uploads'
294300

@@ -320,12 +326,12 @@ class LiaisonStatement(models.Model):
320326

321327
related_to = models.ForeignKey('LiaisonStatement', blank=True, null=True)
322328

323-
from_group = models.ForeignKey(Group, related_name="liaisonstatement_from_set", null=True, blank=True, help_text="From body, if it exists")
329+
from_group = models.ForeignKey(Group, related_name="liaisonstatement_from_set", null=True, blank=True, help_text="Sender group, if it exists")
324330
from_name = models.CharField(max_length=255, help_text="Name of the sender body")
325331
from_contact = models.ForeignKey(Email, blank=True, null=True)
326-
to_group = models.ForeignKey(Group, related_name="liaisonstatement_to_set", null=True, blank=True, help_text="To body, if it exists")
332+
to_group = models.ForeignKey(Group, related_name="liaisonstatement_to_set", null=True, blank=True, help_text="Recipient group, if it exists")
327333
to_name = models.CharField(max_length=255, help_text="Name of the recipient body")
328-
to_contact = models.CharField(blank=True, max_length=255, help_text="Contacts at to body")
334+
to_contact = models.CharField(blank=True, max_length=255, help_text="Contacts at recipient body")
329335

330336
reply_to = models.CharField(blank=True, max_length=255)
331337

0 commit comments

Comments
 (0)