Port and proxy liaison views to new schema and add a bunch of tests

- Legacy-Id: 3350
This commit is contained in:
Ole Laursen 2011-08-22 23:15:35 +00:00
parent bbe959623b
commit b9e1753ef6
16 changed files with 423 additions and 151 deletions

View file

@ -1,14 +1,14 @@
from redesign.person.models import Person
from redesign.group.models import Role
from ietf.liaisons.proxy import proxy_personify_role
LIAISON_EDIT_GROUPS = ['Secretariat'] # this is not working anymore, refers to old auth model
def get_ietf_chair():
try:
return Person.objects.get(email__role__name="chair", email__role__group__acronym="ietf")
except Person.DoesNotExist:
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="ietf"))
except Role.DoesNotExist:
return None
@ -18,14 +18,14 @@ def get_iesg_chair():
def get_iab_chair():
try:
return Person.objects.get(email__role__name="chair", email__role__group__acronym="iab")
except Person.DoesNotExist:
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="iab"))
except Role.DoesNotExist:
return None
def get_iab_executive_director():
try:
return Person.objects.get(email__role__name="execdir", email__role__group__acronym="iab")
return proxy_personify_role(Role.objects.get(name="execdir", group__acronym="iab"))
except Person.DoesNotExist:
return None

View file

@ -1,5 +1,6 @@
# Copyright The IETF Trust 2007, All Rights Reserved
from django.conf import settings
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
from django.utils.feedgenerator import Atom1Feed
from django.db.models import Q
@ -8,6 +9,9 @@ from ietf.idtracker.models import Acronym
from datetime import datetime, time
import re
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
# A slightly funny feed class, the 'object' is really
# just a dict with some parameters that items() uses
# to construct a queryset.
@ -24,6 +28,15 @@ class Liaisons(Feed):
if bits[0] == 'from':
if len(bits) != 2:
raise FeedDoesNotExist
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from redesign.group.models import Group
try:
group = Group.objects.get(acronym=bits[1])
obj['filter'] = { 'from_group': group }
obj['title'] = u'Liaison Statements from %s' % group.name
return obj
except Group.DoesNotExist:
raise FeedDoesNotExist
try:
acronym = Acronym.objects.get(acronym=bits[1])
obj['filter'] = {'from_id': acronym.acronym_id}
@ -49,16 +62,22 @@ class Liaisons(Feed):
if bits[0] == 'to':
if len(bits) != 2:
raise FeedDoesNotExist
# The schema uses two different fields for the same
# basic purpose, depending on whether it's a Secretariat-submitted
# or Liaison-tool-submitted document.
obj['q'] = [ (Q(by_secretariat=0) & Q(to_body__icontains=bits[1])) | (Q(by_secretariat=1) & Q(submitter_name__icontains=bits[1])) ]
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
obj['filter'] = dict(to_name__icontains=bits[1])
else:
# The schema uses two different fields for the same
# basic purpose, depending on whether it's a Secretariat-submitted
# or Liaison-tool-submitted document.
obj['q'] = [ (Q(by_secretariat=0) & Q(to_body__icontains=bits[1])) | (Q(by_secretariat=1) & Q(submitter_name__icontains=bits[1])) ]
obj['title'] = 'Liaison Statements where to matches %s' % bits[1]
return obj
if bits[0] == 'subject':
if len(bits) != 2:
raise FeedDoesNotExist
obj['q'] = [ Q(title__icontains=bits[1]) | Q(uploads__file_title__icontains=bits[1]) ]
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
obj['q'] = [ Q(title__icontains=bits[1]) | Q(attachments__title__icontains=bits[1]) ]
else:
obj['q'] = [ Q(title__icontains=bits[1]) | Q(uploads__file_title__icontains=bits[1]) ]
obj['title'] = 'Liaison Statements where subject matches %s' % bits[1]
return obj
raise FeedDoesNotExist

View file

@ -1,4 +1,4 @@
import datetime
import datetime, os
from email.utils import parseaddr
from django import forms
@ -14,11 +14,14 @@ from ietf.liaisons.utils import IETFHM
from ietf.liaisons.widgets import (FromWidget, ReadOnlyWidget, ButtonWidget,
ShowAttachmentsWidget, RelatedLiaisonWidget)
from ietf.liaisons.models import LiaisonStatement, LiaisonStatementPurposeName
from ietf.liaisons.proxy import LiaisonDetailProxy
from redesign.group.models import Group
from redesign.person.models import Person
from redesign.doc.models import Document
class LiaisonForm(forms.Form):
person = forms.ModelChoiceField(Person.objects.all())
from_field = forms.ChoiceField(widget=FromWidget, label=u'From')
replyto = forms.CharField(label=u'Reply to')
organization = forms.ChoiceField()
@ -64,15 +67,16 @@ class LiaisonForm(forms.Form):
self.fake_person = None
self.person = get_person_for_user(user)
if kwargs.get('data', None):
kwargs['data'].update({'person': self.person.pk})
if is_secretariat(self.user) and 'from_fake_user' in kwargs['data'].keys():
self.fake_person = Person.objects.get(pk=kwargs['data']['from_fake_user'])
kwargs['data'].update({'person': self.fake_person.pk})
else:
kwargs['data'].update({'person': self.person.pk})
self.instance = kwargs.pop("instance", None)
super(LiaisonForm, self).__init__(*args, **kwargs)
# now copy in values from instance, like a ModelForm
if self.instance:
for name, field in self.fields.iteritems():
@ -120,8 +124,7 @@ class LiaisonForm(forms.Form):
assert NotImplemented
def set_replyto_field(self):
email = self.person.email_address()
self.fields['replyto'].initial = email
self.fields['replyto'].initial = self.person.email()[1]
def set_organization_field(self):
assert NotImplemented
@ -193,7 +196,7 @@ class LiaisonForm(forms.Form):
return self.hm.get_entity_by_key(organization_key)
def get_poc(self, organization):
return ', '.join([i.email_address() for i in organization.get_poc()])
return ', '.join(u"%s <%s>" % i.email() for i in organization.get_poc())
def clean_cc1(self):
value = self.cleaned_data.get('cc1', '')
@ -223,7 +226,7 @@ class LiaisonForm(forms.Form):
def save(self, *args, **kwargs):
l = self.instance
if not l:
l = LiaisonStatement()
l = LiaisonDetailProxy()
l.title = self.cleaned_data["title"]
l.purpose = LiaisonStatementPurposeName.objects.get(order=self.cleaned_data["purpose"])
@ -238,11 +241,11 @@ class LiaisonForm(forms.Form):
l.modified = now
l.submitted = datetime.datetime.combine(self.cleaned_data["submitted_date"], now.time())
if self.cleaned_data.get("approval"): # FIXME
if not l.approved:
l.approved = now
if not l.approved:
l.approved = now
self.save_extra_fields(l)
l.save() # we have to save here to make sure we get an id for the attachments
self.save_attachments(l)
@ -250,23 +253,19 @@ class LiaisonForm(forms.Form):
def save_extra_fields(self, liaison):
from_entity = self.get_from_entity()
print from_entity, type(from_entity)
print self.cleaned_data.get("from_field")
liason.from_name = from_entity.name
print from_entity.obj # FIXME? c.get("from_field")
liason.from_group = from_entity.obj
liason.from_contact = self.person # FIXME?
liaison.from_name = from_entity.name
liaison.from_group = from_entity.obj
liaison.from_contact = self.cleaned_data["person"].email_address()
organization = self.get_to_entity()
liason.to_name = organization.name
print organization.obj # FIXME? self.cleaned_data.get('organization')
liason.to_group = organization.obj
liason.to_contact = self.get_poc(organization)
liaison.to_name = organization.name
liaison.to_group = organization.obj
liaison.to_contact = self.get_poc(organization)
liaison.cc = self.get_cc(from_entity, organization)
def save_attachments(self, instance):
return # FIXME
written = instance.attachments.all().count()
for key in self.files.keys():
title_key = key.replace('file', 'title')
if not key.startswith('attach_file_') or not title_key in self.data.keys():
@ -277,13 +276,16 @@ class LiaisonForm(forms.Form):
extension = '.' + extension[1]
else:
extension = ''
attach = Uploads.objects.create(
file_title = self.data.get(title_key),
person = self.person,
detail = instance,
file_extension = extension,
written += 1
name = instance.name() + ("-attachment-%s" % written)
attach = Document.objects.create(
title = self.data.get(title_key),
type_id = "liaison",
name = name,
external_url = name + extension, # strictly speaking not necessary, but just for the time being ...
)
attach_file = open('%sfile%s%s' % (settings.LIAISON_ATTACH_PATH, attach.pk, attach.file_extension), 'w')
instance.attachments.add(attach)
attach_file = open(os.path.join(settings.LIAISON_ATTACH_PATH, attach.name + extension), 'w')
attach_file.write(attached_file.read())
attach_file.close()
@ -380,21 +382,13 @@ class OutgoingLiaisonForm(LiaisonForm):
return self.cleaned_data['to_poc']
def save_extra_fields(self, liaison):
raise NotImplemented
super(OutgoingLiaisonForm, self).save_extra_fields(liaison)
from_entity = self.get_from_entity()
needs_approval = from_entity.needs_approval(self.person)
if not needs_approval or self.cleaned_data.get('approved', False):
approved = True
approval_date = datetime.datetime.now()
liaison.approved = datetime.datetime.now()
else:
approved = False
approval_date = None
approval = OutgoingLiaisonApproval.objects.create(
approved = approved,
approval_date = approval_date)
liaison.approval = approval
liaison.save()
liaison.approved = None
def clean_to_poc(self):
value = self.cleaned_data.get('to_poc', None)

59
ietf/liaisons/mails.py Normal file
View file

@ -0,0 +1,59 @@
from django.conf import settings
from django.template.loader import render_to_string
from django.core.urlresolvers import reverse as urlreverse
from ietf.liaisons.mail import IETFEmailMessage
def send_liaison_by_email(liaison, fake=False):
if not liaison.is_pending(): # this conditional should definitely be at the caller, not here
return notify_pending_by_email(liaison, fake)
subject = u'New Liaison Statement, "%s"' % (liaison.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
to_email = liaison.to_poc.split(',')
cc = liaison.cc1.split(',')
if liaison.technical_contact:
cc += liaison.technical_contact.split(',')
if liaison.response_contact:
cc += liaison.response_contact.split(',')
bcc = ['statements@ietf.org']
body = render_to_string('liaisons/liaison_mail.txt',
{'liaison': liaison,
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk))
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
from_email=from_email,
cc = cc,
bcc = bcc,
body = body)
# rather than this fake stuff, it's probably better to start a
# debug SMTP server as explained in the Django docs
if not fake:
mail.send()
return mail
def notify_pending_by_email(liaison, fake):
from ietf.liaisons.utils import IETFHM
from_entity = IETFHM.get_entity_by_key(liaison.from_raw_code)
if not from_entity:
return None
to_email = []
for person in from_entity.can_approve():
to_email.append('%s <%s>' % person.email())
subject = u'New Liaison Statement, "%s" needs your approval' % (liaison.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
body = render_to_string('liaisons/pending_liaison_mail.txt',
{'liaison': liaison,
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk)),
'approve_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk))
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
from_email=from_email,
body = body)
if not fake:
mail.send()
return mail

View file

@ -5,6 +5,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.template.loader import render_to_string
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse as urlreverse
from ietf.idtracker.models import Acronym, PersonOrOrgInfo, Area, IESGLogin
from ietf.liaisons.mail import IETFEmailMessage
from ietf.ietfauth.models import LegacyLiaisonUser
@ -143,6 +144,7 @@ class LiaisonDetail(models.Model):
from_email = settings.LIAISON_UNIVERSAL_FROM
body = render_to_string('liaisons/pending_liaison_mail.txt',
{'liaison': self,
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk))
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
@ -166,6 +168,8 @@ class LiaisonDetail(models.Model):
bcc = ['statements@ietf.org']
body = render_to_string('liaisons/liaison_mail.txt',
{'liaison': self,
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk)),
'approve_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk))
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
@ -289,6 +293,8 @@ class Uploads(models.Model):
detail = models.ForeignKey(LiaisonDetail)
def __str__(self):
return self.file_title
def filename(self):
return "file%s%s" % (self.file_id, self.file_extension)
class Meta:
db_table = 'uploads'
@ -320,12 +326,12 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES or hasattr(settings, "IMPORTING_FROM_O
related_to = models.ForeignKey('LiaisonStatement', blank=True, null=True)
from_group = models.ForeignKey(Group, related_name="liaisonstatement_from_set", null=True, blank=True, help_text="From body, if it exists")
from_group = models.ForeignKey(Group, related_name="liaisonstatement_from_set", null=True, blank=True, help_text="Sender group, if it exists")
from_name = models.CharField(max_length=255, help_text="Name of the sender body")
from_contact = models.ForeignKey(Email, blank=True, null=True)
to_group = models.ForeignKey(Group, related_name="liaisonstatement_to_set", null=True, blank=True, help_text="To body, if it exists")
to_group = models.ForeignKey(Group, related_name="liaisonstatement_to_set", null=True, blank=True, help_text="Recipient group, if it exists")
to_name = models.CharField(max_length=255, help_text="Name of the recipient body")
to_contact = models.CharField(blank=True, max_length=255, help_text="Contacts at to body")
to_contact = models.CharField(blank=True, max_length=255, help_text="Contacts at recipient body")
reply_to = models.CharField(blank=True, max_length=255)

View file

@ -96,14 +96,22 @@ class LiaisonDetailProxy(LiaisonStatement):
@property
def from_raw_body(self):
return self.from_name
def raw_codify(self, group):
if not group:
return ""
if group.type_id in ("sdo", "wg", "area"):
return "%s_%s" % (group.type_id, group.id)
return group.acronym
#from_raw_code = models.CharField(blank=True, null=True, max_length=255)
@property
def from_raw_code(self):
return self.from_group_id
return self.raw_codify(self.from_group)
#to_raw_code = models.CharField(blank=True, null=True, max_length=255)
@property
def to_raw_code(self):
return self.to_body_id
return self.raw_codify(self.to_group)
#approval = models.ForeignKey(OutgoingLiaisonApproval, blank=True, null=True)
@property
def approval(self):
@ -134,54 +142,10 @@ class LiaisonDetailProxy(LiaisonStatement):
class Meta:
proxy = True
def notify_pending_by_email(self, fake):
raise NotImplemented
from ietf.liaisons.utils import IETFHM
from_entity = IETFHM.get_entity_by_key(self.from_raw_code)
if not from_entity:
return None
to_email = []
for person in from_entity.can_approve():
to_email.append('%s <%s>' % person.email())
subject = 'New Liaison Statement, "%s" needs your approval' % (self.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
body = render_to_string('liaisons/pending_liaison_mail.txt',
{'liaison': self,
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
from_email=from_email,
body = body)
if not fake:
mail.send()
return mail
def send_by_email(self, fake=False):
raise NotImplemented
if self.is_pending():
return self.notify_pending_by_email(fake)
subject = 'New Liaison Statement, "%s"' % (self.title)
from_email = settings.LIAISON_UNIVERSAL_FROM
to_email = self.to_poc.split(',')
cc = self.cc1.split(',')
if self.technical_contact:
cc += self.technical_contact.split(',')
if self.response_contact:
cc += self.response_contact.split(',')
bcc = ['statements@ietf.org']
body = render_to_string('liaisons/liaison_mail.txt',
{'liaison': self,
})
mail = IETFEmailMessage(subject=subject,
to=to_email,
from_email=from_email,
cc = cc,
bcc = bcc,
body = body)
if not fake:
mail.send()
return mail
# grab this from module instead of stuffing in on the model
from ietf.liaisons.mails import send_liaison_by_email
return send_liaison_by_email(self, fake)
def is_pending(self):
return not self.approved
@ -190,7 +154,10 @@ class UploadsProxy(Document):
#file_id = models.AutoField(primary_key=True)
@property
def file_id(self):
return int(self.external_url.split(".")[0])
if self.external_url.startswith(self.name):
return self.name # new data
else:
return int(self.external_url.split(".")[0][len(file):]) # old data
#file_title = models.CharField(blank=True, max_length=255)
@property
def file_title(self):
@ -208,6 +175,14 @@ class UploadsProxy(Document):
@property
def detail(self):
return self.liaisonstatement_set.all()[0]
def filename(self):
return self.external_url
class Meta:
proxy = True
def proxy_personify_role(role):
"""Turn role into person with email() method using email from role."""
p = role.email.person
p.email = lambda: (p.name, role.email.address)
return p

View file

@ -1,9 +1,10 @@
import datetime
import datetime, os, shutil
from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse as urlreverse
import django.test
from StringIO import StringIO
from pyquery import PyQuery
from ietf.utils.test_utils import SimpleUrlTestCase, canonicalize_feed, canonicalize_sitemap, login_testing_unauthorized
@ -76,6 +77,15 @@ def make_liaison_models():
class LiaisonManagementTestCase(django.test.TestCase):
fixtures = ['names']
def setUp(self):
self.liaison_dir = os.path.abspath("tmp-liaison-dir")
os.mkdir(self.liaison_dir)
settings.LIAISON_ATTACH_PATH = self.liaison_dir
def tearDown(self):
shutil.rmtree(self.liaison_dir)
def test_taken_care_of(self):
make_test_data()
liaison = make_liaison_models()
@ -96,13 +106,44 @@ class LiaisonManagementTestCase(django.test.TestCase):
self.assertEquals(len(q('form input[name=do_action_taken]')), 1)
# mark action taken
r = self.client.post(url, dict(do_action_taken=1))
r = self.client.post(url, dict(do_action_taken="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=do_action_taken]')), 0)
liaison = LiaisonStatement.objects.get(id=liaison.id)
self.assertTrue(liaison.action_taken)
def test_approval(self):
make_test_data()
liaison = make_liaison_models()
# has to come from WG to need approval
liaison.from_group = Group.objects.get(acronym="mars")
liaison.approved = None
liaison.save()
url = urlreverse('liaison_approval_detail', kwargs=dict(object_id=liaison.pk))
# this liaison is for a WG so we need the AD for the area
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=do_approval]')), 1)
# approve
mailbox_before = len(mail_outbox)
r = self.client.post(url, dict(do_approval="1"))
self.assertEquals(r.status_code, 302)
liaison = LiaisonStatement.objects.get(id=liaison.id)
self.assertTrue(liaison.approved)
from django.core import mail
self.assertEqual(len(mail.outbox), 1)
self.assertTrue("Liaison Statement" in mail.outbox[-1].subject)
#self.assertEquals(len(mail_outbox), mailbox_before + 1)
#self.assertTrue("Liaison Statement" in mail_outbox[-1]["Subject"])
def test_edit_liaison(self):
make_test_data()
liaison = make_liaison_models()
@ -117,6 +158,9 @@ class LiaisonManagementTestCase(django.test.TestCase):
self.assertEquals(len(q('form input[name=from_field]')), 1)
# edit
attachments_before = liaison.attachments.count()
test_file = StringIO("hello world")
test_file.name = "unnamed"
r = self.client.post(url,
dict(from_field="from",
replyto="replyto@example.com",
@ -124,14 +168,17 @@ class LiaisonManagementTestCase(django.test.TestCase):
to_poc="to_poc@example.com",
response_contact="responce_contact@example.com",
technical_contact="technical_contact@example.com",
cc1="cc1@example.com",
cc1="cc@example.com",
purpose="4",
deadline_date=(liaison.deadline + datetime.timedelta(days=1)).strftime("%Y-%m-%d"),
title="title",
submitted_date=(liaison.submitted + datetime.timedelta(days=1)).strftime("%Y-%m-%d"),
body="body",
attach_file_1=test_file,
attach_title_1="attachment",
))
self.assertEquals(r.status_code, 302)
new_liaison = LiaisonStatement.objects.get(id=liaison.id)
self.assertEquals(new_liaison.from_name, "from")
self.assertEquals(new_liaison.reply_to, "replyto@example.com")
@ -139,7 +186,7 @@ class LiaisonManagementTestCase(django.test.TestCase):
self.assertEquals(new_liaison.to_contact, "to_poc@example.com")
self.assertEquals(new_liaison.response_contact, "responce_contact@example.com")
self.assertEquals(new_liaison.technical_contact, "technical_contact@example.com")
self.assertEquals(new_liaison.cc, "cc1@example.com")
self.assertEquals(new_liaison.cc, "cc@example.com")
self.assertEquals(new_liaison.purpose, LiaisonStatementPurposeName.objects.get(order=4))
self.assertEquals(new_liaison.deadline, liaison.deadline + datetime.timedelta(days=1)),
self.assertEquals(new_liaison.title, "title")
@ -147,7 +194,174 @@ class LiaisonManagementTestCase(django.test.TestCase):
self.assertEquals(new_liaison.body, "body")
self.assertTrue(new_liaison.modified > liaison.modified)
# test links and edit button
self.assertEquals(new_liaison.attachments.count(), attachments_before + 1)
attachment = new_liaison.attachments.order_by("-name")[0]
self.assertEquals(attachment.title, "attachment")
with open(os.path.join(self.liaison_dir, attachment.external_url)) as f:
written_content = f.read()
test_file.seek(0)
self.assertEquals(written_content, test_file.read())
def test_add_incoming_liaison(self):
make_test_data()
liaison = make_liaison_models()
url = urlreverse('add_liaison') + "?incoming=1"
login_testing_unauthorized(self, "secretary", url)
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=body]')), 1)
# add new
test_file = StringIO("hello world")
test_file.name = "unnamed"
from_group = Group.objects.filter(type="sdo")[0]
to_group = Group.objects.get(acronym="mars")
submitter = Person.objects.get(user__username="marschairman")
today = datetime.date.today()
related_liaison = liaison
r = self.client.post(url,
dict(from_field="%s_%s" % (from_group.type_id, from_group.pk),
from_fake_user=str(submitter.pk),
replyto="replyto@example.com",
organization="%s_%s" % (to_group.type_id, to_group.pk),
response_contact="responce_contact@example.com",
technical_contact="technical_contact@example.com",
cc1="cc@example.com",
purpose="4",
deadline_date=(today + datetime.timedelta(days=1)).strftime("%Y-%m-%d"),
related_to=str(related_liaison.pk),
title="title",
submitted_date=today.strftime("%Y-%m-%d"),
body="body",
attach_file_1=test_file,
attach_title_1="attachment",
))
self.assertEquals(r.status_code, 302)
l = LiaisonStatement.objects.all().order_by("-id")[0]
self.assertEquals(l.from_group, from_group)
self.assertEquals(l.from_contact, submitter.email_address())
self.assertEquals(l.reply_to, "replyto@example.com")
self.assertEquals(l.to_group, to_group)
self.assertEquals(l.response_contact, "responce_contact@example.com")
self.assertEquals(l.technical_contact, "technical_contact@example.com")
self.assertEquals(l.cc, "cc@example.com")
self.assertEquals(l.purpose, LiaisonStatementPurposeName.objects.get(order=4))
self.assertEquals(l.deadline, today + datetime.timedelta(days=1)),
self.assertEquals(l.related_to, liaison),
self.assertEquals(l.title, "title")
self.assertEquals(l.submitted.date(), today)
self.assertEquals(l.body, "body")
self.assertTrue(l.approved)
self.assertEquals(l.attachments.count(), 1)
attachment = l.attachments.all()[0]
self.assertEquals(attachment.title, "attachment")
with open(os.path.join(self.liaison_dir, attachment.external_url)) as f:
written_content = f.read()
test_file.seek(0)
self.assertEquals(written_content, test_file.read())
def test_add_outgoing_liaison(self):
make_test_data()
liaison = make_liaison_models()
url = urlreverse('add_liaison')
login_testing_unauthorized(self, "secretary", url)
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form textarea[name=body]')), 1)
# add new
test_file = StringIO("hello world")
test_file.name = "unnamed"
from_group = Group.objects.get(acronym="mars")
to_group = Group.objects.filter(type="sdo")[0]
submitter = Person.objects.get(user__username="marschairman")
today = datetime.date.today()
related_liaison = liaison
r = self.client.post(url,
dict(from_field="%s_%s" % (from_group.type_id, from_group.pk),
from_fake_user=str(submitter.pk),
approved="",
replyto="replyto@example.com",
to_poc="to_poc@example.com",
organization="%s_%s" % (to_group.type_id, to_group.pk),
other_organization="",
response_contact="responce_contact@example.com",
technical_contact="technical_contact@example.com",
cc1="cc@example.com",
purpose="4",
deadline_date=(today + datetime.timedelta(days=1)).strftime("%Y-%m-%d"),
related_to=str(related_liaison.pk),
title="title",
submitted_date=today.strftime("%Y-%m-%d"),
body="body",
attach_file_1=test_file,
attach_title_1="attachment",
))
self.assertEquals(r.status_code, 302)
l = LiaisonStatement.objects.all().order_by("-id")[0]
self.assertEquals(l.from_group, from_group)
self.assertEquals(l.from_contact, submitter.email_address())
self.assertEquals(l.reply_to, "replyto@example.com")
self.assertEquals(l.to_group, to_group)
self.assertEquals(l.to_contact, "to_poc@example.com")
self.assertEquals(l.response_contact, "responce_contact@example.com")
self.assertEquals(l.technical_contact, "technical_contact@example.com")
self.assertEquals(l.cc, "cc@example.com")
self.assertEquals(l.purpose, LiaisonStatementPurposeName.objects.get(order=4))
self.assertEquals(l.deadline, today + datetime.timedelta(days=1)),
self.assertEquals(l.related_to, liaison),
self.assertEquals(l.title, "title")
self.assertEquals(l.submitted.date(), today)
self.assertEquals(l.body, "body")
self.assertTrue(not l.approved)
self.assertEquals(l.attachments.count(), 1)
attachment = l.attachments.all()[0]
self.assertEquals(attachment.title, "attachment")
with open(os.path.join(self.liaison_dir, attachment.external_url)) as f:
written_content = f.read()
test_file.seek(0)
self.assertEquals(written_content, test_file.read())
# try adding statement to non-predefined organization
r = self.client.post(url,
dict(from_field="%s_%s" % (from_group.type_id, from_group.pk),
from_fake_user=str(submitter.pk),
approved="1",
replyto="replyto@example.com",
to_poc="to_poc@example.com",
organization="othersdo",
other_organization="Mars Institute",
response_contact="responce_contact@example.com",
technical_contact="technical_contact@example.com",
cc1="cc@example.com",
purpose="4",
deadline_date=(today + datetime.timedelta(days=1)).strftime("%Y-%m-%d"),
related_to=str(related_liaison.pk),
title="new title",
submitted_date=today.strftime("%Y-%m-%d"),
body="body",
))
self.assertEquals(r.status_code, 302)
l = LiaisonStatement.objects.all().order_by("-id")[0]
self.assertEquals(l.to_group, None)
self.assertEquals(l.to_name, "Mars Institute")
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
# the above tests only work with the new schema

View file

@ -1,3 +1,7 @@
from redesign.group.models import Group, Role
from redesign.person.models import Person
from ietf.liaisons.proxy import proxy_personify_role
from ietf.liaisons.accounts import (is_ietfchair, is_iabchair, is_iab_executive_director,
get_ietf_chair, get_iab_chair, get_iab_executive_director,
is_secretariat)
@ -9,10 +13,6 @@ IABCHAIR = {'name': u'The IAB Chair', 'address': u'iab-chair@iab.org'}
IABEXECUTIVEDIRECTOR = {'name': u'The IAB Executive Director', 'address': u'execd@iab.org'}
def get_all_sdo_managers():
return list(Person.objects.filter(email__role__name="liaiman", email__role__group__state="active").distinct())
class FakePerson(object):
def __init__(self, name, address):
@ -28,15 +28,11 @@ class FakePerson(object):
# schema) way - unfortunately, it's never been strong enough to do so
# fine-grained enough so the form code also has some rules
def all_sdo_managers():
return [proxy_personify_role(r) for r in Role.objects.filter(group__type="sdo", name="liaiman").select_related("email").distinct()]
def role_persons_with_fixed_email(group, role_name):
from redesign.group.models import Role
res = []
for r in Role.objects.filter(group=group, name=role_name).select_related("email"):
p = r.email.person
# proxy hack to make email() return the right address
p.email = (lambda name, address: (lambda: (name, address)))(p.name, r.email.address)
res.append(p)
return res
return [proxy_personify_role(r) for r in Role.objects.filter(group=group, name=role_name).select_related("email").distinct()]
class Entity(object):
@ -94,7 +90,7 @@ class IETFEntity(Entity):
return [self.poc]
def full_user_list(self):
result = get_all_sdo_managers()
result = all_sdo_managers()
result.append(get_ietf_chair())
return result
@ -123,7 +119,7 @@ class IABEntity(Entity):
return [self.chair]
def full_user_list(self):
result = get_all_sdo_managers()
result = all_sdo_managers()
result += [get_iab_chair(), get_iab_executive_director()]
return result
@ -131,7 +127,7 @@ class IABEntity(Entity):
class AreaEntity(Entity):
def get_poc(self):
return [i.person for i in self.obj.areadirector_set.all()]
return role_persons_with_fixed_email(self.obj, "ad")
def get_cc(self, person=None):
return [FakePerson(**IETFCHAIR)]
@ -151,7 +147,7 @@ class AreaEntity(Entity):
return self.get_poc()
def full_user_list(self):
result = get_all_sdo_managers()
result = all_sdo_managers()
result += self.get_poc()
return result
@ -189,7 +185,7 @@ class WGEntity(Entity):
return role_persons_with_fixed_email(self.obj.parent, "ad") if self.obj.parent else []
def full_user_list(self):
result = get_all_sdo_managers()
result = all_sdo_managers()
result += self.get_poc()
return result
@ -332,8 +328,7 @@ class WGEntityManager(EntityManager):
return WGEntity(name=obj.group_acronym.name, obj=obj)
def can_send_on_behalf(self, person):
wgs = set([i.group_acronym.pk for i in person.wgchair_set.all()])
wgs = wgs.union([i.group_acronym.pk for i in person.wgsecretary_set.all()])
wgs = Group.objects.filter(role__email__person=person, role__name__in=("chair", "secretary")).values_list('pk', flat=True)
query_filter = {'pk__in': wgs}
return self.get_managed_list(query_filter)
@ -347,7 +342,6 @@ class SDOEntityManager(EntityManager):
def __init__(self, pk=None, name=None, queryset=None):
super(SDOEntityManager, self).__init__(pk, name, queryset)
if self.queryset == None:
from redesign.group.models import Group
self.queryset = Group.objects.filter(type="sdo")
def get_managed_list(self):

View file

@ -177,19 +177,26 @@ def liaison_approval_list(request):
def liaison_approval_detail(request, object_id):
person = get_person_for_user(request.user)
approval_codes = IETFHM.get_all_can_approve_codes(person)
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
to_approve = approvable_liaison_statements(approval_codes).order_by("-submitted")
else:
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
if request.method=='POST' and request.POST.get('do_approval', False):
try:
liaison = to_approve.get(pk=object_id)
approval = liaison.approval
if not approval:
approval = OutgoingLiaisonApproval.objects.create(approved=True, approval_date=datetime.datetime.now())
liaison.approval = approval
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
liaison.approved = datetime.datetime.now()
liaison.save()
else:
approval.approved=True
approval.save()
approval = liaison.approval
if not approval:
approval = OutgoingLiaisonApproval.objects.create(approved=True, approval_date=datetime.datetime.now())
liaison.approval = approval
liaison.save()
else:
approval.approved=True
approval.save()
if not settings.DEBUG:
liaison.send_by_email()
else:

View file

@ -14,7 +14,7 @@ Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ lia
Body: {{ liaison.body }}
Attachment(s):
{% for file in liaison.uploads_set.all %}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/file{{ file.file_id }}{{ file.file_extension }}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/file{{ file.filename }}
{% empty %}
No document has been attached
{% endfor %}

View file

@ -1,18 +1,18 @@
{% autoescape off %}Title: {{ liaison.title }}
Submission Date: {{ liaison.submitted_date }}
URL of the IETF Web page: {% url liaison_detail object_id=liaison.pk %}
URL of the IETF Web page: {{ url }}
{% if liaison.deadline_date %}Please reply by {{ liaison.deadline_date }}{% endif %}
From: {{ liaison.from_body }} ({{ liaison.person }} <{{ liaison.replyto|default:liaison.from_email }}>)
To: {{ liaison.to_body }} ({{ liaison.to_poc }})
Cc: {{ liaison.cc1 }}
Reponse Contact: {{ liaison.response_contact }}
Technical Contact: {{ liaison.technical_contact }}
Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ liaison.purpose.purpose_text }}{% endif %}
Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ liaison.purpose }}{% endif %}
{% if liaison.related_to %}Referenced liaison: {% if liaison.related_to.title %}{{ liaison.related_to.title }}{% else %}Liaison #{{ liaison.related_to.pk }}{% endif %} ({% url liaison_detail object_id=liaison.related_to.pk %}){% endif %}
Body: {{ liaison.body }}
Attachment(s):
Attachments:
{% for file in liaison.uploads_set.all %}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/file{{ file.file_id }}{{ file.file_extension }}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/{{ file.filename }}
{% empty %}
No document has been attached
{% endfor %}

View file

@ -38,7 +38,7 @@
<td>
{% if liaison.by_secretariat %}
{% for file in liaison.uploads_set.all %}
<a href="https://datatracker.ietf.org/documents/LIAISON/file{{ file.file_id }}{{ file.file_extension }}">{{ file.file_title|escape }}</a><br/>
<a href="https://datatracker.ietf.org/documents/LIAISON/{{ file.filename }}">{{ file.file_title|escape }}</a><br/>
{% endfor %}
{% else %}
<a href="{{ liaison.detail_id }}/">{{ liaison.title|escape }}</a>

View file

@ -2,22 +2,22 @@ The following liaison statement will remain pending (and not public available) i
{% load ietf_filters %}{% autoescape off %}
Title: {{ liaison.title|clean_whitespace }}
Submission Date: {{ liaison.submitted_date }}
URL of the IETF Web page: {% url liaison_approval_detail liaison.pk %}
URL of the IETF Web page: {{ url }}
{% if liaison.deadline_date %}Please reply by {{ liaison.deadline_date }}{% endif %}
From: {{ liaison.from_body }} ({{ liaison.person }} <{{ liaison.replyto|default:liaison.from_email }}>)
To: {{ liaison.to_body }} ({{ liaison.to_poc }})
Cc: {{ liaison.cc1 }}
Reponse Contact: {{ liaison.response_contact }}
Technical Contact: {{ liaison.technical_contact }}
Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ liaison.purpose.purpose_text }}{% endif %}
Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ liaison.purpose }}{% endif %}
{% if liaison.related_to %}Referenced liaison: {% if liaison.related_to.title %}{{ liaison.related_to.title }}{% else %}Liaison #{{ liaison.related_to.pk }}{% endif %} ({% url liaison_detail object_id=liaison.related_to.pk %}){% endif %}
Body: {{ liaison.body }}
Attachment(s):
Attachments:
{% for file in liaison.uploads_set.all %}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/file{{ file.file_id }}{{ file.file_extension }}
{{ file.file_title }} https://datatracker.ietf.org/documents/LIAISON/{{ file.filename }}
{% empty %}
No document has been attached
{% endfor %}
{% endautoescape %}
Please visit {% url liaison_approval_detail liaison.pk %} in order to approve the liaison statement.
Please visit {{ approve_url }} in order to approve the liaison statement.

View file

@ -76,9 +76,11 @@ def make_test_data():
email=email)
# group chair
u = User.objects.create(username="marschairman")
p = Person.objects.create(
name="WG Chair Man",
ascii="WG Chair Man",
user=u
)
wgchair = Email.objects.create(
address="wgchairman@ietf.org",

View file

@ -17,7 +17,7 @@ class Acronym(Group):
#acronym_id = models.AutoField(primary_key=True)
@property
def acronym_id(self):
raise NotImplemented
return self.id
#acronym = models.CharField(max_length=12) # same name
#name = models.CharField(max_length=100) # same name
#name_key = models.CharField(max_length=50, editable=False)

View file

@ -83,9 +83,11 @@ def get_body(name, raw_code):
t = raw_code.split("_")
if len(t) == 2:
if t[0] == "area":
b = lookup_group(acronym=Acronym.objects.get(pk=t[1]), type="area")
elif t[0] == "group":
b = lookup_group(acronym=Acronym.objects.get(pk=t[1]), type="wg")
b = lookup_group(acronym=Acronym.objects.get(pk=t[1]).acronym, type="area")
elif t[0] == "wg":
b = lookup_group(acronym=Acronym.objects.get(pk=t[1]).acronym, type="wg")
elif t[0] == "sdo":
b = lookup_group(name=SDOs.objects.get(pk=t[1]).name, type="sdo")
if not b:
b = lookup_group(acronym=raw_code)
@ -190,7 +192,7 @@ for o in LiaisonDetail.objects.all().order_by("pk"):
attachment.name = l.name() + ("-attachment-%s" % (i + 1))
attachment.time = l.submitted
# we should fixup the filenames, but meanwhile, store it here
attachment.external_url = "%s%s" % (u.file_id, u.file_extension)
attachment.external_url = "file%s%s" % (u.file_id, u.file_extension)
attachment.save()
DocAlias.objects.get_or_create(document=attachment, name=attachment.name)