Remove proxy layer from liaisons tool, do some minor cleanups of
duplicated code, make sure the custom form widgets escape their input. There's still a bit of custom proxying going on in the IETFHM class hierarchy. - Legacy-Id: 6794
This commit is contained in:
parent
97bf521ebb
commit
4250a95556
ietf
liaisons
__init__.pyaccounts.pyaccountsREDESIGN.pyadmin.pydecorators.pyfeeds.pyforms.pyformsREDESIGN.pymails.py
management/commands
models.pyproxy.pysitemaps.pytests.pytesturl.listurls.pyutils.pyutilsREDESIGN.pyviews.pywidgets.pytemplates/liaisons
static/css
|
@ -2,7 +2,7 @@
|
|||
# coding: latin-1
|
||||
|
||||
from types import ModuleType
|
||||
import urls, models, views, forms, accounts, admin, utils, widgets, decorators, sitemaps, feeds
|
||||
import urls, models, views, forms, admin, utils, widgets, sitemaps, feeds
|
||||
|
||||
# These people will be sent a stack trace if there's an uncaught exception in
|
||||
# code any of the modules imported above:
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
from django.conf import settings
|
||||
from ietf.person.models import Person
|
||||
from ietf.group.models import Role
|
||||
from ietf.utils.proxy import proxy_personify_role
|
||||
|
||||
from ietf.idtracker.models import Role, PersonOrOrgInfo
|
||||
|
||||
|
||||
LIAISON_EDIT_GROUPS = ['Secretariat']
|
||||
LIAISON_EDIT_GROUPS = ['Secretariat'] # this is not working anymore, refers to old auth model
|
||||
|
||||
|
||||
def get_ietf_chair():
|
||||
person = PersonOrOrgInfo.objects.filter(role=Role.IETF_CHAIR)
|
||||
return person and person[0] or None
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="ietf"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_iesg_chair():
|
||||
|
@ -16,48 +17,62 @@ def get_iesg_chair():
|
|||
|
||||
|
||||
def get_iab_chair():
|
||||
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_CHAIR)
|
||||
return person and person[0] or None
|
||||
|
||||
|
||||
def get_iab_executive_director():
|
||||
person = PersonOrOrgInfo.objects.filter(role=Role.IAB_EXCUTIVE_DIRECTOR)
|
||||
return person and person[0] or None
|
||||
|
||||
|
||||
def get_person_for_user(user):
|
||||
try:
|
||||
return user.get_profile().person()
|
||||
except:
|
||||
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="iab"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_irtf_chair():
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="irtf"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_iab_executive_director():
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="execdir", group__acronym="iab"))
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_person_for_user(user):
|
||||
if not user.is_authenticated():
|
||||
return None
|
||||
try:
|
||||
p = user.get_profile()
|
||||
p.email = lambda: (p.plain_name(), p.email_address())
|
||||
return p
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
def is_areadirector(person):
|
||||
return bool(person.areadirector_set.all())
|
||||
return bool(Role.objects.filter(person=person, name="ad", group__state="active", group__type="area"))
|
||||
|
||||
|
||||
def is_wgchair(person):
|
||||
return bool(person.wgchair_set.all())
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__state="active", group__type="wg"))
|
||||
|
||||
|
||||
def is_wgsecretary(person):
|
||||
return bool(person.wgsecretary_set.all())
|
||||
|
||||
|
||||
def has_role(person, role):
|
||||
return bool(person.role_set.filter(pk=role))
|
||||
return bool(Role.objects.filter(person=person, name="sec", group__state="active", group__type="wg"))
|
||||
|
||||
|
||||
def is_ietfchair(person):
|
||||
return has_role(person, Role.IETF_CHAIR)
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="ietf"))
|
||||
|
||||
|
||||
def is_iabchair(person):
|
||||
return has_role(person, Role.IAB_CHAIR)
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="iab"))
|
||||
|
||||
|
||||
def is_iab_executive_director(person):
|
||||
return has_role(person, Role.IAB_EXCUTIVE_DIRECTOR)
|
||||
return bool(Role.objects.filter(person=person, name="execdir", group__acronym="iab"))
|
||||
|
||||
|
||||
def is_irtfchair(person):
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="irtf"))
|
||||
|
||||
|
||||
def can_add_outgoing_liaison(user):
|
||||
|
@ -74,15 +89,17 @@ def can_add_outgoing_liaison(user):
|
|||
|
||||
|
||||
def is_sdo_liaison_manager(person):
|
||||
return bool(person.liaisonmanagers_set.all())
|
||||
return bool(Role.objects.filter(person=person, name="liaiman", group__type="sdo"))
|
||||
|
||||
|
||||
def is_sdo_authorized_individual(person):
|
||||
return bool(person.sdoauthorizedindividual_set.all())
|
||||
return bool(Role.objects.filter(person=person, name="auth", group__type="sdo"))
|
||||
|
||||
|
||||
def is_secretariat(user):
|
||||
return bool(user.groups.filter(name='Secretariat'))
|
||||
if isinstance(user, basestring):
|
||||
return False
|
||||
return user.is_authenticated() and bool(Role.objects.filter(person__user=user, name="secr", group__acronym="secretariat"))
|
||||
|
||||
|
||||
def can_add_incoming_liaison(user):
|
||||
|
@ -102,36 +119,14 @@ def can_add_liaison(user):
|
|||
|
||||
|
||||
def is_sdo_manager_for_outgoing_liaison(person, liaison):
|
||||
from ietf.liaisons.utils import IETFHM, SDOEntity
|
||||
from ietf.liaisons.models import SDOs
|
||||
from_entity = IETFHM.get_entity_by_key(liaison.from_raw_code)
|
||||
sdo = None
|
||||
if not from_entity:
|
||||
try:
|
||||
sdo = SDOs.objects.get(sdo_name=liaison.from_body())
|
||||
except SDOs.DoesNotExist:
|
||||
pass
|
||||
elif isinstance(from_entity, SDOEntity):
|
||||
sdo = from_entity.obj
|
||||
if sdo:
|
||||
return bool(sdo.liaisonmanagers_set.filter(person=person))
|
||||
if liaison.from_group and liaison.from_group.type_id == "sdo":
|
||||
return bool(liaison.from_group.role_set.filter(name="liaiman", person=person))
|
||||
return False
|
||||
|
||||
|
||||
def is_sdo_manager_for_incoming_liaison(person, liaison):
|
||||
from ietf.liaisons.utils import IETFHM, SDOEntity
|
||||
from ietf.liaisons.models import SDOs
|
||||
to_entity = IETFHM.get_entity_by_key(liaison.to_raw_code)
|
||||
sdo = None
|
||||
if not to_entity:
|
||||
try:
|
||||
sdo = SDOs.objects.get(sdo_name=liaison.to_body)
|
||||
except SDOs.DoesNotExist:
|
||||
pass
|
||||
elif isinstance(to_entity, SDOEntity):
|
||||
sdo = to_entity.obj
|
||||
if sdo:
|
||||
return bool(sdo.liaisonmanagers_set.filter(person=person))
|
||||
if liaison.to_group and liaison.to_group.type_id == "sdo":
|
||||
return bool(liaison.to_group.role_set.filter(name="liaiman", person=person))
|
||||
return False
|
||||
|
||||
|
||||
|
@ -143,6 +138,3 @@ def can_edit_liaison(user, liaison):
|
|||
return (is_sdo_manager_for_outgoing_liaison(person, liaison) or
|
||||
is_sdo_manager_for_incoming_liaison(person, liaison))
|
||||
return False
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from accountsREDESIGN import *
|
||||
|
|
|
@ -1,140 +0,0 @@
|
|||
from ietf.person.models import Person
|
||||
from ietf.group.models import Role
|
||||
from ietf.utils.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 proxy_personify_role(Role.objects.get(name="chair", group__acronym="ietf"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_iesg_chair():
|
||||
return get_ietf_chair()
|
||||
|
||||
|
||||
def get_iab_chair():
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="iab"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_irtf_chair():
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="chair", group__acronym="irtf"))
|
||||
except Role.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_iab_executive_director():
|
||||
try:
|
||||
return proxy_personify_role(Role.objects.get(name="execdir", group__acronym="iab"))
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
|
||||
def get_person_for_user(user):
|
||||
if not user.is_authenticated():
|
||||
return None
|
||||
try:
|
||||
p = user.get_profile()
|
||||
p.email = lambda: (p.plain_name(), p.email_address())
|
||||
return p
|
||||
except Person.DoesNotExist:
|
||||
return None
|
||||
|
||||
def is_areadirector(person):
|
||||
return bool(Role.objects.filter(person=person, name="ad", group__state="active", group__type="area"))
|
||||
|
||||
|
||||
def is_wgchair(person):
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__state="active", group__type="wg"))
|
||||
|
||||
|
||||
def is_wgsecretary(person):
|
||||
return bool(Role.objects.filter(person=person, name="sec", group__state="active", group__type="wg"))
|
||||
|
||||
|
||||
def is_ietfchair(person):
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="ietf"))
|
||||
|
||||
|
||||
def is_iabchair(person):
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="iab"))
|
||||
|
||||
|
||||
def is_iab_executive_director(person):
|
||||
return bool(Role.objects.filter(person=person, name="execdir", group__acronym="iab"))
|
||||
|
||||
|
||||
def is_irtfchair(person):
|
||||
return bool(Role.objects.filter(person=person, name="chair", group__acronym="irtf"))
|
||||
|
||||
|
||||
def can_add_outgoing_liaison(user):
|
||||
person = get_person_for_user(user)
|
||||
if not person:
|
||||
return False
|
||||
|
||||
if (is_areadirector(person) or is_wgchair(person) or
|
||||
is_wgsecretary(person) or is_ietfchair(person) or
|
||||
is_iabchair(person) or is_iab_executive_director(person) or
|
||||
is_sdo_liaison_manager(person) or is_secretariat(user)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def is_sdo_liaison_manager(person):
|
||||
return bool(Role.objects.filter(person=person, name="liaiman", group__type="sdo"))
|
||||
|
||||
|
||||
def is_sdo_authorized_individual(person):
|
||||
return bool(Role.objects.filter(person=person, name="auth", group__type="sdo"))
|
||||
|
||||
|
||||
def is_secretariat(user):
|
||||
if isinstance(user, basestring):
|
||||
return False
|
||||
return user.is_authenticated() and bool(Role.objects.filter(person__user=user, name="secr", group__acronym="secretariat"))
|
||||
|
||||
|
||||
def can_add_incoming_liaison(user):
|
||||
person = get_person_for_user(user)
|
||||
if not person:
|
||||
return False
|
||||
|
||||
if (is_sdo_liaison_manager(person) or
|
||||
is_sdo_authorized_individual(person) or
|
||||
is_secretariat(user)):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def can_add_liaison(user):
|
||||
return can_add_incoming_liaison(user) or can_add_outgoing_liaison(user)
|
||||
|
||||
|
||||
def is_sdo_manager_for_outgoing_liaison(person, liaison):
|
||||
if liaison.from_group and liaison.from_group.type_id == "sdo":
|
||||
return bool(liaison.from_group.role_set.filter(name="liaiman", person=person))
|
||||
return False
|
||||
|
||||
|
||||
def is_sdo_manager_for_incoming_liaison(person, liaison):
|
||||
if liaison.to_group and liaison.to_group.type_id == "sdo":
|
||||
return bool(liaison.to_group.role_set.filter(name="liaiman", person=person))
|
||||
return False
|
||||
|
||||
|
||||
def can_edit_liaison(user, liaison):
|
||||
if is_secretariat(user):
|
||||
return True
|
||||
person = get_person_for_user(user)
|
||||
if is_sdo_liaison_manager(person):
|
||||
return (is_sdo_manager_for_outgoing_liaison(person, liaison) or
|
||||
is_sdo_manager_for_incoming_liaison(person, liaison))
|
||||
return False
|
|
@ -8,10 +8,3 @@ class LiaisonStatementAdmin(admin.ModelAdmin):
|
|||
ordering = ('title', )
|
||||
raw_id_fields = ('from_contact', 'related_to', 'from_group', 'to_group', 'attachments')
|
||||
admin.site.register(LiaisonStatement, LiaisonStatementAdmin)
|
||||
|
||||
class LiaisonDetailAdmin(admin.ModelAdmin):
|
||||
list_display = ['pk', 'title', 'from_id', 'to_body', 'submitted_date', 'purpose', 'related_to' ]
|
||||
list_display_links = ['pk', 'title']
|
||||
ordering = ('title', )
|
||||
admin.site.register(LiaisonDetail, LiaisonDetailAdmin)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
from ietf.ietfauth.decorators import passes_test_decorator
|
||||
from ietf.liaisons.accounts import can_add_liaison
|
||||
|
||||
can_submit_liaison = passes_test_decorator(lambda u, *args, **kwargs: can_add_liaison(u),
|
||||
"Restricted to participants who are authorized to submit liaison statements on behalf of the various IETF entities")
|
|
@ -1,24 +1,22 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
import re, datetime
|
||||
|
||||
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
|
||||
from ietf.liaisons.models import LiaisonDetail, FromBodies
|
||||
from ietf.idtracker.models import Acronym
|
||||
from datetime import datetime, time
|
||||
import re
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.group.models import Group
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
from ietf.group.models import Group
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
|
||||
# A slightly funny feed class, the 'object' is really
|
||||
# just a dict with some parameters that items() uses
|
||||
# to construct a queryset.
|
||||
class Liaisons(Feed):
|
||||
feed_type = Atom1Feed
|
||||
|
||||
def get_object(self, bits):
|
||||
obj = {}
|
||||
if bits[0] == 'recent':
|
||||
|
@ -27,77 +25,50 @@ class Liaisons(Feed):
|
|||
obj['title'] = 'Recent Liaison Statements'
|
||||
obj['limit'] = 15
|
||||
return obj
|
||||
if bits[0] == 'from':
|
||||
|
||||
if bits[0] == 'from':
|
||||
if len(bits) != 2:
|
||||
raise FeedDoesNotExist
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
try:
|
||||
group = Group.objects.get(acronym=bits[1])
|
||||
obj['filter'] = { 'from_group': group }
|
||||
obj['title'] = u'Liaison Statements from %s' % group.name
|
||||
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:
|
||||
# turn all-nonword characters into one-character
|
||||
# wildcards to make it easier to construct a URL that
|
||||
# matches
|
||||
search_string = re.sub(r"[^a-zA-Z1-9]", ".", bits[1])
|
||||
statements = LiaisonStatement.objects.filter(from_name__iregex=search_string)
|
||||
if statements:
|
||||
name = statements[0].from_name
|
||||
obj['filter'] = { 'from_name': name }
|
||||
obj['title'] = u'Liaison Statements from %s' % name
|
||||
return obj
|
||||
except Group.DoesNotExist:
|
||||
# turn all-nonword characters into one-character
|
||||
# wildcards to make it easier to construct the URL
|
||||
search_string = re.sub(r"[^a-zA-Z1-9]", ".", bits[1])
|
||||
statements = LiaisonStatement.objects.filter(from_name__iregex=search_string)
|
||||
if statements:
|
||||
name = statements[0].from_name
|
||||
obj['filter'] = { 'from_name': name }
|
||||
obj['title'] = u'Liaison Statements from %s' % name
|
||||
return obj
|
||||
else:
|
||||
raise FeedDoesNotExist
|
||||
try:
|
||||
acronym = Acronym.objects.get(acronym=bits[1])
|
||||
obj['filter'] = {'from_id': acronym.acronym_id}
|
||||
body = bits[1]
|
||||
except Acronym.DoesNotExist:
|
||||
# Find body matches. Turn all non-word characters
|
||||
# into wildcards for the like search.
|
||||
# Note that supplying sql here means that this is
|
||||
# mysql-specific (e.g., postgresql wants 'ilike' for
|
||||
# the same operation)
|
||||
body_list = FromBodies.objects.values('from_id','body_name').extra(where=['body_name like "%s"' % re.sub('\W', '_', bits[1])])
|
||||
if not body_list:
|
||||
raise FeedDoesNotExist
|
||||
frmlist = [b['from_id'] for b in body_list]
|
||||
# Assume that all of the matches have the same name.
|
||||
# This is not guaranteed (e.g., a url like '-----------'
|
||||
# will match several bodies) but is true of well-formed
|
||||
# inputs.
|
||||
body = body_list[0]['body_name']
|
||||
obj['filter'] = {'from_id__in': frmlist}
|
||||
obj['title'] = 'Liaison Statements from %s' % body
|
||||
return obj
|
||||
if bits[0] == 'to':
|
||||
else:
|
||||
raise FeedDoesNotExist
|
||||
|
||||
if bits[0] == 'to':
|
||||
if len(bits) != 2:
|
||||
raise FeedDoesNotExist
|
||||
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
|
||||
obj['filter'] = dict(to_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
|
||||
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]
|
||||
|
||||
obj['q'] = [ Q(title__icontains=bits[1]) | Q(attachments__title__icontains=bits[1]) ]
|
||||
obj['title'] = 'Liaison Statements where subject matches %s' % bits[1]
|
||||
return obj
|
||||
raise FeedDoesNotExist
|
||||
|
||||
def get_feed(self, url=None):
|
||||
if not url:
|
||||
raise FeedDoesNotExist
|
||||
else:
|
||||
if url:
|
||||
return Feed.get_feed(self, url=url)
|
||||
else:
|
||||
raise FeedDoesNotExist
|
||||
|
||||
def title(self, obj):
|
||||
return obj['title']
|
||||
|
@ -106,12 +77,16 @@ class Liaisons(Feed):
|
|||
# no real equivalent for any objects
|
||||
return '/liaison/'
|
||||
|
||||
def item_link(self, obj):
|
||||
# no real equivalent for any objects
|
||||
return urlreverse("liaison_detail", kwargs={ "object_id": obj.pk })
|
||||
|
||||
def description(self, obj):
|
||||
return self.title(obj)
|
||||
|
||||
def items(self, obj):
|
||||
# Start with the common queryset
|
||||
qs = LiaisonDetail.objects.all().order_by("-submitted_date")
|
||||
qs = LiaisonStatement.objects.all().order_by("-submitted")
|
||||
if obj.has_key('q'):
|
||||
qs = qs.filter(*obj['q'])
|
||||
if obj.has_key('filter'):
|
||||
|
@ -123,7 +98,7 @@ class Liaisons(Feed):
|
|||
def item_pubdate(self, item):
|
||||
# this method needs to return a datetime instance, even
|
||||
# though the database has only date, not time
|
||||
return datetime.combine(item.submitted_date, time(0,0,0))
|
||||
return item.submitted
|
||||
|
||||
def item_author_name(self, item):
|
||||
return item.from_body()
|
||||
return item.from_name
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import datetime
|
||||
import datetime, os
|
||||
from email.utils import parseaddr
|
||||
|
||||
from django import forms
|
||||
|
@ -8,26 +8,31 @@ from django.forms.util import ErrorList
|
|||
from django.core.validators import email_re
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from ietf.idtracker.models import PersonOrOrgInfo
|
||||
from ietf.liaisons.accounts import (can_add_outgoing_liaison, can_add_incoming_liaison,
|
||||
get_person_for_user, is_secretariat, is_sdo_liaison_manager)
|
||||
from ietf.liaisons.models import LiaisonDetail, Uploads, OutgoingLiaisonApproval, SDOs
|
||||
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.group.models import Group, Role
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.doc.models import Document
|
||||
|
||||
|
||||
class LiaisonForm(forms.ModelForm):
|
||||
|
||||
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()
|
||||
to_poc = forms.CharField(widget=ReadOnlyWidget, label="POC", required=False)
|
||||
response_contact = forms.CharField(required=False, max_length=255)
|
||||
technical_contact = forms.CharField(required=False, max_length=255)
|
||||
cc1 = forms.CharField(widget=forms.Textarea, label="CC", required=False, help_text='Please insert one email address per line')
|
||||
purpose_text = forms.CharField(widget=forms.Textarea, label='Other purpose')
|
||||
purpose = forms.ChoiceField()
|
||||
deadline_date = forms.DateField(label='Deadline')
|
||||
submitted_date = forms.DateField(label='Submission date', initial=datetime.date.today())
|
||||
title = forms.CharField(label=u'Title')
|
||||
body = forms.CharField(widget=forms.Textarea, required=False)
|
||||
attachments = forms.CharField(label='Attachments', widget=ShowAttachmentsWidget, required=False)
|
||||
attach_title = forms.CharField(label='Title', required=False)
|
||||
attach_file = forms.FileField(label='File', required=False)
|
||||
|
@ -36,38 +41,51 @@ class LiaisonForm(forms.ModelForm):
|
|||
require=['id_attach_title', 'id_attach_file'],
|
||||
required_label='title and file'),
|
||||
required=False)
|
||||
related_to = forms.ModelChoiceField(LiaisonDetail.objects.all(), label=u'Related Liaison', widget=RelatedLiaisonWidget, required=False)
|
||||
related_to = forms.ModelChoiceField(LiaisonStatement.objects.all(), label=u'Related Liaison', widget=RelatedLiaisonWidget, required=False)
|
||||
|
||||
fieldsets = [('From', ('from_field', 'replyto')),
|
||||
('To', ('organization', 'to_poc')),
|
||||
('Other email addresses', ('response_contact', 'technical_contact', 'cc1')),
|
||||
('Purpose', ('purpose', 'purpose_text', 'deadline_date')),
|
||||
('Purpose', ('purpose', 'deadline_date')),
|
||||
('References', ('related_to', )),
|
||||
('Liaison Statement', ('title', 'submitted_date', 'body', 'attachments')),
|
||||
('Add attachment', ('attach_title', 'attach_file', 'attach_button')),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
model = LiaisonDetail
|
||||
|
||||
class Media:
|
||||
js = ("/js/jquery-1.5.1.min.js",
|
||||
"/js/jquery-ui-1.8.11.custom.min.js",
|
||||
"/js/liaisons.js", )
|
||||
|
||||
css = {'all': ("/css/liaisons.css",
|
||||
"/css/jquery-ui-themes/jquery-ui-1.8.11.custom.css")}
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
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 = PersonOrOrgInfo.objects.get(pk=kwargs['data']['from_fake_user'])
|
||||
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:
|
||||
self.initial["person"] = self.instance.from_contact.person_id if self.instance.from_contact else None
|
||||
self.initial["replyto"] = self.instance.reply_to
|
||||
self.initial["to_poc"] = self.instance.to_contact
|
||||
self.initial["response_contact"] = self.instance.response_contact
|
||||
self.initial["technical_contact"] = self.instance.technical_contact
|
||||
self.initial["cc1"] = self.instance.cc
|
||||
self.initial["purpose"] = self.instance.purpose.order
|
||||
self.initial["deadline_date"] = self.instance.deadline
|
||||
self.initial["submitted_date"] = self.instance.submitted.date() if self.instance.submitted else None
|
||||
self.initial["title"] = self.instance.title
|
||||
self.initial["body"] = self.instance.body
|
||||
self.initial["attachments"] = self.instance.attachments.all()
|
||||
self.initial["related_to"] = self.instance.related_to_id
|
||||
if "approved" in self.fields:
|
||||
self.initial["approved"] = bool(self.instance.approved)
|
||||
|
||||
self.fields["purpose"].choices = [("", "---------")] + [(str(l.order), l.name) for l in LiaisonStatementPurposeName.objects.all()]
|
||||
self.hm = IETFHM
|
||||
self.set_from_field()
|
||||
self.set_replyto_field()
|
||||
|
@ -81,25 +99,19 @@ class LiaisonForm(forms.ModelForm):
|
|||
|
||||
def set_required_fields(self):
|
||||
purpose = self.data.get('purpose', None)
|
||||
if purpose == '5':
|
||||
self.fields['purpose_text'].required=True
|
||||
else:
|
||||
self.fields['purpose_text'].required=False
|
||||
if purpose in ['1', '2']:
|
||||
self.fields['deadline_date'].required=True
|
||||
self.fields['deadline_date'].required = True
|
||||
else:
|
||||
self.fields['deadline_date'].required=False
|
||||
self.fields['deadline_date'].required = False
|
||||
|
||||
def reset_required_fields(self):
|
||||
self.fields['purpose_text'].required=True
|
||||
self.fields['deadline_date'].required=True
|
||||
self.fields['deadline_date'].required = True
|
||||
|
||||
def set_from_field(self):
|
||||
assert NotImplemented
|
||||
|
||||
def set_replyto_field(self):
|
||||
email = self.person.email()
|
||||
self.fields['replyto'].initial = email and email[1]
|
||||
self.fields['replyto'].initial = self.person.email()[1]
|
||||
|
||||
def set_organization_field(self):
|
||||
assert NotImplemented
|
||||
|
@ -171,7 +183,7 @@ class LiaisonForm(forms.ModelForm):
|
|||
return self.hm.get_entity_by_key(organization_key)
|
||||
|
||||
def get_poc(self, organization):
|
||||
return ', '.join([i.email()[1] 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', '')
|
||||
|
@ -191,34 +203,53 @@ class LiaisonForm(forms.ModelForm):
|
|||
return ','.join(result)
|
||||
|
||||
def get_cc(self, from_entity, to_entity):
|
||||
#Old automatic Cc code, now we retrive it from cleaned_data
|
||||
#persons = to_entity.get_cc(self.person)
|
||||
#persons += from_entity.get_from_cc(self.person)
|
||||
#return ', '.join(['%s <%s>' % i.email() for i in persons])
|
||||
cc = self.cleaned_data.get('cc1', '')
|
||||
return cc
|
||||
return self.cleaned_data.get('cc1', '')
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
liaison = super(LiaisonForm, self).save(*args, **kwargs)
|
||||
self.save_extra_fields(liaison)
|
||||
self.save_attachments(liaison)
|
||||
return liaison
|
||||
l = self.instance
|
||||
if not l:
|
||||
l = LiaisonStatement()
|
||||
|
||||
l.title = self.cleaned_data["title"]
|
||||
l.purpose = LiaisonStatementPurposeName.objects.get(order=self.cleaned_data["purpose"])
|
||||
l.body = self.cleaned_data["body"].strip()
|
||||
l.deadline = self.cleaned_data["deadline_date"]
|
||||
l.related_to = self.cleaned_data["related_to"]
|
||||
l.reply_to = self.cleaned_data["replyto"]
|
||||
l.response_contact = self.cleaned_data["response_contact"]
|
||||
l.technical_contact = self.cleaned_data["technical_contact"]
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
l.modified = now
|
||||
l.submitted = datetime.datetime.combine(self.cleaned_data["submitted_date"], now.time())
|
||||
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)
|
||||
|
||||
return l
|
||||
|
||||
def save_extra_fields(self, liaison):
|
||||
now = datetime.datetime.now()
|
||||
liaison.last_modified_date = now
|
||||
from_entity = self.get_from_entity()
|
||||
liaison.from_raw_body = from_entity.name
|
||||
liaison.from_raw_code = self.cleaned_data.get('from_field')
|
||||
liaison.from_name = from_entity.name
|
||||
liaison.from_group = from_entity.obj
|
||||
e = self.cleaned_data["person"].email_set.order_by('-active', '-time')
|
||||
if e:
|
||||
liaison.from_contact = e[0]
|
||||
|
||||
organization = self.get_to_entity()
|
||||
liaison.to_raw_code = self.cleaned_data.get('organization')
|
||||
liaison.to_body = organization.name
|
||||
liaison.to_poc = self.get_poc(organization)
|
||||
liaison.submitter_name, liaison.submitter_email = self.person.email()
|
||||
liaison.cc1 = self.get_cc(from_entity, organization)
|
||||
liaison.save()
|
||||
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):
|
||||
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():
|
||||
|
@ -229,13 +260,18 @@ class LiaisonForm(forms.ModelForm):
|
|||
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.get_or_create(
|
||||
name = name,
|
||||
defaults=dict(
|
||||
title = self.data.get(title_key),
|
||||
type_id = "liai-att",
|
||||
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()
|
||||
|
||||
|
@ -245,8 +281,7 @@ class LiaisonForm(forms.ModelForm):
|
|||
exclude_filter = {'pk': self.instance.pk}
|
||||
else:
|
||||
exclude_filter = {}
|
||||
exists = bool(LiaisonDetail.objects.exclude(**exclude_filter).filter(title__iexact=title).count())
|
||||
if exists:
|
||||
if LiaisonStatement.objects.exclude(**exclude_filter).filter(title__iexact=title).exists():
|
||||
raise forms.ValidationError('A liaison statement with the same title has previously been submitted.')
|
||||
return title
|
||||
|
||||
|
@ -255,20 +290,26 @@ class IncomingLiaisonForm(LiaisonForm):
|
|||
|
||||
def set_from_field(self):
|
||||
if is_secretariat(self.user):
|
||||
sdos = SDOs.objects.all()
|
||||
sdos = Group.objects.filter(type="sdo", state="active")
|
||||
else:
|
||||
sdo_managed = [i.sdo for i in self.person.liaisonmanagers_set.all()]
|
||||
sdo_authorized = [i.sdo for i in self.person.sdoauthorizedindividual_set.all()]
|
||||
sdos = set(sdo_managed).union(sdo_authorized)
|
||||
self.fields['from_field'].choices = [('sdo_%s' % i.pk, i.sdo_name) for i in sdos]
|
||||
sdos = Group.objects.filter(type="sdo", state="active", role__person=self.person, role__name__in=("liaiman", "auth")).distinct()
|
||||
self.fields['from_field'].choices = [('sdo_%s' % i.pk, i.name) for i in sdos.order_by("name")]
|
||||
self.fields['from_field'].widget.submitter = unicode(self.person)
|
||||
|
||||
def set_replyto_field(self):
|
||||
e = Email.objects.filter(person=self.person, role__group__state="active", role__name__in=["liaiman", "auth"])
|
||||
if e:
|
||||
addr = e[0].address
|
||||
else:
|
||||
addr = self.person.email_address()
|
||||
self.fields['replyto'].initial = addr
|
||||
|
||||
def set_organization_field(self):
|
||||
self.fields['organization'].choices = self.hm.get_all_incoming_entities()
|
||||
|
||||
def get_post_only(self):
|
||||
from_entity = self.get_from_entity()
|
||||
if is_secretariat(self.user) or self.person.sdoauthorizedindividual_set.filter(sdo=from_entity.obj):
|
||||
if is_secretariat(self.user) or Role.objects.filter(person=self.person, group=from_entity.obj, name="auth"):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -278,6 +319,9 @@ class IncomingLiaisonForm(LiaisonForm):
|
|||
return super(IncomingLiaisonForm, self).clean()
|
||||
|
||||
|
||||
def liaison_manager_sdos(person):
|
||||
return Group.objects.filter(type="sdo", state="active", role__person=person, role__name="liaiman").distinct()
|
||||
|
||||
class OutgoingLiaisonForm(LiaisonForm):
|
||||
|
||||
to_poc = forms.CharField(label="POC", required=True)
|
||||
|
@ -301,17 +345,24 @@ class OutgoingLiaisonForm(LiaisonForm):
|
|||
all_entities += i[1]
|
||||
if all_entities:
|
||||
self.fields['from_field'].widget.full_power_on = [i[0] for i in all_entities]
|
||||
self.fields['from_field'].widget.reduced_to_set = ['sdo_%s' % i.sdo.pk for i in self.person.liaisonmanagers_set.all().distinct()]
|
||||
self.fields['from_field'].widget.reduced_to_set = ['sdo_%s' % i.pk for i in liaison_manager_sdos(self.person)]
|
||||
else:
|
||||
self.fields['from_field'].choices = self.hm.get_entities_for_person(self.person)
|
||||
self.fields['from_field'].widget.submitter = unicode(self.person)
|
||||
self.fieldsets[0] = ('From', ('from_field', 'replyto', 'approved'))
|
||||
|
||||
def set_replyto_field(self):
|
||||
e = Email.objects.filter(person=self.person, role__group__state="active", role__name__in=["ad", "chair"])
|
||||
if e:
|
||||
addr = e[0].address
|
||||
else:
|
||||
addr = self.person.email_address()
|
||||
self.fields['replyto'].initial = addr
|
||||
|
||||
def set_organization_field(self):
|
||||
# If the user is a liaison manager and is nothing more, reduce the To field to his SDOs
|
||||
if not self.hm.get_entities_for_person(self.person) and is_sdo_liaison_manager(self.person):
|
||||
sdos = [i.sdo for i in self.person.liaisonmanagers_set.all().distinct()]
|
||||
self.fields['organization'].choices = [('sdo_%s' % i.pk, i.sdo_name) for i in sdos]
|
||||
self.fields['organization'].choices = [('sdo_%s' % i.pk, i.name) for i in liaison_manager_sdos(self.person)]
|
||||
else:
|
||||
self.fields['organization'].choices = self.hm.get_all_outgoing_entities()
|
||||
self.fieldsets[1] = ('To', ('organization', 'other_organization', 'to_poc'))
|
||||
|
@ -336,16 +387,9 @@ class OutgoingLiaisonForm(LiaisonForm):
|
|||
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)
|
||||
|
@ -361,10 +405,10 @@ class OutgoingLiaisonForm(LiaisonForm):
|
|||
person = self.fake_person or self.person
|
||||
for i in self.hm.get_entities_for_person(person):
|
||||
all_entities += i[1]
|
||||
# If the from entity is one in which the user has full privileges the to entity could be anyone
|
||||
# If the from entity is one in wich the user has full privileges the to entity could be anyone
|
||||
if from_code in [i[0] for i in all_entities]:
|
||||
return to_code
|
||||
sdo_codes = ['sdo_%s' % i.sdo.pk for i in person.liaisonmanagers_set.all().distinct()]
|
||||
sdo_codes = ['sdo_%s' % i.pk for i in liaison_manager_sdos(person)]
|
||||
if to_code in sdo_codes:
|
||||
return to_code
|
||||
entity = self.get_to_entity()
|
||||
|
@ -384,35 +428,28 @@ class EditLiaisonForm(LiaisonForm):
|
|||
cc1 = forms.CharField(widget=forms.TextInput, label="CC", required=False)
|
||||
|
||||
class Meta:
|
||||
model = LiaisonDetail
|
||||
fields = ('from_raw_body', 'to_body', 'to_poc', 'cc1', 'last_modified_date', 'title',
|
||||
'response_contact', 'technical_contact', 'purpose_text', 'body',
|
||||
'response_contact', 'technical_contact', 'body',
|
||||
'deadline_date', 'purpose', 'replyto', 'related_to')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EditLiaisonForm, self).__init__(*args, **kwargs)
|
||||
self.edit = True
|
||||
self.initial.update({'attachments': self.instance.uploads_set.all()})
|
||||
self.fields['submitted_date'].initial = self.instance.submitted_date
|
||||
|
||||
def set_from_field(self):
|
||||
self.fields['from_field'].initial = self.instance.from_body
|
||||
self.fields['from_field'].initial = self.instance.from_name
|
||||
|
||||
def set_replyto_field(self):
|
||||
self.fields['replyto'].initial = self.instance.replyto
|
||||
self.fields['replyto'].initial = self.instance.reply_to
|
||||
|
||||
def set_organization_field(self):
|
||||
self.fields['organization'].initial = self.instance.to_body
|
||||
self.fields['organization'].initial = self.instance.to_name
|
||||
|
||||
def save_extra_fields(self, liaison):
|
||||
now = datetime.datetime.now()
|
||||
liaison.last_modified_date = now
|
||||
liaison.from_raw_body = self.cleaned_data.get('from_field')
|
||||
liaison.to_body = self.cleaned_data.get('organization')
|
||||
liaison.to_poc = self.cleaned_data['to_poc']
|
||||
liaison.cc1 = self.cleaned_data['cc1']
|
||||
liaison.save()
|
||||
|
||||
liaison.from_name = self.cleaned_data.get('from_field')
|
||||
liaison.to_name = self.cleaned_data.get('organization')
|
||||
liaison.to_contact = self.cleaned_data['to_poc']
|
||||
liaison.cc = self.cleaned_data['cc1']
|
||||
|
||||
def liaison_form_factory(request, **kwargs):
|
||||
user = request.user
|
||||
|
@ -426,5 +463,3 @@ def liaison_form_factory(request, **kwargs):
|
|||
return IncomingLiaisonForm(user, **kwargs)
|
||||
return None
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.formsREDESIGN import *
|
||||
|
|
|
@ -1,474 +0,0 @@
|
|||
import datetime, os
|
||||
from email.utils import parseaddr
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
from django.forms.util import ErrorList
|
||||
from django.core.validators import email_re
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from ietf.liaisons.accounts import (can_add_outgoing_liaison, can_add_incoming_liaison,
|
||||
get_person_for_user, is_secretariat, is_sdo_liaison_manager)
|
||||
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 ietf.group.models import Group, Role
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.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()
|
||||
to_poc = forms.CharField(widget=ReadOnlyWidget, label="POC", required=False)
|
||||
response_contact = forms.CharField(required=False, max_length=255)
|
||||
technical_contact = forms.CharField(required=False, max_length=255)
|
||||
cc1 = forms.CharField(widget=forms.Textarea, label="CC", required=False, help_text='Please insert one email address per line')
|
||||
purpose = forms.ChoiceField()
|
||||
purpose_text = forms.CharField(widget=forms.Textarea, label='Other purpose')
|
||||
deadline_date = forms.DateField(label='Deadline')
|
||||
submitted_date = forms.DateField(label='Submission date', initial=datetime.date.today())
|
||||
title = forms.CharField(label=u'Title')
|
||||
body = forms.CharField(widget=forms.Textarea, required=False)
|
||||
attachments = forms.CharField(label='Attachments', widget=ShowAttachmentsWidget, required=False)
|
||||
attach_title = forms.CharField(label='Title', required=False)
|
||||
attach_file = forms.FileField(label='File', required=False)
|
||||
attach_button = forms.CharField(label='',
|
||||
widget=ButtonWidget(label='Attach', show_on='id_attachments',
|
||||
require=['id_attach_title', 'id_attach_file'],
|
||||
required_label='title and file'),
|
||||
required=False)
|
||||
related_to = forms.ModelChoiceField(LiaisonStatement.objects.all(), label=u'Related Liaison', widget=RelatedLiaisonWidget, required=False)
|
||||
|
||||
fieldsets = [('From', ('from_field', 'replyto')),
|
||||
('To', ('organization', 'to_poc')),
|
||||
('Other email addresses', ('response_contact', 'technical_contact', 'cc1')),
|
||||
('Purpose', ('purpose', 'purpose_text', 'deadline_date')),
|
||||
('References', ('related_to', )),
|
||||
('Liaison Statement', ('title', 'submitted_date', 'body', 'attachments')),
|
||||
('Add attachment', ('attach_title', 'attach_file', 'attach_button')),
|
||||
]
|
||||
|
||||
class Media:
|
||||
js = ("/js/jquery-1.5.1.min.js",
|
||||
"/js/jquery-ui-1.8.11.custom.min.js",
|
||||
"/js/liaisons.js", )
|
||||
|
||||
css = {'all': ("/css/liaisons.css",
|
||||
"/css/jquery-ui-themes/jquery-ui-1.8.11.custom.css")}
|
||||
|
||||
def __init__(self, user, *args, **kwargs):
|
||||
self.user = user
|
||||
self.fake_person = None
|
||||
self.person = get_person_for_user(user)
|
||||
if kwargs.get('data', None):
|
||||
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():
|
||||
try:
|
||||
x = getattr(self.instance, name)
|
||||
if name == "purpose": # proxy has a name-clash on purpose so help it
|
||||
x = x.order
|
||||
|
||||
try:
|
||||
x = x.pk # foreign keys need the .pk, not the actual object
|
||||
except AttributeError:
|
||||
pass
|
||||
self.initial[name] = x
|
||||
except AttributeError:
|
||||
# we have some fields on the form that aren't in the model
|
||||
pass
|
||||
self.fields["purpose"].choices = [("", "---------")] + [(str(l.order), l.name) for l in LiaisonStatementPurposeName.objects.all()]
|
||||
self.hm = IETFHM
|
||||
self.set_from_field()
|
||||
self.set_replyto_field()
|
||||
self.set_organization_field()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.as_div()
|
||||
|
||||
def get_post_only(self):
|
||||
return False
|
||||
|
||||
def set_required_fields(self):
|
||||
purpose = self.data.get('purpose', None)
|
||||
if purpose == '5':
|
||||
self.fields['purpose_text'].required=True
|
||||
else:
|
||||
self.fields['purpose_text'].required=False
|
||||
if purpose in ['1', '2']:
|
||||
self.fields['deadline_date'].required=True
|
||||
else:
|
||||
self.fields['deadline_date'].required=False
|
||||
|
||||
def reset_required_fields(self):
|
||||
self.fields['purpose_text'].required=True
|
||||
self.fields['deadline_date'].required=True
|
||||
|
||||
def set_from_field(self):
|
||||
assert NotImplemented
|
||||
|
||||
def set_replyto_field(self):
|
||||
self.fields['replyto'].initial = self.person.email()[1]
|
||||
|
||||
def set_organization_field(self):
|
||||
assert NotImplemented
|
||||
|
||||
def as_div(self):
|
||||
return render_to_string('liaisons/liaisonform.html', {'form': self})
|
||||
|
||||
def get_fieldsets(self):
|
||||
if not self.fieldsets:
|
||||
yield dict(name=None, fields=self)
|
||||
else:
|
||||
for fieldset, fields in self.fieldsets:
|
||||
fieldset_dict = dict(name=fieldset, fields=[])
|
||||
for field_name in fields:
|
||||
if field_name in self.fields.keyOrder:
|
||||
fieldset_dict['fields'].append(self[field_name])
|
||||
if not fieldset_dict['fields']:
|
||||
# if there is no fields in this fieldset, we continue to next fieldset
|
||||
continue
|
||||
yield fieldset_dict
|
||||
|
||||
def full_clean(self):
|
||||
self.set_required_fields()
|
||||
super(LiaisonForm, self).full_clean()
|
||||
self.reset_required_fields()
|
||||
|
||||
def has_attachments(self):
|
||||
for key in self.files.keys():
|
||||
if key.startswith('attach_file_') and key.replace('file', 'title') in self.data.keys():
|
||||
return True
|
||||
return False
|
||||
|
||||
def check_email(self, value):
|
||||
if not value:
|
||||
return
|
||||
emails = value.split(',')
|
||||
for email in emails:
|
||||
name, addr = parseaddr(email)
|
||||
if not email_re.search(addr):
|
||||
raise forms.ValidationError('Invalid email address: %s' % addr)
|
||||
|
||||
def clean_response_contact(self):
|
||||
value = self.cleaned_data.get('response_contact', None)
|
||||
self.check_email(value)
|
||||
return value
|
||||
|
||||
def clean_technical_contact(self):
|
||||
value = self.cleaned_data.get('technical_contact', None)
|
||||
self.check_email(value)
|
||||
return value
|
||||
|
||||
def clean_reply_to(self):
|
||||
value = self.cleaned_data.get('reply_to', None)
|
||||
self.check_email(value)
|
||||
return value
|
||||
|
||||
def clean(self):
|
||||
if not self.cleaned_data.get('body', None) and not self.has_attachments():
|
||||
self._errors['body'] = ErrorList([u'You must provide a body or attachment files'])
|
||||
self._errors['attachments'] = ErrorList([u'You must provide a body or attachment files'])
|
||||
return self.cleaned_data
|
||||
|
||||
def get_from_entity(self):
|
||||
organization_key = self.cleaned_data.get('from_field')
|
||||
return self.hm.get_entity_by_key(organization_key)
|
||||
|
||||
def get_to_entity(self):
|
||||
organization_key = self.cleaned_data.get('organization')
|
||||
return self.hm.get_entity_by_key(organization_key)
|
||||
|
||||
def get_poc(self, organization):
|
||||
return ', '.join(u"%s <%s>" % i.email() for i in organization.get_poc())
|
||||
|
||||
def clean_cc1(self):
|
||||
value = self.cleaned_data.get('cc1', '')
|
||||
result = []
|
||||
errors = []
|
||||
for address in value.split('\n'):
|
||||
address = address.strip();
|
||||
if not address:
|
||||
continue
|
||||
try:
|
||||
self.check_email(address)
|
||||
except forms.ValidationError:
|
||||
errors.append(address)
|
||||
result.append(address)
|
||||
if errors:
|
||||
raise forms.ValidationError('Invalid email addresses: %s' % ', '.join(errors))
|
||||
return ','.join(result)
|
||||
|
||||
def get_cc(self, from_entity, to_entity):
|
||||
#Old automatic Cc code, now we retrive it from cleaned_data
|
||||
#persons = to_entity.get_cc(self.person)
|
||||
#persons += from_entity.get_from_cc(self.person)
|
||||
#return ', '.join(['%s <%s>' % i.email() for i in persons])
|
||||
cc = self.cleaned_data.get('cc1', '')
|
||||
return cc
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
l = self.instance
|
||||
if not l:
|
||||
l = LiaisonDetailProxy()
|
||||
|
||||
l.title = self.cleaned_data["title"]
|
||||
l.purpose = LiaisonStatementPurposeName.objects.get(order=self.cleaned_data["purpose"])
|
||||
l.body = self.cleaned_data["body"].strip()
|
||||
l.deadline = self.cleaned_data["deadline_date"]
|
||||
l.related_to = self.cleaned_data["related_to"]
|
||||
l.reply_to = self.cleaned_data["replyto"]
|
||||
l.response_contact = self.cleaned_data["response_contact"]
|
||||
l.technical_contact = self.cleaned_data["technical_contact"]
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
l.modified = now
|
||||
l.submitted = datetime.datetime.combine(self.cleaned_data["submitted_date"], now.time())
|
||||
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)
|
||||
|
||||
return l
|
||||
|
||||
def save_extra_fields(self, liaison):
|
||||
from_entity = self.get_from_entity()
|
||||
liaison.from_name = from_entity.name
|
||||
liaison.from_group = from_entity.obj
|
||||
e = self.cleaned_data["person"].email_set.order_by('-active')
|
||||
if e:
|
||||
liaison.from_contact = e[0]
|
||||
|
||||
organization = self.get_to_entity()
|
||||
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):
|
||||
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():
|
||||
continue
|
||||
attached_file = self.files.get(key)
|
||||
extension=attached_file.name.rsplit('.', 1)
|
||||
if len(extension) > 1:
|
||||
extension = '.' + extension[1]
|
||||
else:
|
||||
extension = ''
|
||||
written += 1
|
||||
name = instance.name() + ("-attachment-%s" % written)
|
||||
attach, _ = Document.objects.get_or_create(
|
||||
name = name,
|
||||
defaults=dict(
|
||||
title = self.data.get(title_key),
|
||||
type_id = "liai-att",
|
||||
external_url = name + extension, # strictly speaking not necessary, but just for the time being ...
|
||||
)
|
||||
)
|
||||
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()
|
||||
|
||||
def clean_title(self):
|
||||
title = self.cleaned_data.get('title', None)
|
||||
if self.instance and self.instance.pk:
|
||||
exclude_filter = {'pk': self.instance.pk}
|
||||
else:
|
||||
exclude_filter = {}
|
||||
exists = bool(LiaisonStatement.objects.exclude(**exclude_filter).filter(title__iexact=title).count())
|
||||
if exists:
|
||||
raise forms.ValidationError('A liaison statement with the same title has previously been submitted.')
|
||||
return title
|
||||
|
||||
|
||||
class IncomingLiaisonForm(LiaisonForm):
|
||||
|
||||
def set_from_field(self):
|
||||
if is_secretariat(self.user):
|
||||
sdos = Group.objects.filter(type="sdo", state="active")
|
||||
else:
|
||||
sdos = Group.objects.filter(type="sdo", state="active", role__person=self.person, role__name__in=("liaiman", "auth")).distinct()
|
||||
self.fields['from_field'].choices = [('sdo_%s' % i.pk, i.name) for i in sdos.order_by("name")]
|
||||
self.fields['from_field'].widget.submitter = unicode(self.person)
|
||||
|
||||
def set_replyto_field(self):
|
||||
e = Email.objects.filter(person=self.person, role__group__state="active", role__name__in=["liaiman", "auth"])
|
||||
if e:
|
||||
addr = e[0].address
|
||||
else:
|
||||
addr = self.person.email_address()
|
||||
self.fields['replyto'].initial = addr
|
||||
|
||||
def set_organization_field(self):
|
||||
self.fields['organization'].choices = self.hm.get_all_incoming_entities()
|
||||
|
||||
def get_post_only(self):
|
||||
from_entity = self.get_from_entity()
|
||||
if is_secretariat(self.user) or Role.objects.filter(person=self.person, group=from_entity.obj, name="auth"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def clean(self):
|
||||
if 'send' in self.data.keys() and self.get_post_only():
|
||||
self._errors['from_field'] = ErrorList([u'As an IETF Liaison Manager you can not send an incoming liaison statements, you only can post them'])
|
||||
return super(IncomingLiaisonForm, self).clean()
|
||||
|
||||
|
||||
def liaison_manager_sdos(person):
|
||||
return Group.objects.filter(type="sdo", state="active", role__person=person, role__name="liaiman").distinct()
|
||||
|
||||
class OutgoingLiaisonForm(LiaisonForm):
|
||||
|
||||
to_poc = forms.CharField(label="POC", required=True)
|
||||
approved = forms.BooleanField(label="Obtained prior approval", required=False)
|
||||
other_organization = forms.CharField(label="Other SDO", required=True)
|
||||
|
||||
def get_to_entity(self):
|
||||
organization_key = self.cleaned_data.get('organization')
|
||||
organization = self.hm.get_entity_by_key(organization_key)
|
||||
if organization_key == 'othersdo' and self.cleaned_data.get('other_organization', None):
|
||||
organization.name=self.cleaned_data['other_organization']
|
||||
return organization
|
||||
|
||||
def set_from_field(self):
|
||||
if is_secretariat(self.user):
|
||||
self.fields['from_field'].choices = self.hm.get_all_incoming_entities()
|
||||
elif is_sdo_liaison_manager(self.person):
|
||||
self.fields['from_field'].choices = self.hm.get_all_incoming_entities()
|
||||
all_entities = []
|
||||
for i in self.hm.get_entities_for_person(self.person):
|
||||
all_entities += i[1]
|
||||
if all_entities:
|
||||
self.fields['from_field'].widget.full_power_on = [i[0] for i in all_entities]
|
||||
self.fields['from_field'].widget.reduced_to_set = ['sdo_%s' % i.pk for i in liaison_manager_sdos(self.person)]
|
||||
else:
|
||||
self.fields['from_field'].choices = self.hm.get_entities_for_person(self.person)
|
||||
self.fields['from_field'].widget.submitter = unicode(self.person)
|
||||
self.fieldsets[0] = ('From', ('from_field', 'replyto', 'approved'))
|
||||
|
||||
def set_replyto_field(self):
|
||||
e = Email.objects.filter(person=self.person, role__group__state="active", role__name__in=["ad", "chair"])
|
||||
if e:
|
||||
addr = e[0].address
|
||||
else:
|
||||
addr = self.person.email_address()
|
||||
self.fields['replyto'].initial = addr
|
||||
|
||||
def set_organization_field(self):
|
||||
# If the user is a liaison manager and is nothing more, reduce the To field to his SDOs
|
||||
if not self.hm.get_entities_for_person(self.person) and is_sdo_liaison_manager(self.person):
|
||||
self.fields['organization'].choices = [('sdo_%s' % i.pk, i.name) for i in liaison_manager_sdos(self.person)]
|
||||
else:
|
||||
self.fields['organization'].choices = self.hm.get_all_outgoing_entities()
|
||||
self.fieldsets[1] = ('To', ('organization', 'other_organization', 'to_poc'))
|
||||
|
||||
def set_required_fields(self):
|
||||
super(OutgoingLiaisonForm, self).set_required_fields()
|
||||
organization = self.data.get('organization', None)
|
||||
if organization == 'othersdo':
|
||||
self.fields['other_organization'].required=True
|
||||
else:
|
||||
self.fields['other_organization'].required=False
|
||||
|
||||
def reset_required_fields(self):
|
||||
super(OutgoingLiaisonForm, self).reset_required_fields()
|
||||
self.fields['other_organization'].required=True
|
||||
|
||||
def get_poc(self, organization):
|
||||
return self.cleaned_data['to_poc']
|
||||
|
||||
def save_extra_fields(self, liaison):
|
||||
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):
|
||||
liaison.approved = datetime.datetime.now()
|
||||
else:
|
||||
liaison.approved = None
|
||||
|
||||
def clean_to_poc(self):
|
||||
value = self.cleaned_data.get('to_poc', None)
|
||||
self.check_email(value)
|
||||
return value
|
||||
|
||||
def clean_organization(self):
|
||||
to_code = self.cleaned_data.get('organization', None)
|
||||
from_code = self.cleaned_data.get('from_field', None)
|
||||
if not to_code or not from_code:
|
||||
return to_code
|
||||
all_entities = []
|
||||
person = self.fake_person or self.person
|
||||
for i in self.hm.get_entities_for_person(person):
|
||||
all_entities += i[1]
|
||||
# If the from entity is one in wich the user has full privileges the to entity could be anyone
|
||||
if from_code in [i[0] for i in all_entities]:
|
||||
return to_code
|
||||
sdo_codes = ['sdo_%s' % i.pk for i in liaison_manager_sdos(person)]
|
||||
if to_code in sdo_codes:
|
||||
return to_code
|
||||
entity = self.get_to_entity()
|
||||
entity_name = entity and entity.name or to_code
|
||||
if self.fake_person:
|
||||
raise forms.ValidationError('%s is not allowed to send a liaison to: %s' % (self.fake_person, entity_name))
|
||||
else:
|
||||
raise forms.ValidationError('You are not allowed to send a liaison to: %s' % entity_name)
|
||||
|
||||
|
||||
class EditLiaisonForm(LiaisonForm):
|
||||
|
||||
from_field = forms.CharField(widget=forms.TextInput, label=u'From')
|
||||
replyto = forms.CharField(label=u'Reply to', widget=forms.TextInput)
|
||||
organization = forms.CharField(widget=forms.TextInput)
|
||||
to_poc = forms.CharField(widget=forms.TextInput, label="POC", required=False)
|
||||
cc1 = forms.CharField(widget=forms.TextInput, label="CC", required=False)
|
||||
|
||||
class Meta:
|
||||
fields = ('from_raw_body', 'to_body', 'to_poc', 'cc1', 'last_modified_date', 'title',
|
||||
'response_contact', 'technical_contact', 'purpose_text', 'body',
|
||||
'deadline_date', 'purpose', 'replyto', 'related_to')
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(EditLiaisonForm, self).__init__(*args, **kwargs)
|
||||
self.edit = True
|
||||
self.initial.update({'attachments': self.instance.uploads_set.all()})
|
||||
self.fields['submitted_date'].initial = self.instance.submitted_date
|
||||
|
||||
def set_from_field(self):
|
||||
self.fields['from_field'].initial = self.instance.from_body
|
||||
|
||||
def set_replyto_field(self):
|
||||
self.fields['replyto'].initial = self.instance.replyto
|
||||
|
||||
def set_organization_field(self):
|
||||
self.fields['organization'].initial = self.instance.to_body
|
||||
|
||||
def save_extra_fields(self, liaison):
|
||||
liaison.from_name = self.cleaned_data.get('from_field')
|
||||
liaison.to_name = self.cleaned_data.get('organization')
|
||||
liaison.to_contact = self.cleaned_data['to_poc']
|
||||
liaison.cc = self.cleaned_data['cc1']
|
||||
|
|
@ -8,14 +8,11 @@ from ietf.utils.mail import send_mail_text
|
|||
from ietf.liaisons.utils import role_persons_with_fixed_email
|
||||
from ietf.group.models import Role
|
||||
|
||||
def send_liaison_by_email(request, liaison, fake=False):
|
||||
if liaison.is_pending(): # this conditional should definitely be at the caller, not here
|
||||
return notify_pending_by_email(request, liaison, fake)
|
||||
|
||||
def send_liaison_by_email(request, liaison):
|
||||
subject = u'New Liaison Statement, "%s"' % (liaison.title)
|
||||
from_email = settings.LIAISON_UNIVERSAL_FROM
|
||||
to_email = liaison.to_poc.split(',')
|
||||
cc = liaison.cc1.split(',')
|
||||
to_email = liaison.to_contact.split(',')
|
||||
cc = liaison.cc.split(',')
|
||||
if liaison.technical_contact:
|
||||
cc += liaison.technical_contact.split(',')
|
||||
if liaison.response_contact:
|
||||
|
@ -29,7 +26,7 @@ def send_liaison_by_email(request, liaison, fake=False):
|
|||
|
||||
send_mail_text(request, to_email, from_email, subject, body, cc=", ".join(cc), bcc=", ".join(bcc))
|
||||
|
||||
def notify_pending_by_email(request, liaison, fake):
|
||||
def notify_pending_by_email(request, liaison):
|
||||
|
||||
# Broken: this does not find the list of approvers for the sending body
|
||||
# For now, we are sending to statements@ietf.org so the Secretariat can nudge
|
||||
|
|
|
@ -5,78 +5,19 @@ from django.core.management.base import BaseCommand
|
|||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.liaisons.models import LiaisonDetail
|
||||
#from ietf.liaisons.mail import IETFEmailMessage
|
||||
from ietf.utils.mail import send_mail_text
|
||||
|
||||
|
||||
PREVIOUS_DAYS = {
|
||||
14: 'in two weeks',
|
||||
7: 'in one week',
|
||||
4: 'in four days',
|
||||
3: 'in three days',
|
||||
2: 'in two days',
|
||||
1: 'tomorrow',
|
||||
0: 'today'}
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
from ietf.liaisons.mails import possibly_send_deadline_reminder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = (u"Check liaison deadlines and send a reminder if we are close to a deadline")
|
||||
|
||||
def send_reminder(self, liaison, days_to_go):
|
||||
if days_to_go < 0:
|
||||
subject = '[Liaison OUT OF DATE] %s' % liaison.title
|
||||
days_msg = 'is out of date for %s days' % (-days_to_go)
|
||||
else:
|
||||
subject = '[Liaison deadline %s] %s' % (PREVIOUS_DAYS[days_to_go], liaison.title)
|
||||
days_msg = 'expires %s' % PREVIOUS_DAYS[days_to_go]
|
||||
|
||||
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_deadline_mail.txt',
|
||||
{'liaison': liaison,
|
||||
'days_msg': days_msg,
|
||||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.related_to.pk)) if liaison.related_to else None,
|
||||
})
|
||||
send_mail_text(context=None,to=to_email,frm=from_email,cc=cc,subject=subject,bcc=bcc,txt=body)
|
||||
print 'Liaison %05s#: Deadline reminder Sent!' % liaison.pk
|
||||
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# cc=cc,
|
||||
# bcc=bcc,
|
||||
# body=body)
|
||||
#if not settings.DEBUG:
|
||||
# mail.send()
|
||||
# print 'Liaison %05s#: Deadline reminder Sent!' % liaison.pk
|
||||
#else:
|
||||
# print 'Liaison %05s#: Deadline reminder Not Sent because in DEBUG mode!' % liaison.pk
|
||||
|
||||
def handle(self, *args, **options):
|
||||
today = datetime.date.today()
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.mails import possibly_send_deadline_reminder
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
|
||||
cutoff = today - datetime.timedelta(14)
|
||||
|
||||
for l in LiaisonDetail.objects.filter(action_taken=False, deadline__gte=cutoff).exclude(deadline=None):
|
||||
r = possibly_send_deadline_reminder(l)
|
||||
if r:
|
||||
print 'Liaison %05s#: Deadline reminder sent!' % liaison.pk
|
||||
return
|
||||
|
||||
query = LiaisonDetail.objects.filter(deadline_date__isnull=False, action_taken=False, deadline_date__gte=today - datetime.timedelta(14))
|
||||
for liaison in query:
|
||||
delta = liaison.deadline_date - today
|
||||
if delta.days < 0 or delta.days in PREVIOUS_DAYS.keys():
|
||||
self.send_reminder(liaison, delta.days)
|
||||
cutoff = today - datetime.timedelta(14)
|
||||
|
||||
for l in LiaisonStatement.objects.filter(action_taken=False, deadline__gte=cutoff).exclude(deadline=None):
|
||||
r = possibly_send_deadline_reminder(l)
|
||||
if r:
|
||||
print 'Liaison %05s#: Deadline reminder sent!' % liaison.pk
|
||||
|
|
|
@ -5,7 +5,8 @@ from django.core.mail import EmailMessage
|
|||
from django.core.management.base import BaseCommand
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from ietf.liaisons.models import SDOs
|
||||
from ietf.group.models import Group
|
||||
from ietf.liaisons.mails import send_sdo_reminder
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -16,56 +17,15 @@ class Command(BaseCommand):
|
|||
)
|
||||
|
||||
|
||||
def send_mail_to(self, person, sdo):
|
||||
subject = 'Request for update list of authorized individuals'
|
||||
email = person.email()[1]
|
||||
name = ' '.join([i for i in (person.name_prefix, person.first_name, person.middle_initial, person.last_name, person.name_suffix) if i])
|
||||
authorized_list = [i.person for i in sdo.sdoauthorizedindividual_set.all()]
|
||||
body = render_to_string('liaisons/sdo_reminder.txt',
|
||||
{'manager_name': name,
|
||||
'sdo_name': sdo.sdo_name,
|
||||
'individuals': authorized_list,
|
||||
})
|
||||
mail = EmailMessage(subject=subject,
|
||||
to=[email],
|
||||
from_email=settings.LIAISON_UNIVERSAL_FROM,
|
||||
body = body)
|
||||
if not settings.DEBUG:
|
||||
mail.send()
|
||||
msg = '%05s#: %s Mail Sent!' % (sdo.pk, sdo.sdo_name)
|
||||
else:
|
||||
msg = '%05s#: %s Mail Not Sent because in DEBUG mode!' % (sdo.pk, sdo.sdo_name)
|
||||
return msg
|
||||
|
||||
def handle(self, *args, **options):
|
||||
sdo_pk = options.get('sdo_pk', None)
|
||||
return_output = options.get('return_output', False)
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
msg_list = send_reminders_to_sdos(sdo_pk=sdo_pk)
|
||||
return msg_list if return_output else None
|
||||
|
||||
query = SDOs.objects.all().order_by('pk')
|
||||
if sdo_pk:
|
||||
query = query.filter(pk=sdo_pk)
|
||||
|
||||
msg_list = []
|
||||
for sdo in query:
|
||||
manager = sdo.liaisonmanager()
|
||||
if manager:
|
||||
msg = self.send_mail_to(manager.person, sdo)
|
||||
else:
|
||||
msg = '%05s#: %s has no liaison manager' % (sdo.pk, sdo.sdo_name)
|
||||
print msg
|
||||
msg_list.append(msg)
|
||||
if return_output:
|
||||
return msg_list
|
||||
msg_list = send_reminders_to_sdos(sdo_pk=sdo_pk)
|
||||
return msg_list if return_output else None
|
||||
|
||||
|
||||
def send_reminders_to_sdos(sdo_pk=None):
|
||||
from ietf.group.models import Group
|
||||
from ietf.liaisons.mails import send_sdo_reminder
|
||||
|
||||
sdos = Group.objects.filter(type="sdo").order_by('pk')
|
||||
if sdo_pk:
|
||||
sdos = sdos.filter(pk=sdo_pk)
|
||||
|
|
|
@ -1,369 +1,52 @@
|
|||
# Copyright The IETF Trust 2007, All Rights Reserved
|
||||
|
||||
from django.conf import settings
|
||||
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.utils.mail import send_mail_text
|
||||
from ietf.ietfauth.models import LegacyLiaisonUser
|
||||
from ietf.utils.admin import admin_link
|
||||
|
||||
class LiaisonPurpose(models.Model):
|
||||
purpose_id = models.AutoField(primary_key=True)
|
||||
purpose_text = models.CharField(blank=True, max_length=50)
|
||||
def __str__(self):
|
||||
return self.purpose_text
|
||||
class Meta:
|
||||
db_table = 'liaison_purpose'
|
||||
|
||||
class FromBodies(models.Model):
|
||||
from_id = models.AutoField(primary_key=True)
|
||||
body_name = models.CharField(blank=True, max_length=35)
|
||||
poc = models.ForeignKey(PersonOrOrgInfo, db_column='poc', null=True)
|
||||
is_liaison_manager = models.BooleanField()
|
||||
other_sdo = models.BooleanField()
|
||||
email_priority = models.IntegerField(null=True, blank=True)
|
||||
def __str__(self):
|
||||
return self.body_name
|
||||
class Meta:
|
||||
db_table = 'from_bodies'
|
||||
verbose_name = "From body"
|
||||
verbose_name_plural = "From bodies"
|
||||
contact_link = admin_link('poc', label='Contact')
|
||||
from ietf.name.models import LiaisonStatementPurposeName
|
||||
from ietf.doc.models import Document
|
||||
from ietf.person.models import Email
|
||||
from ietf.group.models import Group
|
||||
|
||||
class LiaisonStatement(models.Model):
|
||||
title = models.CharField(blank=True, max_length=255)
|
||||
purpose = models.ForeignKey(LiaisonStatementPurposeName)
|
||||
body = models.TextField(blank=True)
|
||||
deadline = models.DateField(null=True, blank=True)
|
||||
|
||||
related_to = models.ForeignKey('LiaisonStatement', blank=True, null=True)
|
||||
|
||||
class OutgoingLiaisonApproval(models.Model):
|
||||
approved = models.BooleanField(default=True)
|
||||
approval_date = models.DateField(null=True, blank=True)
|
||||
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="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 recipient body")
|
||||
|
||||
reply_to = models.CharField(blank=True, max_length=255)
|
||||
|
||||
class LiaisonDetail(models.Model):
|
||||
detail_id = models.AutoField(primary_key=True)
|
||||
person = models.ForeignKey(PersonOrOrgInfo, null=True, db_column='person_or_org_tag')
|
||||
submitted_date = models.DateField(null=True, blank=True)
|
||||
last_modified_date = models.DateField(null=True, blank=True)
|
||||
from_id = models.IntegerField(null=True, blank=True)
|
||||
to_body = models.CharField(blank=True, null=True, max_length=255)
|
||||
title = models.CharField(blank=True, null=True, max_length=255)
|
||||
response_contact = models.CharField(blank=True, null=True, max_length=255)
|
||||
technical_contact = models.CharField(blank=True, null=True, max_length=255)
|
||||
purpose_text = models.TextField(blank=True, null=True, db_column='purpose')
|
||||
body = models.TextField(blank=True,null=True)
|
||||
deadline_date = models.DateField(null=True, blank=True)
|
||||
cc1 = models.TextField(blank=True, null=True)
|
||||
# unclear why cc2 is a CharField, but it's always
|
||||
# either NULL or blank.
|
||||
cc2 = models.CharField(blank=True, null=True, max_length=50)
|
||||
submitter_name = models.CharField(blank=True, null=True, max_length=255)
|
||||
submitter_email = models.CharField(blank=True, null=True, max_length=255)
|
||||
by_secretariat = models.IntegerField(null=True, blank=True)
|
||||
to_poc = models.CharField(blank=True, null=True, max_length=255)
|
||||
to_email = models.CharField(blank=True, null=True, max_length=255)
|
||||
purpose = models.ForeignKey(LiaisonPurpose,null=True)
|
||||
replyto = models.CharField(blank=True, null=True, max_length=255)
|
||||
from_raw_body = models.CharField(blank=True, null=True, max_length=255)
|
||||
from_raw_code = models.CharField(blank=True, null=True, max_length=255)
|
||||
to_raw_code = models.CharField(blank=True, null=True, max_length=255)
|
||||
approval = models.ForeignKey(OutgoingLiaisonApproval, blank=True, null=True)
|
||||
action_taken = models.BooleanField(default=False, db_column='taken_care')
|
||||
related_to = models.ForeignKey('LiaisonDetail', blank=True, null=True)
|
||||
def __str__(self):
|
||||
return self.title or "<no title>"
|
||||
def __unicode__(self):
|
||||
return self.title or "<no title>"
|
||||
def from_body(self):
|
||||
"""The from_raw_body stores the name of the entity
|
||||
sending the liaison.
|
||||
For legacy liaisons (the ones with empty from_raw_body)
|
||||
the legacy_from_body() is returned."""
|
||||
if not self.from_raw_body:
|
||||
return self.legacy_from_body()
|
||||
return self.from_raw_body
|
||||
def from_sdo(self):
|
||||
try:
|
||||
name = FromBodies.objects.get(pk=self.from_id).body_name
|
||||
sdo = SDOs.objects.get(sdo_name=name)
|
||||
return sdo
|
||||
except ObjectDoesNotExist:
|
||||
return None
|
||||
def legacy_from_body(self):
|
||||
"""The from_id field is a foreign key for either
|
||||
FromBodies or Acronyms, depending on whether it's
|
||||
the IETF or not. There is no flag field saying
|
||||
which, so we just try it. If the index values
|
||||
overlap, then this function will be ambiguous
|
||||
and will return the value from FromBodies. Current
|
||||
acronym IDs start at 925 so the day of reckoning
|
||||
is not nigh."""
|
||||
try:
|
||||
from_body = FromBodies.objects.get(pk=self.from_id)
|
||||
return from_body.body_name
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
try:
|
||||
acronym = Acronym.objects.get(pk=self.from_id)
|
||||
try:
|
||||
x = acronym.area
|
||||
kind = "AREA"
|
||||
except Area.DoesNotExist:
|
||||
kind = "WG"
|
||||
return "IETF %s %s" % (acronym.acronym.upper(), kind)
|
||||
except ObjectDoesNotExist:
|
||||
pass
|
||||
return "<unknown body %s>" % self.from_id
|
||||
def from_email(self):
|
||||
"""If there is an entry in from_bodies, it has
|
||||
the desired email priority. However, if it's from
|
||||
an IETF WG, there is no entry in from_bodies, so
|
||||
default to 1."""
|
||||
try:
|
||||
from_body = FromBodies.objects.get(pk=self.from_id)
|
||||
email_priority = from_body.email_priority
|
||||
except FromBodies.DoesNotExist:
|
||||
email_priority = 1
|
||||
return self.person.emailaddress_set.all().get(priority=email_priority)
|
||||
def get_absolute_url(self):
|
||||
return '/liaison/%d/' % self.detail_id
|
||||
class Meta:
|
||||
db_table = 'liaison_detail'
|
||||
response_contact = models.CharField(blank=True, max_length=255)
|
||||
technical_contact = models.CharField(blank=True, max_length=255)
|
||||
cc = models.TextField(blank=True)
|
||||
|
||||
def notify_pending_by_email(self, fake):
|
||||
from ietf.liaisons.utils import IETFHM
|
||||
submitted = models.DateTimeField(null=True, blank=True)
|
||||
modified = models.DateTimeField(null=True, blank=True)
|
||||
approved = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
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,
|
||||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=self.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.related_to.pk)) if self.related_to else None,
|
||||
})
|
||||
send_mail_text(context=None, to=to_email, frm=from_email, subject=subject, txt = body)
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# body = body)
|
||||
#if not fake:
|
||||
# mail.send()
|
||||
#return mail
|
||||
action_taken = models.BooleanField(default=False)
|
||||
|
||||
def send_by_email(self, fake=False):
|
||||
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,
|
||||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.related_to.pk)) if self.related_to else None,
|
||||
})
|
||||
send_mail_text(context=None,to=to_email,frm=from_email,subject=subject,txt=body,cc=cc,bcc=bcc)
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# cc = cc,
|
||||
# bcc = bcc,
|
||||
# body = body)
|
||||
#if not fake:
|
||||
# mail.send()
|
||||
#return mail
|
||||
attachments = models.ManyToManyField(Document, blank=True)
|
||||
|
||||
def is_pending(self):
|
||||
return bool(self.approval and not self.approval.approved)
|
||||
|
||||
|
||||
class SDOs(models.Model):
|
||||
sdo_id = models.AutoField(primary_key=True, verbose_name='ID')
|
||||
sdo_name = models.CharField(blank=True, max_length=255, verbose_name='SDO Name')
|
||||
def __str__(self):
|
||||
return self.sdo_name
|
||||
def liaisonmanager(self):
|
||||
try:
|
||||
return self.liaisonmanagers_set.all()[0]
|
||||
except:
|
||||
return None
|
||||
def sdo_contact(self):
|
||||
try:
|
||||
return self.sdoauthorizedindividual_set.all()[0]
|
||||
except:
|
||||
return None
|
||||
class Meta:
|
||||
verbose_name = 'SDO'
|
||||
verbose_name_plural = 'SDOs'
|
||||
db_table = 'sdos'
|
||||
ordering = ('sdo_name', )
|
||||
liaisonmanager_link = admin_link('liaisonmanager', label='Liaison')
|
||||
sdo_contact_link = admin_link('sdo_contact')
|
||||
|
||||
class LiaisonStatementManager(models.Model):
|
||||
person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag')
|
||||
sdo = models.ForeignKey(SDOs, verbose_name='SDO')
|
||||
def __unicode__(self):
|
||||
return '%s (%s)' % (self.person, self.sdo)
|
||||
class Meta:
|
||||
abstract = True
|
||||
# Helper functions, for use in the admin interface
|
||||
def login_name(self):
|
||||
login_name = None
|
||||
try:
|
||||
login_name = IESGLogin.objects.get(person=self.person).login_name
|
||||
if User.objects.filter(username=login_name).count():
|
||||
return login_name
|
||||
except IESGLogin.DoesNotExist:
|
||||
pass
|
||||
try:
|
||||
login_name = LegacyLiaisonUser.objects.get(person=self.person).login_name
|
||||
except LegacyLiaisonUser.DoesNotExist:
|
||||
pass
|
||||
return login_name
|
||||
def user(self):
|
||||
login_name = self.login_name()
|
||||
user = None
|
||||
if login_name:
|
||||
try:
|
||||
return User.objects.get(username=login_name), login_name
|
||||
except User.DoesNotExist:
|
||||
pass
|
||||
return None, login_name
|
||||
def user_name(self):
|
||||
user, login_name = self.user()
|
||||
if user:
|
||||
return u'<a href="/admin/auth/user/%s/">%s</a>' % (user.id, login_name)
|
||||
def name(self):
|
||||
from django.template.defaultfilters import slugify
|
||||
if self.from_group:
|
||||
frm = self.from_group.acronym or self.from_group.name
|
||||
else:
|
||||
if login_name:
|
||||
return u'Add login: <a href="/admin/auth/user/add/?username=%s"><span style="color: red">%s</span></a>' % (login_name, login_name)
|
||||
else:
|
||||
return u'Add liaison user: <a href="/admin/ietfauth/legacyliaisonuser/add/?person=%s&login_name=%s&user_level=3"><span style="color: red">%s</span></a>' % (self.person.pk, self.person.email()[1], self.person, )
|
||||
|
||||
user_name.allow_tags = True
|
||||
def groups(self):
|
||||
user, login_name = self.user()
|
||||
return ", ".join([ group.name for group in user.groups.all()])
|
||||
person_link = admin_link('person')
|
||||
sdo_link = admin_link('sdo', label='SDO')
|
||||
|
||||
class LiaisonManagers(LiaisonStatementManager):
|
||||
email_priority = models.IntegerField(null=True, blank=True)
|
||||
def email(self):
|
||||
try:
|
||||
return self.person.emailaddress_set.get(priority=self.email_priority)
|
||||
except ObjectDoesNotExist:
|
||||
return None
|
||||
class Meta:
|
||||
verbose_name = 'SDO Liaison Manager'
|
||||
verbose_name_plural = 'SDO Liaison Managers'
|
||||
db_table = 'liaison_managers'
|
||||
ordering = ('sdo__sdo_name', )
|
||||
frm = self.from_name
|
||||
if self.to_group:
|
||||
to = self.to_group.acronym or self.to_group.name
|
||||
else:
|
||||
to = self.to_name
|
||||
return slugify("liaison" + " " + self.submitted.strftime("%Y-%m-%d") + " " + frm[:50] + " " + to[:50] + " " + self.title[:115])
|
||||
|
||||
class SDOAuthorizedIndividual(LiaisonStatementManager):
|
||||
class Meta:
|
||||
verbose_name = 'SDO Authorized Individual'
|
||||
verbose_name_plural = 'SDO Authorized Individuals'
|
||||
|
||||
# This table is not used by any code right now.
|
||||
#class LiaisonsInterim(models.Model):
|
||||
# title = models.CharField(blank=True, max_length=255)
|
||||
# submitter_name = models.CharField(blank=True, max_length=255)
|
||||
# submitter_email = models.CharField(blank=True, max_length=255)
|
||||
# submitted_date = models.DateField(null=True, blank=True)
|
||||
# from_id = models.IntegerField(null=True, blank=True)
|
||||
# def __str__(self):
|
||||
# return self.title
|
||||
# class Meta:
|
||||
# db_table = 'liaisons_interim'
|
||||
|
||||
class Uploads(models.Model):
|
||||
file_id = models.AutoField(primary_key=True)
|
||||
file_title = models.CharField(blank=True, max_length=255)
|
||||
person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag')
|
||||
file_extension = models.CharField(blank=True, max_length=10)
|
||||
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'
|
||||
|
||||
# empty table
|
||||
#class SdoChairs(models.Model):
|
||||
# sdo = models.ForeignKey(SDOs)
|
||||
# person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag')
|
||||
# email_priority = models.IntegerField(null=True, blank=True)
|
||||
# class Meta:
|
||||
# db_table = 'sdo_chairs'
|
||||
|
||||
# changes done by convert-096.py:changed maxlength to max_length
|
||||
# removed core
|
||||
# removed edit_inline
|
||||
# removed num_in_admin
|
||||
# removed raw_id_admin
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES or hasattr(settings, "IMPORTING_FROM_OLD_SCHEMA"):
|
||||
from ietf.name.models import LiaisonStatementPurposeName
|
||||
from ietf.doc.models import Document
|
||||
from ietf.person.models import Email
|
||||
from ietf.group.models import Group
|
||||
|
||||
class LiaisonStatement(models.Model):
|
||||
title = models.CharField(blank=True, max_length=255)
|
||||
purpose = models.ForeignKey(LiaisonStatementPurposeName)
|
||||
body = models.TextField(blank=True)
|
||||
deadline = models.DateField(null=True, blank=True)
|
||||
|
||||
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="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="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 recipient body")
|
||||
|
||||
reply_to = models.CharField(blank=True, max_length=255)
|
||||
|
||||
response_contact = models.CharField(blank=True, max_length=255)
|
||||
technical_contact = models.CharField(blank=True, max_length=255)
|
||||
cc = models.TextField(blank=True)
|
||||
|
||||
submitted = models.DateTimeField(null=True, blank=True)
|
||||
modified = models.DateTimeField(null=True, blank=True)
|
||||
approved = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
action_taken = models.BooleanField(default=False)
|
||||
|
||||
attachments = models.ManyToManyField(Document, blank=True)
|
||||
|
||||
def name(self):
|
||||
from django.template.defaultfilters import slugify
|
||||
if self.from_group:
|
||||
frm = self.from_group.acronym or self.from_group.name
|
||||
else:
|
||||
frm = self.from_name
|
||||
if self.to_group:
|
||||
to = self.to_group.acronym or self.to_group.name
|
||||
else:
|
||||
to = self.to_name
|
||||
return slugify("liaison" + " " + self.submitted.strftime("%Y-%m-%d") + " " + frm[:50] + " " + to[:50] + " " + self.title[:115])
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title or "<no title>"
|
||||
|
||||
LiaisonDetailOld = LiaisonDetail
|
||||
def __unicode__(self):
|
||||
return self.title or u"<no title>"
|
||||
|
|
|
@ -1,188 +0,0 @@
|
|||
from ietf.utils.proxy import TranslatingManager
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
from ietf.doc.models import Document
|
||||
|
||||
class LiaisonDetailProxy(LiaisonStatement):
|
||||
objects = TranslatingManager(dict(submitted_date="submitted",
|
||||
deadline_date="deadline",
|
||||
to_body="to_name",
|
||||
from_raw_body="from_name"))
|
||||
|
||||
def from_object(self, base):
|
||||
for f in base._meta.fields:
|
||||
setattr(self, f.name, getattr(base, f.name))
|
||||
return self
|
||||
|
||||
#detail_id = models.AutoField(primary_key=True)
|
||||
@property
|
||||
def detail_id(self):
|
||||
return self.id
|
||||
#person = models.ForeignKey(PersonOrOrgInfo, null=True, db_column='person_or_org_tag')
|
||||
@property
|
||||
def person(self):
|
||||
return self.from_contact.person if self.from_contact else ""
|
||||
#submitted_date = models.DateField(null=True, blank=True)
|
||||
@property
|
||||
def submitted_date(self):
|
||||
return self.submitted.date() if self.submitted else None
|
||||
#last_modified_date = models.DateField(null=True, blank=True)
|
||||
@property
|
||||
def last_modified_date(self):
|
||||
return self.modified.date() if self.modified else None
|
||||
#from_id = models.IntegerField(null=True, blank=True)
|
||||
@property
|
||||
def from_id(self):
|
||||
return self.from_group_id
|
||||
#to_body = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def to_body(self):
|
||||
return self.to_name
|
||||
#title = models.CharField(blank=True, null=True, max_length=255) # same name
|
||||
#response_contact = models.CharField(blank=True, null=True, max_length=255) # same name
|
||||
#technical_contact = models.CharField(blank=True, null=True, max_length=255) # same name
|
||||
#purpose_text = models.TextField(blank=True, null=True, db_column='purpose')
|
||||
@property
|
||||
def purpose_text(self):
|
||||
return ""
|
||||
#body = models.TextField(blank=True,null=True) # same name
|
||||
#deadline_date = models.DateField(null=True, blank=True)
|
||||
@property
|
||||
def deadline_date(self):
|
||||
return self.deadline
|
||||
#cc1 = models.TextField(blank=True, null=True)
|
||||
@property
|
||||
def cc1(self):
|
||||
return self.cc
|
||||
#cc2 = models.CharField(blank=True, null=True, max_length=50) # unused
|
||||
@property
|
||||
def cc2(self):
|
||||
return ""
|
||||
#submitter_name = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def submitter_name(self):
|
||||
i = self.to_name.find('<')
|
||||
if i > 0:
|
||||
return self.to_name[:i - 1]
|
||||
else:
|
||||
return self.to_name
|
||||
#submitter_email = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def submitter_email(self):
|
||||
import re
|
||||
re_email = re.compile("<(.*)>")
|
||||
match = re_email.search(self.to_name)
|
||||
if match:
|
||||
return match.group(1)
|
||||
else:
|
||||
return ""
|
||||
#by_secretariat = models.IntegerField(null=True, blank=True)
|
||||
@property
|
||||
def by_secretariat(self):
|
||||
return not self.from_contact
|
||||
#to_poc = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def to_poc(self):
|
||||
return self.to_contact
|
||||
#to_email = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def to_email(self):
|
||||
return ""
|
||||
#purpose = models.ForeignKey(LiaisonPurpose,null=True)
|
||||
#replyto = models.CharField(blank=True, null=True, max_length=255)
|
||||
@property
|
||||
def replyto(self):
|
||||
return self.reply_to
|
||||
#from_raw_body = models.CharField(blank=True, null=True, max_length=255)
|
||||
@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.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.raw_codify(self.to_group)
|
||||
#approval = models.ForeignKey(OutgoingLiaisonApproval, blank=True, null=True)
|
||||
@property
|
||||
def approval(self):
|
||||
return bool(self.approved)
|
||||
#action_taken = models.BooleanField(default=False, db_column='taken_care') # same name
|
||||
#related_to = models.ForeignKey('LiaisonDetail', blank=True, null=True) # same name
|
||||
|
||||
@property
|
||||
def uploads_set(self):
|
||||
return UploadsProxy.objects.filter(liaisonstatement=self).order_by("name", "external_url")
|
||||
|
||||
@property
|
||||
def liaisondetail_set(self):
|
||||
return self.liaisonstatement_set
|
||||
|
||||
def __str__(self):
|
||||
return unicode(self)
|
||||
def __unicode__(self):
|
||||
return self.title or "<no title>"
|
||||
def from_body(self):
|
||||
return self.from_name
|
||||
def from_sdo(self):
|
||||
return self.from_group if self.from_group and self.from_group.type_id == "sdo" else None
|
||||
def from_email(self):
|
||||
return self.from_contact.address
|
||||
def get_absolute_url(self):
|
||||
return '/liaison/%d/' % self.detail_id
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
def send_by_email(self, fake=False):
|
||||
# grab this from module instead of stuffing in on the model
|
||||
from ietf.liaisons.mails import send_liaison_by_email
|
||||
# we don't have a request so just pass None for the time being
|
||||
return send_liaison_by_email(None, self, fake)
|
||||
|
||||
def notify_pending_by_email(self, fake=False):
|
||||
# grab this from module instead of stuffing in on the model
|
||||
from ietf.liaisons.mails import notify_pending_by_email
|
||||
# we don't have a request so just pass None for the time being
|
||||
return notify_pending_by_email(None, self, fake)
|
||||
|
||||
def is_pending(self):
|
||||
return not self.approved
|
||||
|
||||
class UploadsProxy(Document):
|
||||
#file_id = models.AutoField(primary_key=True)
|
||||
@property
|
||||
def file_id(self):
|
||||
if not self.external_url or 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):
|
||||
return self.title
|
||||
#person = models.ForeignKey(PersonOrOrgInfo, db_column='person_or_org_tag')
|
||||
#file_extension = models.CharField(blank=True, max_length=10)
|
||||
@property
|
||||
def file_extension(self):
|
||||
t = self.external_url.split(".")
|
||||
if len(t) > 1:
|
||||
return "." + t[1]
|
||||
else:
|
||||
return ""
|
||||
#detail = models.ForeignKey(LiaisonDetail)
|
||||
@property
|
||||
def detail(self):
|
||||
return self.liaisonstatement_set.all()[0]
|
||||
def filename(self):
|
||||
return self.external_url
|
||||
class Meta:
|
||||
proxy = True
|
|
@ -2,16 +2,17 @@
|
|||
#
|
||||
from django.contrib.sitemaps import Sitemap
|
||||
from django.conf import settings
|
||||
from ietf.liaisons.models import LiaisonDetail
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
|
||||
class LiaisonMap(Sitemap):
|
||||
changefreq = "never"
|
||||
|
||||
def items(self):
|
||||
return LiaisonDetail.objects.all()
|
||||
return LiaisonStatement.objects.all()
|
||||
|
||||
def location(self, obj):
|
||||
return "/liaison/%d/" % obj.detail_id
|
||||
return "/liaison/%s/" % obj.pk
|
||||
|
||||
def lastmod(self, obj):
|
||||
return obj.last_modified_date
|
||||
return obj.modified
|
||||
|
|
|
@ -11,6 +11,11 @@ from ietf.utils.test_data import make_test_data
|
|||
from ietf.utils.mail import outbox
|
||||
from ietf.utils import TestCase
|
||||
|
||||
from ietf.liaisons.models import LiaisonStatement, LiaisonStatementPurposeName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.liaisons.mails import send_sdo_reminder, possibly_send_deadline_reminder
|
||||
|
||||
class LiaisonsUrlTestCase(SimpleUrlTestCase):
|
||||
def testUrls(self):
|
||||
self.doTestUrls(__file__)
|
||||
|
@ -22,11 +27,6 @@ class LiaisonsUrlTestCase(SimpleUrlTestCase):
|
|||
else:
|
||||
return content
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.models import LiaisonStatement, LiaisonStatementPurposeName
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.group.models import Group, Role
|
||||
|
||||
def make_liaison_models():
|
||||
sdo = Group.objects.create(
|
||||
name="United League of Marsmen",
|
||||
|
@ -89,7 +89,58 @@ def make_liaison_models():
|
|||
action_taken=False,
|
||||
)
|
||||
return l
|
||||
|
||||
|
||||
class LiaisonTests(TestCase):
|
||||
def test_overview(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
r = self.client.get(urlreverse('liaison_list'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
def test_details(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
r = self.client.get(urlreverse("liaison_detail", kwargs={ 'object_id': liaison.pk }))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
def test_feeds(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
r = self.client.get('/feed/liaison/recent/')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
r = self.client.get('/feed/liaison/from/%s/' % liaison.from_group.acronym)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
r = self.client.get('/feed/liaison/to/%s/' % liaison.to_name)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
r = self.client.get('/feed/liaison/subject/marsmen/')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
def test_sitemap(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
r = self.client.get('/sitemap-liaison.xml')
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(urlreverse("liaison_detail", kwargs={ 'object_id': liaison.pk }) in r.content)
|
||||
|
||||
def test_help_pages(self):
|
||||
self.assertEqual(self.client.get('/liaison/help/').status_code, 200)
|
||||
self.assertEqual(self.client.get('/liaison/help/fields/').status_code, 200)
|
||||
self.assertEqual(self.client.get('/liaison/help/from_ietf/').status_code, 200)
|
||||
self.assertEqual(self.client.get('/liaison/help/to_ietf/').status_code, 200)
|
||||
|
||||
|
||||
class LiaisonManagementTests(TestCase):
|
||||
def setUp(self):
|
||||
|
@ -114,52 +165,63 @@ class LiaisonManagementTests(TestCase):
|
|||
url = urlreverse('liaison_detail', kwargs=dict(object_id=liaison.pk))
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=do_action_taken]')), 0)
|
||||
self.assertEqual(len(q('form input[name=do_action_taken]')), 0)
|
||||
|
||||
# log in and get
|
||||
self.client.login(remote_user="secretary")
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=do_action_taken]')), 1)
|
||||
self.assertEqual(len(q('form input[name=do_action_taken]')), 1)
|
||||
|
||||
# mark action taken
|
||||
r = self.client.post(url, dict(do_action_taken="1"))
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=do_action_taken]')), 0)
|
||||
self.assertEqual(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):
|
||||
def test_approval_process(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))
|
||||
|
||||
# check the overview page
|
||||
url = urlreverse('liaison_approval_list')
|
||||
# this liaison is for a WG so we need the AD for the area
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
|
||||
# check detail page
|
||||
url = urlreverse('liaison_approval_detail', kwargs=dict(object_id=liaison.pk))
|
||||
self.client.logout()
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertTrue(liaison.title in r.content)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=do_approval]')), 1)
|
||||
self.assertEqual(len(q('form input[name=do_approval]')), 1)
|
||||
|
||||
# approve
|
||||
mailbox_before = len(outbox)
|
||||
r = self.client.post(url, dict(do_approval="1"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
liaison = LiaisonStatement.objects.get(id=liaison.id)
|
||||
self.assertTrue(liaison.approved)
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("Liaison Statement" in outbox[-1]["Subject"])
|
||||
|
||||
def test_edit_liaison(self):
|
||||
|
@ -171,9 +233,9 @@ class LiaisonManagementTests(TestCase):
|
|||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form input[name=from_field]')), 1)
|
||||
self.assertEqual(len(q('form input[name=from_field]')), 1)
|
||||
|
||||
# edit
|
||||
attachments_before = liaison.attachments.count()
|
||||
|
@ -195,30 +257,30 @@ class LiaisonManagementTests(TestCase):
|
|||
attach_file_1=test_file,
|
||||
attach_title_1="attachment",
|
||||
))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEqual(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")
|
||||
self.assertEquals(new_liaison.to_name, "org")
|
||||
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, "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")
|
||||
self.assertEquals(new_liaison.submitted.date(), (liaison.submitted + datetime.timedelta(days=1)).date())
|
||||
self.assertEquals(new_liaison.body, "body")
|
||||
self.assertEqual(new_liaison.from_name, "from")
|
||||
self.assertEqual(new_liaison.reply_to, "replyto@example.com")
|
||||
self.assertEqual(new_liaison.to_name, "org")
|
||||
self.assertEqual(new_liaison.to_contact, "to_poc@example.com")
|
||||
self.assertEqual(new_liaison.response_contact, "responce_contact@example.com")
|
||||
self.assertEqual(new_liaison.technical_contact, "technical_contact@example.com")
|
||||
self.assertEqual(new_liaison.cc, "cc@example.com")
|
||||
self.assertEqual(new_liaison.purpose, LiaisonStatementPurposeName.objects.get(order=4))
|
||||
self.assertEqual(new_liaison.deadline, liaison.deadline + datetime.timedelta(days=1)),
|
||||
self.assertEqual(new_liaison.title, "title")
|
||||
self.assertEqual(new_liaison.submitted.date(), (liaison.submitted + datetime.timedelta(days=1)).date())
|
||||
self.assertEqual(new_liaison.body, "body")
|
||||
|
||||
self.assertEquals(new_liaison.attachments.count(), attachments_before + 1)
|
||||
self.assertEqual(new_liaison.attachments.count(), attachments_before + 1)
|
||||
attachment = new_liaison.attachments.order_by("-name")[0]
|
||||
self.assertEquals(attachment.title, "attachment")
|
||||
self.assertEqual(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())
|
||||
self.assertEqual(written_content, test_file.read())
|
||||
|
||||
def test_add_incoming_liaison(self):
|
||||
make_test_data()
|
||||
|
@ -229,9 +291,9 @@ class LiaisonManagementTests(TestCase):
|
|||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form textarea[name=body]')), 1)
|
||||
self.assertEqual(len(q('form textarea[name=body]')), 1)
|
||||
|
||||
# add new
|
||||
mailbox_before = len(outbox)
|
||||
|
@ -260,34 +322,34 @@ class LiaisonManagementTests(TestCase):
|
|||
attach_title_1="attachment",
|
||||
send="1",
|
||||
))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
l = LiaisonStatement.objects.all().order_by("-id")[0]
|
||||
self.assertEquals(l.from_group, from_group)
|
||||
self.assertEquals(l.from_contact.address, 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.assertEqual(l.from_group, from_group)
|
||||
self.assertEqual(l.from_contact.address, submitter.email_address())
|
||||
self.assertEqual(l.reply_to, "replyto@example.com")
|
||||
self.assertEqual(l.to_group, to_group)
|
||||
self.assertEqual(l.response_contact, "responce_contact@example.com")
|
||||
self.assertEqual(l.technical_contact, "technical_contact@example.com")
|
||||
self.assertEqual(l.cc, "cc@example.com")
|
||||
self.assertEqual(l.purpose, LiaisonStatementPurposeName.objects.get(order=4))
|
||||
self.assertEqual(l.deadline, today + datetime.timedelta(days=1)),
|
||||
self.assertEqual(l.related_to, liaison),
|
||||
self.assertEqual(l.title, "title")
|
||||
self.assertEqual(l.submitted.date(), today)
|
||||
self.assertEqual(l.body, "body")
|
||||
self.assertTrue(l.approved)
|
||||
|
||||
self.assertEquals(l.attachments.count(), 1)
|
||||
self.assertEqual(l.attachments.count(), 1)
|
||||
attachment = l.attachments.all()[0]
|
||||
self.assertEquals(attachment.title, "attachment")
|
||||
self.assertEqual(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())
|
||||
self.assertEqual(written_content, test_file.read())
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("Liaison Statement" in outbox[-1]["Subject"])
|
||||
|
||||
def test_add_outgoing_liaison(self):
|
||||
|
@ -299,9 +361,9 @@ class LiaisonManagementTests(TestCase):
|
|||
|
||||
# get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('form textarea[name=body]')), 1)
|
||||
self.assertEqual(len(q('form textarea[name=body]')), 1)
|
||||
|
||||
# add new
|
||||
mailbox_before = len(outbox)
|
||||
|
@ -333,35 +395,35 @@ class LiaisonManagementTests(TestCase):
|
|||
attach_title_1="attachment",
|
||||
send="1",
|
||||
))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
l = LiaisonStatement.objects.all().order_by("-id")[0]
|
||||
self.assertEquals(l.from_group, from_group)
|
||||
self.assertEquals(l.from_contact.address, 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.assertEqual(l.from_group, from_group)
|
||||
self.assertEqual(l.from_contact.address, submitter.email_address())
|
||||
self.assertEqual(l.reply_to, "replyto@example.com")
|
||||
self.assertEqual(l.to_group, to_group)
|
||||
self.assertEqual(l.to_contact, "to_poc@example.com")
|
||||
self.assertEqual(l.response_contact, "responce_contact@example.com")
|
||||
self.assertEqual(l.technical_contact, "technical_contact@example.com")
|
||||
self.assertEqual(l.cc, "cc@example.com")
|
||||
self.assertEqual(l.purpose, LiaisonStatementPurposeName.objects.get(order=4))
|
||||
self.assertEqual(l.deadline, today + datetime.timedelta(days=1)),
|
||||
self.assertEqual(l.related_to, liaison),
|
||||
self.assertEqual(l.title, "title")
|
||||
self.assertEqual(l.submitted.date(), today)
|
||||
self.assertEqual(l.body, "body")
|
||||
self.assertTrue(not l.approved)
|
||||
|
||||
self.assertEquals(l.attachments.count(), 1)
|
||||
self.assertEqual(l.attachments.count(), 1)
|
||||
attachment = l.attachments.all()[0]
|
||||
self.assertEquals(attachment.title, "attachment")
|
||||
self.assertEqual(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())
|
||||
self.assertEqual(written_content, test_file.read())
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("Liaison Statement" in outbox[-1]["Subject"])
|
||||
|
||||
# try adding statement to non-predefined organization
|
||||
|
@ -383,46 +445,34 @@ class LiaisonManagementTests(TestCase):
|
|||
submitted_date=today.strftime("%Y-%m-%d"),
|
||||
body="body",
|
||||
))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
self.assertEqual(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")
|
||||
self.assertEqual(l.to_group, None)
|
||||
self.assertEqual(l.to_name, "Mars Institute")
|
||||
|
||||
def test_send_sdo_reminder(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
from ietf.liaisons.mails import send_sdo_reminder
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
send_sdo_reminder(Group.objects.filter(type="sdo")[0])
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("authorized individuals" in outbox[-1]["Subject"])
|
||||
|
||||
def test_send_liaison_deadline_reminder(self):
|
||||
make_test_data()
|
||||
liaison = make_liaison_models()
|
||||
|
||||
from ietf.liaisons.mails import possibly_send_deadline_reminder
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
|
||||
l = LiaisonDetail.objects.all()[0]
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
possibly_send_deadline_reminder(l)
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
possibly_send_deadline_reminder(liaison)
|
||||
self.assertEqual(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("deadline" in outbox[-1]["Subject"])
|
||||
|
||||
# try pushing the deadline
|
||||
l.deadline = l.deadline + datetime.timedelta(days=30)
|
||||
l.save()
|
||||
liaison.deadline = liaison.deadline + datetime.timedelta(days=30)
|
||||
liaison.save()
|
||||
|
||||
mailbox_before = len(outbox)
|
||||
possibly_send_deadline_reminder(l)
|
||||
self.assertEquals(len(outbox), mailbox_before)
|
||||
|
||||
|
||||
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
# the above tests only work with the new schema
|
||||
del LiaisonManagementTestCase
|
||||
possibly_send_deadline_reminder(liaison)
|
||||
self.assertEqual(len(outbox), mailbox_before)
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
200 /liaison/
|
||||
200 /liaison/321/
|
||||
200 /liaison/553/ # submitted by email
|
||||
200 /liaison/337/ # test case for ticket #182
|
||||
200 /liaison/458/ # non-ASCII title
|
||||
200 /liaison/471/ # non-ASCII body and submitter name
|
||||
|
||||
301 /liaison/managers/
|
||||
|
||||
200 /liaison/help/to_ietf/
|
||||
200 /liaison/help/from_ietf/
|
||||
200 /liaison/help/fields/
|
||||
200 /liaison/help/
|
||||
|
||||
404 /feed/liaison/
|
||||
200 /feed/liaison/recent/
|
||||
200 /feed/liaison/from/ccamp/
|
||||
#200 /feed/liaison/from/MFA%20Forum/
|
||||
200 /feed/liaison/from/MFA_Forum/
|
||||
200 /feed/liaison/to/ccamp/
|
||||
200 /feed/liaison/subject/H.248/
|
||||
200 /feed/liaison/subject/2173/ # non-ASCII title
|
||||
|
||||
404 /feed/liaison/recent/foobar/
|
||||
404 /feed/liaison/from/
|
||||
404 /feed/liaison/from/nosuchorganization/
|
||||
404 /feed/liaison/from/foo/bar/
|
||||
404 /feed/liaison/to/
|
||||
404 /feed/liaison/to/foo/bar/
|
||||
404 /feed/liaison/subject/
|
||||
404 /feed/liaison/subject/foo/bar/
|
||||
|
||||
200 /sitemap-liaison.xml
|
|
@ -2,17 +2,8 @@
|
|||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
from django.db.models import Q
|
||||
from ietf.liaisons.models import LiaisonDetail
|
||||
|
||||
info_dict = {
|
||||
'queryset': LiaisonDetail.objects.filter(Q(approval__isnull=True)|Q(approval__approved=True)).order_by("-submitted_date"),
|
||||
}
|
||||
|
||||
# there's an opportunity for date-based filtering.
|
||||
urlpatterns = patterns('django.views.generic.list_detail',
|
||||
)
|
||||
|
||||
urlpatterns += patterns('django.views.generic.simple',
|
||||
urlpatterns = patterns('django.views.generic.simple',
|
||||
(r'^help/$', 'direct_to_template', {'template': 'liaisons/help.html'}),
|
||||
(r'^help/fields/$', 'direct_to_template', {'template': 'liaisons/field_help.html'}),
|
||||
(r'^help/from_ietf/$', 'direct_to_template', {'template': 'liaisons/guide_from_ietf.html'}),
|
||||
|
|
|
@ -1,10 +1,43 @@
|
|||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
|
||||
from ietf.idtracker.models import Area, IETFWG
|
||||
from ietf.liaisons.models import SDOs, LiaisonManagers
|
||||
from ietf.liaisons.accounts import (is_ietfchair, is_iabchair, is_iab_executive_director, is_irtfchair,
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.person.models import Person
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
from ietf.ietfauth.utils import has_role, passes_test_decorator
|
||||
from ietf.utils.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)
|
||||
is_secretariat, can_add_liaison, get_person_for_user)
|
||||
|
||||
can_submit_liaison_required = passes_test_decorator(
|
||||
lambda u, *args, **kwargs: can_add_liaison(u),
|
||||
"Restricted to participants who are authorized to submit liaison statements on behalf of the various IETF entities")
|
||||
|
||||
def approvable_liaison_statements(user):
|
||||
liaisons = LiaisonStatement.objects.filter(approved=None)
|
||||
if has_role(user, "Secretariat"):
|
||||
return liaisons
|
||||
|
||||
# this is a bit complicated because IETFHM encodes the
|
||||
# groups, it should just give us a list of ids or acronyms
|
||||
group_codes = IETFHM.get_all_can_approve_codes(get_person_for_user(user))
|
||||
group_acronyms = []
|
||||
group_ids = []
|
||||
for x in group_codes:
|
||||
if "_" in x:
|
||||
group_ids.append(x.split("_")[1])
|
||||
else:
|
||||
group_acronyms.append(x)
|
||||
|
||||
return liaisons.filter(Q(from_group__acronym__in=group_acronyms) | Q(from_group__pk__in=group_ids))
|
||||
|
||||
|
||||
# the following is a biggish object hierarchy abstracting the entity
|
||||
# names and auth rules for posting liaison statements in a sort of
|
||||
# semi-declarational (and perhaps overengineered given the revamped
|
||||
# schema) way - unfortunately, it's never been strong enough to do so
|
||||
# fine-grained enough so the form code also has some rules
|
||||
|
||||
IETFCHAIR = {'name': u'The IETF Chair', 'address': u'chair@ietf.org'}
|
||||
IESG = {'name': u'The IESG', 'address': u'iesg@ietf.org'}
|
||||
|
@ -12,10 +45,7 @@ IAB = {'name': u'The IAB', 'address': u'iab@iab.org'}
|
|||
IABCHAIR = {'name': u'The IAB Chair', 'address': u'iab-chair@iab.org'}
|
||||
IABEXECUTIVEDIRECTOR = {'name': u'The IAB Executive Director', 'address': u'execd@iab.org'}
|
||||
IRTFCHAIR = {'name': u'The IRTF Chair', 'address': u'irtf-chair@irtf.org'}
|
||||
|
||||
|
||||
def get_all_sdo_managers():
|
||||
return [i.person for i in LiaisonManagers.objects.all().distinct()]
|
||||
IESGANDIAB = {'name': u'The IESG and IAB', 'address': u'iesg-iab@ietf.org'}
|
||||
|
||||
|
||||
class FakePerson(object):
|
||||
|
@ -27,7 +57,12 @@ class FakePerson(object):
|
|||
def email(self):
|
||||
return (self.name, self.address)
|
||||
|
||||
def all_sdo_managers():
|
||||
return [proxy_personify_role(r) for r in Role.objects.filter(group__type="sdo", name="liaiman").select_related("person").distinct()]
|
||||
|
||||
def role_persons_with_fixed_email(group, role_name):
|
||||
return [proxy_personify_role(r) for r in Role.objects.filter(group=group, name=role_name).select_related("person").distinct()]
|
||||
|
||||
class Entity(object):
|
||||
|
||||
poc = []
|
||||
|
@ -84,34 +119,11 @@ 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
|
||||
|
||||
|
||||
class IRTFEntity(Entity):
|
||||
|
||||
poc = FakePerson(**IRTFCHAIR)
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = []
|
||||
if not is_irtfchair(person):
|
||||
result.append(self.poc)
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if is_irtfchair(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [self.poc]
|
||||
|
||||
def full_user_list(self):
|
||||
result.append(get_irtf_chair())
|
||||
return result
|
||||
|
||||
|
||||
class IABEntity(Entity):
|
||||
chair = FakePerson(**IABCHAIR)
|
||||
director = FakePerson(**IABEXECUTIVEDIRECTOR)
|
||||
|
@ -136,27 +148,75 @@ 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
|
||||
|
||||
|
||||
class IRTFEntity(Entity):
|
||||
chair = FakePerson(**IRTFCHAIR)
|
||||
poc = [chair,]
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = []
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if is_irtfchair(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [self.chair]
|
||||
|
||||
def full_user_list(self):
|
||||
result = [get_irtf_chair()]
|
||||
return result
|
||||
|
||||
|
||||
class IAB_IESG_Entity(Entity):
|
||||
|
||||
poc = [IABEntity.chair, IABEntity.director, FakePerson(**IETFCHAIR), FakePerson(**IESGANDIAB), ]
|
||||
cc = [FakePerson(**IAB), FakePerson(**IESG), FakePerson(**IESGANDIAB)]
|
||||
|
||||
def __init__(self, name, obj=None):
|
||||
self.name = name
|
||||
self.obj = obj
|
||||
self.iab = IABEntity(name, obj)
|
||||
self.iesg = IETFEntity(name, obj)
|
||||
|
||||
def get_from_cc(self, person):
|
||||
return list(set(self.iab.get_from_cc(person) + self.iesg.get_from_cc(person)))
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if not self.iab.needs_approval(person):
|
||||
return False
|
||||
if not self.iesg.needs_approval(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return list(set(self.iab.can_approve() + self.iesg.can_approve()))
|
||||
|
||||
def full_user_list(self):
|
||||
return [get_ietf_chair(), get_iab_chair(), get_iab_executive_director()]
|
||||
|
||||
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)]
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = [i.person for i in self.obj.areadirector_set.all() if i.person!=person]
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj, "ad") if p != person]
|
||||
result.append(FakePerson(**IETFCHAIR))
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
# Check if person is an area director
|
||||
if self.obj.areadirector_set.filter(person=person):
|
||||
if self.obj.role_set.filter(person=person, name="ad"):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
@ -164,7 +224,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
|
||||
|
||||
|
@ -172,34 +232,37 @@ class AreaEntity(Entity):
|
|||
class WGEntity(Entity):
|
||||
|
||||
def get_poc(self):
|
||||
return [i.person for i in self.obj.wgchair_set.all()]
|
||||
return role_persons_with_fixed_email(self.obj, "chair")
|
||||
|
||||
def get_cc(self, person=None):
|
||||
result = [i.person for i in self.obj.area_directors()]
|
||||
if self.obj.email_address:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.group_acronym.name,
|
||||
address = self.obj.email_address))
|
||||
if self.obj.parent:
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj.parent, "ad") if p != person]
|
||||
else:
|
||||
result = []
|
||||
if self.obj.list_subscribe:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.name,
|
||||
address = self.obj.list_subscribe))
|
||||
return result
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = [i.person for i in self.obj.wgchair_set.all() if i.person!=person]
|
||||
result += [i.person for i in self.obj.area_directors()]
|
||||
if self.obj.email_address:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.group_acronym.name,
|
||||
address = self.obj.email_address))
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj, "chair") if p != person]
|
||||
result += role_persons_with_fixed_email(self.obj.parent, "ad") if self.obj.parent else []
|
||||
if self.obj.list_subscribe:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.name,
|
||||
address = self.obj.list_subscribe))
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
# Check if person is director of this wg area
|
||||
if self.obj.area.area.areadirector_set.filter(person=person):
|
||||
if self.obj.parent and self.obj.parent.role_set.filter(person=person, name="ad"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [i.person for i in self.obj.area.area.areadirector_set.all()]
|
||||
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
|
||||
|
||||
|
@ -210,25 +273,19 @@ class SDOEntity(Entity):
|
|||
return []
|
||||
|
||||
def get_cc(self, person=None):
|
||||
manager = self.obj.liaisonmanager()
|
||||
if manager:
|
||||
return [manager.person]
|
||||
return []
|
||||
return role_persons_with_fixed_email(self.obj, "liaiman")
|
||||
|
||||
def get_from_cc(self, person=None):
|
||||
manager = self.obj.liaisonmanager()
|
||||
if manager and manager.person!=person:
|
||||
return [manager.person]
|
||||
return []
|
||||
return [p for p in role_persons_with_fixed_email(self.obj, "liaiman") if p != person]
|
||||
|
||||
def post_only(self, person, user):
|
||||
if is_secretariat(user) or person.sdoauthorizedindividual_set.filter(sdo=self.obj):
|
||||
if is_secretariat(user) or self.obj.role_set.filter(person=person, name="auth"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def full_user_list(self):
|
||||
result = [i.person for i in self.obj.liaisonmanagers_set.all().distinct()]
|
||||
result += [i.person for i in self.obj.sdoauthorizedindividual_set.all().distinct()]
|
||||
result = role_persons_with_fixed_email(self.obj, "liaiman")
|
||||
result += role_persons_with_fixed_email(self.obj, "auth")
|
||||
return result
|
||||
|
||||
|
||||
|
@ -314,10 +371,35 @@ class IRTFEntityManager(EntityManager):
|
|||
return []
|
||||
|
||||
|
||||
class IAB_IESG_EntityManager(EntityManager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IAB_IESG_EntityManager, self).__init__(*args, **kwargs)
|
||||
self.entity = IAB_IESG_Entity(name=self.name)
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return self.entity
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person) or
|
||||
is_ietfchair(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person) or
|
||||
is_ietfchair(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
|
||||
class AreaEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(AreaEntityManager, self).__init__(pk, name, queryset)
|
||||
from ietf.group.proxy import Area
|
||||
if self.queryset == None:
|
||||
self.queryset = Area.active_areas()
|
||||
|
||||
|
@ -336,11 +418,11 @@ class AreaEntityManager(EntityManager):
|
|||
return AreaEntity(name=obj.area_acronym.name, obj=obj)
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
query_filter = {'areadirector__in': person.areadirector_set.all()}
|
||||
query_filter = dict(role__person=person, role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
def can_approve_list(self, person):
|
||||
query_filter = {'areadirector__in': person.areadirector_set.all()}
|
||||
query_filter = dict(role__person=person, role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
|
||||
|
@ -349,6 +431,7 @@ class WGEntityManager(EntityManager):
|
|||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(WGEntityManager, self).__init__(pk, name, queryset)
|
||||
if self.queryset == None:
|
||||
from ietf.group.proxy import IETFWG, Area
|
||||
self.queryset = IETFWG.objects.filter(group_type=1, status=IETFWG.ACTIVE, areagroup__area__status=Area.ACTIVE)
|
||||
|
||||
def get_managed_list(self, query_filter=None):
|
||||
|
@ -366,13 +449,12 @@ 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__person=person, role__name__in=("chair", "secretary")).values_list('pk', flat=True)
|
||||
query_filter = {'pk__in': wgs}
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
def can_approve_list(self, person):
|
||||
query_filter = {'areagroup__area__areadirector__in': person.areadirector_set.all()}
|
||||
query_filter = dict(parent__role__person=person, parent__role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
|
||||
|
@ -381,10 +463,10 @@ class SDOEntityManager(EntityManager):
|
|||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(SDOEntityManager, self).__init__(pk, name, queryset)
|
||||
if self.queryset == None:
|
||||
self.queryset = SDOs.objects.all()
|
||||
self.queryset = Group.objects.filter(type="sdo")
|
||||
|
||||
def get_managed_list(self):
|
||||
return [(u'%s_%s' % (self.pk, i.pk), i.sdo_name) for i in self.queryset.order_by('sdo_name')]
|
||||
return [(u'%s_%s' % (self.pk, i.pk), i.name) for i in self.queryset.order_by('name')]
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
if not pk:
|
||||
|
@ -393,7 +475,7 @@ class SDOEntityManager(EntityManager):
|
|||
obj = self.queryset.get(pk=pk)
|
||||
except self.queryset.model.DoesNotExist:
|
||||
return None
|
||||
return SDOEntity(name=obj.sdo_name, obj=obj)
|
||||
return SDOEntity(name=obj.name, obj=obj)
|
||||
|
||||
|
||||
class IETFHierarchyManager(object):
|
||||
|
@ -402,7 +484,7 @@ class IETFHierarchyManager(object):
|
|||
self.managers = {'ietf': IETFEntityManager(pk='ietf', name=u'The IETF'),
|
||||
'iesg': IETFEntityManager(pk='iesg', name=u'The IESG'),
|
||||
'iab': IABEntityManager(pk='iab', name=u'The IAB'),
|
||||
'irtf': IRTFEntityManager(pk='irtf', name=u'The IAB'),
|
||||
'iabiesg': IAB_IESG_EntityManager(pk='iabiesg', name=u'The IESG and the IAB'),
|
||||
'area': AreaEntityManager(pk='area', name=u'IETF Areas'),
|
||||
'wg': WGEntityManager(pk='wg', name=u'IETF Working Groups'),
|
||||
'sdo': SDOEntityManager(pk='sdo', name=u'Standards Development Organizations'),
|
||||
|
@ -430,7 +512,7 @@ class IETFHierarchyManager(object):
|
|||
def get_all_incoming_entities(self):
|
||||
entities = []
|
||||
results = []
|
||||
for key in ['ietf', 'iesg', 'iab']:
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
results += self.managers[key].get_managed_list()
|
||||
entities.append(('Main IETF Entities', results))
|
||||
entities.append(('IETF Areas', self.managers['area'].get_managed_list()))
|
||||
|
@ -445,7 +527,7 @@ class IETFHierarchyManager(object):
|
|||
def get_entities_for_person(self, person):
|
||||
entities = []
|
||||
results = []
|
||||
for key in ['ietf', 'iesg', 'iab']:
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
results += self.managers[key].can_send_on_behalf(person)
|
||||
if results:
|
||||
entities.append(('Main IETF Entities', results))
|
||||
|
@ -459,7 +541,7 @@ class IETFHierarchyManager(object):
|
|||
|
||||
def get_all_can_approve_codes(self, person):
|
||||
entities = []
|
||||
for key in ['ietf', 'iesg', 'iab']:
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
entities += self.managers[key].can_approve_list(person)
|
||||
entities += self.managers['area'].can_approve_list(person)
|
||||
entities += self.managers['wg'].can_approve_list(person)
|
||||
|
@ -467,6 +549,3 @@ class IETFHierarchyManager(object):
|
|||
|
||||
|
||||
IETFHM = IETFHierarchyManager()
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from utilsREDESIGN import *
|
||||
|
|
|
@ -1,524 +0,0 @@
|
|||
from ietf.group.models import Group, Role
|
||||
from ietf.person.models import Person
|
||||
from ietf.utils.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)
|
||||
|
||||
IETFCHAIR = {'name': u'The IETF Chair', 'address': u'chair@ietf.org'}
|
||||
IESG = {'name': u'The IESG', 'address': u'iesg@ietf.org'}
|
||||
IAB = {'name': u'The IAB', 'address': u'iab@iab.org'}
|
||||
IABCHAIR = {'name': u'The IAB Chair', 'address': u'iab-chair@iab.org'}
|
||||
IABEXECUTIVEDIRECTOR = {'name': u'The IAB Executive Director', 'address': u'execd@iab.org'}
|
||||
IRTFCHAIR = {'name': u'The IRTF Chair', 'address': u'irtf-chair@irtf.org'}
|
||||
IESGANDIAB = {'name': u'The IESG and IAB', 'address': u'iesg-iab@ietf.org'}
|
||||
|
||||
|
||||
class FakePerson(object):
|
||||
|
||||
def __init__(self, name, address):
|
||||
self.name = name
|
||||
self.address = address
|
||||
|
||||
def email(self):
|
||||
return (self.name, self.address)
|
||||
|
||||
# the following is a biggish object hierarchy abstracting the entity
|
||||
# names and auth rules for posting liaison statements in a sort of
|
||||
# semi-declarational (and perhaps overengineered given the revamped
|
||||
# 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("person").distinct()]
|
||||
|
||||
def role_persons_with_fixed_email(group, role_name):
|
||||
return [proxy_personify_role(r) for r in Role.objects.filter(group=group, name=role_name).select_related("person").distinct()]
|
||||
|
||||
class Entity(object):
|
||||
|
||||
poc = []
|
||||
cc = []
|
||||
|
||||
def __init__(self, name, obj=None):
|
||||
self.name = name
|
||||
self.obj = obj
|
||||
|
||||
def get_poc(self):
|
||||
if not isinstance(self.poc, list):
|
||||
return [self.poc]
|
||||
return self.poc
|
||||
|
||||
def get_cc(self, person=None):
|
||||
if not isinstance(self.cc, list):
|
||||
return [self.cc]
|
||||
return self.cc
|
||||
|
||||
def get_from_cc(self, person=None):
|
||||
return []
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
return False
|
||||
|
||||
def can_approve(self):
|
||||
return []
|
||||
|
||||
def post_only(self, person, user):
|
||||
return False
|
||||
|
||||
def full_user_list(self):
|
||||
return False
|
||||
|
||||
|
||||
class IETFEntity(Entity):
|
||||
|
||||
poc = FakePerson(**IETFCHAIR)
|
||||
cc = FakePerson(**IESG)
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = []
|
||||
if not is_ietfchair(person):
|
||||
result.append(self.poc)
|
||||
result.append(self.cc)
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if is_ietfchair(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [self.poc]
|
||||
|
||||
def full_user_list(self):
|
||||
result = all_sdo_managers()
|
||||
result.append(get_ietf_chair())
|
||||
return result
|
||||
|
||||
|
||||
class IABEntity(Entity):
|
||||
chair = FakePerson(**IABCHAIR)
|
||||
director = FakePerson(**IABEXECUTIVEDIRECTOR)
|
||||
poc = [chair, director]
|
||||
cc = FakePerson(**IAB)
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = []
|
||||
if not is_iabchair(person):
|
||||
result.append(self.chair)
|
||||
result.append(self.cc)
|
||||
if not is_iab_executive_director(person):
|
||||
result.append(self.director)
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if is_iabchair(person) or is_iab_executive_director(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [self.chair]
|
||||
|
||||
def full_user_list(self):
|
||||
result = all_sdo_managers()
|
||||
result += [get_iab_chair(), get_iab_executive_director()]
|
||||
return result
|
||||
|
||||
|
||||
class IRTFEntity(Entity):
|
||||
chair = FakePerson(**IRTFCHAIR)
|
||||
poc = [chair,]
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = []
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if is_irtfchair(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return [self.chair]
|
||||
|
||||
def full_user_list(self):
|
||||
result = [get_irtf_chair()]
|
||||
return result
|
||||
|
||||
|
||||
class IAB_IESG_Entity(Entity):
|
||||
|
||||
poc = [IABEntity.chair, IABEntity.director, FakePerson(**IETFCHAIR), FakePerson(**IESGANDIAB), ]
|
||||
cc = [FakePerson(**IAB), FakePerson(**IESG), FakePerson(**IESGANDIAB)]
|
||||
|
||||
def __init__(self, name, obj=None):
|
||||
self.name = name
|
||||
self.obj = obj
|
||||
self.iab = IABEntity(name, obj)
|
||||
self.iesg = IETFEntity(name, obj)
|
||||
|
||||
def get_from_cc(self, person):
|
||||
return list(set(self.iab.get_from_cc(person) + self.iesg.get_from_cc(person)))
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
if not self.iab.needs_approval(person):
|
||||
return False
|
||||
if not self.iesg.needs_approval(person):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return list(set(self.iab.can_approve() + self.iesg.can_approve()))
|
||||
|
||||
def full_user_list(self):
|
||||
return [get_ietf_chair(), get_iab_chair(), get_iab_executive_director()]
|
||||
|
||||
class AreaEntity(Entity):
|
||||
|
||||
def get_poc(self):
|
||||
return role_persons_with_fixed_email(self.obj, "ad")
|
||||
|
||||
def get_cc(self, person=None):
|
||||
return [FakePerson(**IETFCHAIR)]
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj, "ad") if p != person]
|
||||
result.append(FakePerson(**IETFCHAIR))
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
# Check if person is an area director
|
||||
if self.obj.role_set.filter(person=person, name="ad"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return self.get_poc()
|
||||
|
||||
def full_user_list(self):
|
||||
result = all_sdo_managers()
|
||||
result += self.get_poc()
|
||||
return result
|
||||
|
||||
|
||||
class WGEntity(Entity):
|
||||
|
||||
def get_poc(self):
|
||||
return role_persons_with_fixed_email(self.obj, "chair")
|
||||
|
||||
def get_cc(self, person=None):
|
||||
if self.obj.parent:
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj.parent, "ad") if p != person]
|
||||
else:
|
||||
result = []
|
||||
if self.obj.list_subscribe:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.name,
|
||||
address = self.obj.list_subscribe))
|
||||
return result
|
||||
|
||||
def get_from_cc(self, person):
|
||||
result = [p for p in role_persons_with_fixed_email(self.obj, "chair") if p != person]
|
||||
result += role_persons_with_fixed_email(self.obj.parent, "ad") if self.obj.parent else []
|
||||
if self.obj.list_subscribe:
|
||||
result.append(FakePerson(name ='%s Discussion List' % self.obj.name,
|
||||
address = self.obj.list_subscribe))
|
||||
return result
|
||||
|
||||
def needs_approval(self, person=None):
|
||||
# Check if person is director of this wg area
|
||||
if self.obj.parent and self.obj.parent.role_set.filter(person=person, name="ad"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def can_approve(self):
|
||||
return role_persons_with_fixed_email(self.obj.parent, "ad") if self.obj.parent else []
|
||||
|
||||
def full_user_list(self):
|
||||
result = all_sdo_managers()
|
||||
result += self.get_poc()
|
||||
return result
|
||||
|
||||
|
||||
class SDOEntity(Entity):
|
||||
|
||||
def get_poc(self):
|
||||
return []
|
||||
|
||||
def get_cc(self, person=None):
|
||||
return role_persons_with_fixed_email(self.obj, "liaiman")
|
||||
|
||||
def get_from_cc(self, person=None):
|
||||
return [p for p in role_persons_with_fixed_email(self.obj, "liaiman") if p != person]
|
||||
|
||||
def post_only(self, person, user):
|
||||
if is_secretariat(user) or self.obj.role_set.filter(person=person, name="auth"):
|
||||
return False
|
||||
return True
|
||||
|
||||
def full_user_list(self):
|
||||
result = role_persons_with_fixed_email(self.obj, "liaiman")
|
||||
result += role_persons_with_fixed_email(self.obj, "auth")
|
||||
return result
|
||||
|
||||
|
||||
class EntityManager(object):
|
||||
|
||||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
self.pk = pk
|
||||
self.name = name
|
||||
self.queryset = queryset
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return Entity(name=self.name)
|
||||
|
||||
def get_managed_list(self):
|
||||
return [(self.pk, self.name)]
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
return []
|
||||
|
||||
|
||||
class IETFEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IETFEntityManager, self).__init__(*args, **kwargs)
|
||||
self.entity = IETFEntity(name=self.name)
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return self.entity
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
if is_ietfchair(person):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
if is_ietfchair(person):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
|
||||
class IABEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IABEntityManager, self).__init__(*args, **kwargs)
|
||||
self.entity = IABEntity(name=self.name)
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return self.entity
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
|
||||
class IRTFEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IRTFEntityManager, self).__init__(*args, **kwargs)
|
||||
self.entity = IRTFEntity(name=self.name)
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return self.entity
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
if is_irtfchair(person):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
if is_irtfchair(person):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
|
||||
class IAB_IESG_EntityManager(EntityManager):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(IAB_IESG_EntityManager, self).__init__(*args, **kwargs)
|
||||
self.entity = IAB_IESG_Entity(name=self.name)
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
return self.entity
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person) or
|
||||
is_ietfchair(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
def can_approve_list(self, person):
|
||||
if (is_iabchair(person) or
|
||||
is_iab_executive_director(person) or
|
||||
is_ietfchair(person)):
|
||||
return self.get_managed_list()
|
||||
return []
|
||||
|
||||
|
||||
class AreaEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(AreaEntityManager, self).__init__(pk, name, queryset)
|
||||
from ietf.group.proxy import Area
|
||||
if self.queryset == None:
|
||||
self.queryset = Area.active_areas()
|
||||
|
||||
def get_managed_list(self, query_filter=None):
|
||||
if not query_filter:
|
||||
query_filter = {}
|
||||
return [(u'%s_%s' % (self.pk, i.pk), i.area_acronym.name) for i in self.queryset.filter(**query_filter).order_by('area_acronym__name')]
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
if not pk:
|
||||
return None
|
||||
try:
|
||||
obj = self.queryset.get(pk=pk)
|
||||
except self.queryset.model.DoesNotExist:
|
||||
return None
|
||||
return AreaEntity(name=obj.area_acronym.name, obj=obj)
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
query_filter = dict(role__person=person, role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
def can_approve_list(self, person):
|
||||
query_filter = dict(role__person=person, role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
|
||||
class WGEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(WGEntityManager, self).__init__(pk, name, queryset)
|
||||
if self.queryset == None:
|
||||
from ietf.group.proxy import IETFWG, Area
|
||||
self.queryset = IETFWG.objects.filter(group_type=1, status=IETFWG.ACTIVE, areagroup__area__status=Area.ACTIVE)
|
||||
|
||||
def get_managed_list(self, query_filter=None):
|
||||
if not query_filter:
|
||||
query_filter = {}
|
||||
return [(u'%s_%s' % (self.pk, i.pk), '%s - %s' % (i.group_acronym.acronym, i.group_acronym.name)) for i in self.queryset.filter(**query_filter).order_by('group_acronym__acronym')]
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
if not pk:
|
||||
return None
|
||||
try:
|
||||
obj = self.queryset.get(pk=pk)
|
||||
except self.queryset.model.DoesNotExist:
|
||||
return None
|
||||
return WGEntity(name=obj.group_acronym.name, obj=obj)
|
||||
|
||||
def can_send_on_behalf(self, person):
|
||||
wgs = Group.objects.filter(role__person=person, role__name__in=("chair", "secretary")).values_list('pk', flat=True)
|
||||
query_filter = {'pk__in': wgs}
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
def can_approve_list(self, person):
|
||||
query_filter = dict(parent__role__person=person, parent__role__name="ad")
|
||||
return self.get_managed_list(query_filter)
|
||||
|
||||
|
||||
class SDOEntityManager(EntityManager):
|
||||
|
||||
def __init__(self, pk=None, name=None, queryset=None):
|
||||
super(SDOEntityManager, self).__init__(pk, name, queryset)
|
||||
if self.queryset == None:
|
||||
self.queryset = Group.objects.filter(type="sdo")
|
||||
|
||||
def get_managed_list(self):
|
||||
return [(u'%s_%s' % (self.pk, i.pk), i.name) for i in self.queryset.order_by('name')]
|
||||
|
||||
def get_entity(self, pk=None):
|
||||
if not pk:
|
||||
return None
|
||||
try:
|
||||
obj = self.queryset.get(pk=pk)
|
||||
except self.queryset.model.DoesNotExist:
|
||||
return None
|
||||
return SDOEntity(name=obj.name, obj=obj)
|
||||
|
||||
|
||||
class IETFHierarchyManager(object):
|
||||
|
||||
def __init__(self):
|
||||
self.managers = {'ietf': IETFEntityManager(pk='ietf', name=u'The IETF'),
|
||||
'iesg': IETFEntityManager(pk='iesg', name=u'The IESG'),
|
||||
'iab': IABEntityManager(pk='iab', name=u'The IAB'),
|
||||
'iabiesg': IAB_IESG_EntityManager(pk='iabiesg', name=u'The IESG and the IAB'),
|
||||
'area': AreaEntityManager(pk='area', name=u'IETF Areas'),
|
||||
'wg': WGEntityManager(pk='wg', name=u'IETF Working Groups'),
|
||||
'sdo': SDOEntityManager(pk='sdo', name=u'Standards Development Organizations'),
|
||||
'othersdo': EntityManager(pk='othersdo', name=u'Other SDOs'),
|
||||
}
|
||||
|
||||
def get_entity_by_key(self, entity_id):
|
||||
if not entity_id:
|
||||
return None
|
||||
id_list = entity_id.split('_', 1)
|
||||
key = id_list[0]
|
||||
pk = None
|
||||
if len(id_list)==2:
|
||||
pk = id_list[1]
|
||||
if key not in self.managers.keys():
|
||||
return None
|
||||
return self.managers[key].get_entity(pk)
|
||||
|
||||
def get_all_entities(self):
|
||||
entities = []
|
||||
for manager in self.managers.values():
|
||||
entities += manager.get_managed_list()
|
||||
return entities
|
||||
|
||||
def get_all_incoming_entities(self):
|
||||
entities = []
|
||||
results = []
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
results += self.managers[key].get_managed_list()
|
||||
entities.append(('Main IETF Entities', results))
|
||||
entities.append(('IETF Areas', self.managers['area'].get_managed_list()))
|
||||
entities.append(('IETF Working Groups', self.managers['wg'].get_managed_list()))
|
||||
return entities
|
||||
|
||||
def get_all_outgoing_entities(self):
|
||||
entities = [(self.managers['sdo'].name, self.managers['sdo'].get_managed_list())]
|
||||
entities += [(self.managers['othersdo'].name, self.managers['othersdo'].get_managed_list())]
|
||||
return entities
|
||||
|
||||
def get_entities_for_person(self, person):
|
||||
entities = []
|
||||
results = []
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
results += self.managers[key].can_send_on_behalf(person)
|
||||
if results:
|
||||
entities.append(('Main IETF Entities', results))
|
||||
areas = self.managers['area'].can_send_on_behalf(person)
|
||||
if areas:
|
||||
entities.append(('IETF Areas', areas))
|
||||
wgs = self.managers['wg'].can_send_on_behalf(person)
|
||||
if wgs:
|
||||
entities.append(('IETF Working Groups', wgs))
|
||||
return entities
|
||||
|
||||
def get_all_can_approve_codes(self, person):
|
||||
entities = []
|
||||
for key in ['ietf', 'iesg', 'iab', 'iabiesg']:
|
||||
entities += self.managers[key].can_approve_list(person)
|
||||
entities += self.managers['area'].can_approve_list(person)
|
||||
entities += self.managers['wg'].can_approve_list(person)
|
||||
return [i[0] for i in entities]
|
||||
|
||||
|
||||
IETFHM = IETFHierarchyManager()
|
|
@ -4,52 +4,49 @@ from email.utils import parseaddr
|
|||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Q
|
||||
from django.core.validators import email_re
|
||||
from django.core.validators import validate_email, ValidationError
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden
|
||||
from django.shortcuts import render_to_response, get_object_or_404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.template import RequestContext
|
||||
from django.utils import simplejson
|
||||
from django.views.generic.list_detail import object_list, object_detail
|
||||
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
from ietf.liaisons.accounts import (get_person_for_user, can_add_outgoing_liaison,
|
||||
can_add_incoming_liaison, LIAISON_EDIT_GROUPS,
|
||||
is_ietfchair, is_iabchair, is_iab_executive_director,
|
||||
can_edit_liaison, is_secretariat)
|
||||
from ietf.liaisons.decorators import can_submit_liaison
|
||||
from ietf.liaisons.forms import liaison_form_factory
|
||||
from ietf.liaisons.models import LiaisonDetail, OutgoingLiaisonApproval
|
||||
from ietf.liaisons.utils import IETFHM
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
from ietf.liaisons.utils import IETFHM, can_submit_liaison_required, approvable_liaison_statements
|
||||
from ietf.liaisons.mails import notify_pending_by_email, send_liaison_by_email
|
||||
|
||||
|
||||
@can_submit_liaison
|
||||
|
||||
@can_submit_liaison_required
|
||||
def add_liaison(request, liaison=None):
|
||||
if request.method == 'POST':
|
||||
form = liaison_form_factory(request, data=request.POST.copy(),
|
||||
files = request.FILES, liaison=liaison)
|
||||
if form.is_valid():
|
||||
liaison = form.save()
|
||||
if request.POST.get('send', None):
|
||||
if liaison.is_pending():
|
||||
liaison.notify_pending_by_email()
|
||||
if request.POST.get('send', False):
|
||||
if not liaison.approved:
|
||||
notify_pending_by_email(request, liaison)
|
||||
else:
|
||||
liaison.send_by_email()
|
||||
send_liaison_by_email(request, liaison)
|
||||
return HttpResponseRedirect(reverse('liaison_list'))
|
||||
else:
|
||||
form = liaison_form_factory(request, liaison=liaison)
|
||||
|
||||
return render_to_response(
|
||||
'liaisons/liaisondetail_edit.html',
|
||||
'liaisons/edit.html',
|
||||
{'form': form,
|
||||
'liaison': liaison},
|
||||
context_instance=RequestContext(request),
|
||||
)
|
||||
|
||||
|
||||
@can_submit_liaison
|
||||
@can_submit_liaison_required
|
||||
def get_info(request):
|
||||
person = get_person_for_user(request.user)
|
||||
|
||||
|
@ -74,143 +71,84 @@ def get_info(request):
|
|||
result.update({'error': '\n'.join([to_error, from_error])})
|
||||
else:
|
||||
result.update({'error': False,
|
||||
'cc': [i.email() for i in to_entity.get_cc(person=person)] +\
|
||||
[i.email() for i in from_entity.get_from_cc(person=person)],
|
||||
'cc': ([i.email() for i in to_entity.get_cc(person=person)] +
|
||||
[i.email() for i in from_entity.get_from_cc(person=person)]),
|
||||
'poc': [i.email() for i in to_entity.get_poc()],
|
||||
'needs_approval': from_entity.needs_approval(person=person),
|
||||
'post_only': from_entity.post_only(person=person, user=request.user)})
|
||||
if is_secretariat(request.user):
|
||||
full_list = [(i.pk, i.email()) for i in set(from_entity.full_user_list())]
|
||||
full_list.sort(lambda x,y: cmp(x[1], y[1]))
|
||||
full_list.sort(key=lambda x: x[1])
|
||||
full_list = [(person.pk, person.email())] + full_list
|
||||
result.update({'full_list': full_list})
|
||||
|
||||
json_result = simplejson.dumps(result)
|
||||
return HttpResponse(json_result, mimetype='text/javascript')
|
||||
|
||||
def normalize_sort(request):
|
||||
sort = request.GET.get('sort', "")
|
||||
if sort not in ('submitted', 'deadline', 'title', 'to_name', 'from_name'):
|
||||
sort = "submitted"
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
def approvable_liaison_statements(group_codes):
|
||||
# this is a bit complicated because IETFHM encodes the
|
||||
# groups, it should just give us a list of ids or acronyms
|
||||
group_acronyms = []
|
||||
group_ids = []
|
||||
for x in group_codes:
|
||||
if "_" in x:
|
||||
group_ids.append(x.split("_")[1])
|
||||
else:
|
||||
group_acronyms.append(x)
|
||||
# reverse dates
|
||||
order_by = "-" + sort if sort in ("submitted", "deadline") else sort
|
||||
|
||||
return LiaisonDetail.objects.filter(approved=None).filter(Q(from_group__acronym__in=group_acronyms) | Q (from_group__pk__in=group_ids))
|
||||
return sort, order_by
|
||||
|
||||
def liaison_list(request):
|
||||
user = request.user
|
||||
can_send_outgoing = can_add_outgoing_liaison(user)
|
||||
can_send_incoming = can_add_incoming_liaison(user)
|
||||
can_approve = False
|
||||
can_edit = False
|
||||
sort, order_by = normalize_sort(request)
|
||||
liaisons = LiaisonStatement.objects.exclude(approved=None).order_by(order_by)
|
||||
|
||||
person = get_person_for_user(request.user)
|
||||
if person:
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
if is_secretariat(request.user):
|
||||
can_approve = LiaisonDetail.objects.filter(approved=None).order_by("-submitted").count()
|
||||
else:
|
||||
can_approve = approvable_liaison_statements(approval_codes).count()
|
||||
else:
|
||||
can_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).count()
|
||||
can_send_outgoing = can_add_outgoing_liaison(request.user)
|
||||
can_send_incoming = can_add_incoming_liaison(request.user)
|
||||
|
||||
order = request.GET.get('order_by', 'submitted_date')
|
||||
plain_order = order
|
||||
reverse_order = order.startswith('-')
|
||||
if reverse_order:
|
||||
plain_order = order[1:]
|
||||
if plain_order not in ('submitted_date', 'deadline_date', 'title', 'to_body', 'from_raw_body'):
|
||||
order = 'submitted_date'
|
||||
reverse_order = True
|
||||
plain_order = 'submitted_date'
|
||||
elif plain_order in ('submitted_date', 'deadline_date'):
|
||||
# Reverse order for date fields, humans find it more natural
|
||||
if reverse_order:
|
||||
order = plain_order
|
||||
else:
|
||||
order = '-%s' % plain_order
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
public_liaisons = LiaisonDetail.objects.exclude(approved=None).order_by(order)
|
||||
else:
|
||||
public_liaisons = LiaisonDetail.objects.filter(Q(approval__isnull=True)|Q(approval__approved=True)).order_by(order)
|
||||
approvable = approvable_liaison_statements(request.user).count()
|
||||
|
||||
return object_list(request, public_liaisons,
|
||||
allow_empty=True,
|
||||
template_name='liaisons/liaisondetail_list.html',
|
||||
extra_context={'can_manage': can_approve or can_send_incoming or can_send_outgoing,
|
||||
'can_approve': can_approve,
|
||||
'can_edit': can_edit,
|
||||
'can_send_incoming': can_send_incoming,
|
||||
'can_send_outgoing': can_send_outgoing,
|
||||
plain_order: not reverse_order and '-' or None},
|
||||
)
|
||||
return render_to_response('liaisons/overview.html', {
|
||||
"liaisons": liaisons,
|
||||
"can_manage": approvable or can_send_incoming or can_send_outgoing,
|
||||
"approvable": approvable,
|
||||
"can_send_incoming": can_send_incoming,
|
||||
"can_send_outgoing": can_send_outgoing,
|
||||
"sort": sort,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def ajax_liaison_list(request):
|
||||
sort, order_by = normalize_sort(request)
|
||||
liaisons = LiaisonStatement.objects.exclude(approved=None).order_by(order_by)
|
||||
|
||||
@can_submit_liaison
|
||||
return render_to_response('liaisons/liaison_table.html', {
|
||||
"liaisons": liaisons,
|
||||
"sort": sort,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
@can_submit_liaison_required
|
||||
def liaison_approval_list(request):
|
||||
if is_secretariat(request.user):
|
||||
to_approve = LiaisonDetail.objects.filter(approved=None).order_by("-submitted")
|
||||
else:
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
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")
|
||||
liaisons = approvable_liaison_statements(request.user).order_by("-submitted")
|
||||
|
||||
return object_list(request, to_approve,
|
||||
allow_empty=True,
|
||||
template_name='liaisons/liaisondetail_approval_list.html',
|
||||
)
|
||||
return render_to_response('liaisons/approval_list.html', {
|
||||
"liaisons": liaisons,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@can_submit_liaison
|
||||
@can_submit_liaison_required
|
||||
def liaison_approval_detail(request, object_id):
|
||||
if is_secretariat(request.user):
|
||||
to_approve = LiaisonDetail.objects.filter(approved=None).order_by("-submitted")
|
||||
else:
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
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")
|
||||
liaison = get_object_or_404(approvable_liaison_statements(request.user), pk=object_id)
|
||||
|
||||
if request.method=='POST' and request.POST.get('do_approval', False):
|
||||
try:
|
||||
liaison = to_approve.get(pk=object_id)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
liaison.approved = datetime.datetime.now()
|
||||
liaison.save()
|
||||
else:
|
||||
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()
|
||||
liaison.send_by_email()
|
||||
except LiaisonDetail.DoesNotExist:
|
||||
pass
|
||||
return HttpResponseRedirect(reverse('liaison_list'))
|
||||
return object_detail(request,
|
||||
to_approve,
|
||||
object_id=object_id,
|
||||
template_name='liaisons/liaisondetail_approval_detail.html',
|
||||
)
|
||||
liaison.approved = datetime.datetime.now()
|
||||
liaison.save()
|
||||
|
||||
send_liaison_by_email(request, liaison)
|
||||
return redirect('liaison_list')
|
||||
|
||||
return render_to_response('liaisons/approval_detail.html', {
|
||||
"liaison": liaison,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
|
||||
def _can_take_care(liaison, user):
|
||||
if not liaison.deadline_date or liaison.action_taken:
|
||||
if not liaison.deadline or liaison.action_taken:
|
||||
return False
|
||||
|
||||
if user.is_authenticated():
|
||||
|
@ -224,15 +162,18 @@ def _can_take_care(liaison, user):
|
|||
def _find_person_in_emails(liaison, person):
|
||||
if not person:
|
||||
return False
|
||||
emails = ','.join([ e for e in [liaison.cc1, liaison.cc2, liaison.to_email,
|
||||
liaison.to_poc, liaison.submitter_email,
|
||||
liaison.replyto, liaison.response_contact,
|
||||
liaison.technical_contact] if e ])
|
||||
|
||||
emails = ','.join(e for e in [liaison.cc, liaison.to_contact, liaison.to_name,
|
||||
liaison.reply_to, liaison.response_contact,
|
||||
liaison.technical_contact] if e)
|
||||
for email in emails.split(','):
|
||||
name, addr = parseaddr(email)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
person.emailaddress_set = person.email_set
|
||||
if email_re.search(addr) and person.emailaddress_set.filter(address=addr):
|
||||
try:
|
||||
validate_email(addr)
|
||||
except ValidationError:
|
||||
continue
|
||||
|
||||
if person.email_set.filter(address=addr):
|
||||
return True
|
||||
elif addr in ('chair@ietf.org', 'iesg@ietf.org') and is_ietfchair(person):
|
||||
return True
|
||||
|
@ -240,67 +181,31 @@ def _find_person_in_emails(liaison, person):
|
|||
return True
|
||||
elif addr in ('execd@iab.org', ) and is_iab_executive_director(person):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def liaison_detail(request, object_id):
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
qfilter = Q()
|
||||
public_liaisons = LiaisonDetail.objects.exclude(approved=None).order_by("-submitted_date")
|
||||
else:
|
||||
qfilter = Q(approval__isnull=True)|Q(approval__approved=True)
|
||||
public_liaisons = LiaisonDetail.objects.filter(qfilter).order_by("-submitted_date")
|
||||
liaison = get_object_or_404(public_liaisons, pk=object_id)
|
||||
can_edit = False
|
||||
user = request.user
|
||||
can_take_care = _can_take_care(liaison, user)
|
||||
if user.is_authenticated() and can_edit_liaison(user, liaison):
|
||||
can_edit = True
|
||||
liaison = get_object_or_404(LiaisonStatement.objects.exclude(approved=None), pk=object_id)
|
||||
can_edit = request.user.is_authenticated() and can_edit_liaison(request.user, liaison)
|
||||
can_take_care = _can_take_care(liaison, request.user)
|
||||
|
||||
if request.method == 'POST' and request.POST.get('do_action_taken', None) and can_take_care:
|
||||
liaison.action_taken = True
|
||||
liaison.save()
|
||||
can_take_care = False
|
||||
relations = liaison.liaisondetail_set.filter(qfilter)
|
||||
return object_detail(request,
|
||||
public_liaisons,
|
||||
template_name="liaisons/liaisondetail_detail.html",
|
||||
object_id=object_id,
|
||||
extra_context = {'can_edit': can_edit,
|
||||
'relations': relations,
|
||||
'can_take_care': can_take_care}
|
||||
)
|
||||
|
||||
relations = liaison.liaisonstatement_set.all()
|
||||
|
||||
return render_to_response("liaisons/detail.html", {
|
||||
"liaison": liaison,
|
||||
"can_edit": can_edit,
|
||||
"can_take_care": can_take_care,
|
||||
"relations": relations,
|
||||
}, context_instance=RequestContext(request))
|
||||
|
||||
def liaison_edit(request, object_id):
|
||||
liaison = get_object_or_404(LiaisonDetail, pk=object_id)
|
||||
user = request.user
|
||||
if not (user.is_authenticated() and can_edit_liaison(user, liaison)):
|
||||
return HttpResponseForbidden('You have no permission to edit this liaison')
|
||||
liaison = get_object_or_404(LiaisonStatement, pk=object_id)
|
||||
if not (request.user.is_authenticated() and can_edit_liaison(request.user, liaison)):
|
||||
return HttpResponseForbidden('You do not have permission to edit this liaison statement')
|
||||
return add_liaison(request, liaison=liaison)
|
||||
|
||||
def ajax_liaison_list(request):
|
||||
order = request.GET.get('order_by', 'submitted_date')
|
||||
plain_order = order
|
||||
reverse_order = order.startswith('-')
|
||||
if reverse_order:
|
||||
plain_order = order[1:]
|
||||
if plain_order not in ('submitted_date', 'deadline_date', 'title', 'to_body', 'from_raw_body'):
|
||||
order = 'submitted_date'
|
||||
reverse_order = True
|
||||
plain_order = 'submitted_date'
|
||||
elif plain_order in ('submitted_date', 'deadline_date'):
|
||||
# Reverse order for date fields, humans find it more natural
|
||||
if reverse_order:
|
||||
order = plain_order
|
||||
else:
|
||||
order = '-%s' % plain_order
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
public_liaisons = LiaisonDetail.objects.exclude(approved=None).order_by(order)
|
||||
else:
|
||||
public_liaisons = LiaisonDetail.objects.filter(Q(approval__isnull=True)|Q(approval__approved=True)).order_by(order)
|
||||
|
||||
return object_list(request, public_liaisons,
|
||||
allow_empty=True,
|
||||
template_name='liaisons/liaisondetail_simple_list.html',
|
||||
extra_context={plain_order: not reverse_order and '-' or None}
|
||||
)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.db.models.query import QuerySet
|
||||
from django.forms.widgets import Select, Widget, TextInput
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.html import conditional_escape
|
||||
|
||||
from ietf.liaisons.models import LiaisonStatement
|
||||
|
||||
|
||||
class FromWidget(Select):
|
||||
|
@ -14,9 +17,9 @@ class FromWidget(Select):
|
|||
|
||||
def render(self, name, value, attrs=None, choices=()):
|
||||
all_choices = list(self.choices) + list(choices)
|
||||
if len(all_choices)!=1 or \
|
||||
(isinstance(all_choices[0][1], (list, tuple)) and \
|
||||
len(all_choices[0][1])!=1):
|
||||
if (len(all_choices) != 1 or
|
||||
(isinstance(all_choices[0][1], (list, tuple)) and
|
||||
len(all_choices[0][1]) != 1)):
|
||||
base = super(FromWidget, self).render(name, value, attrs, choices)
|
||||
else:
|
||||
option = all_choices[0]
|
||||
|
@ -24,14 +27,14 @@ class FromWidget(Select):
|
|||
option = option[1][0]
|
||||
value = option[0]
|
||||
text = option[1]
|
||||
base = u'<input type="hidden" value="%s" id="id_%s" name="%s" />%s' % (value, name, name, text)
|
||||
base += u' (<a class="from_mailto" href="">' + self.submitter + u'</a>)'
|
||||
base = u'<input type="hidden" value="%s" id="id_%s" name="%s" />%s' % (conditional_escape(value), conditional_escape(name), conditional_escape(name), conditional_escape(text))
|
||||
base += u' (<a class="from_mailto" href="">' + conditional_escape(self.submitter) + u'</a>)'
|
||||
if self.full_power_on:
|
||||
base += '<div style="display: none;" class="reducedToOptions">'
|
||||
for from_code in self.full_power_on:
|
||||
base += '<span class="full_power_on_%s"></span>' % from_code
|
||||
base += '<span class="full_power_on_%s"></span>' % conditional_escape(from_code)
|
||||
for to_code in self.reduced_to_set:
|
||||
base += '<span class="reduced_to_set_%s"></span>' % to_code
|
||||
base += '<span class="reduced_to_set_%s"></span>' % conditional_escape(to_code)
|
||||
base += '</div>'
|
||||
return mark_safe(base)
|
||||
|
||||
|
@ -39,7 +42,7 @@ class FromWidget(Select):
|
|||
class ReadOnlyWidget(Widget):
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
html = u'<div id="id_%s">%s</div>' % (name, value or '')
|
||||
html = u'<div id="id_%s">%s</div>' % (conditional_escape(name), conditional_escape(value or ''))
|
||||
return mark_safe(html)
|
||||
|
||||
|
||||
|
@ -53,14 +56,14 @@ class ButtonWidget(Widget):
|
|||
super(ButtonWidget, self).__init__(*args, **kwargs)
|
||||
|
||||
def render(self, name, value, attrs=None):
|
||||
html = u'<span style="display: none" class="showAttachsOn">%s</span>' % self.show_on
|
||||
html += u'<span style="display: none" class="attachEnabledLabel">%s</span>' % self.label
|
||||
html = u'<span style="display: none" class="showAttachsOn">%s</span>' % conditional_escape(self.show_on)
|
||||
html += u'<span style="display: none" class="attachEnabledLabel">%s</span>' % conditional_escape(self.label)
|
||||
if self.require:
|
||||
for i in self.require:
|
||||
html += u'<span style="display: none" class="attachRequiredField">%s</span>' % i
|
||||
required_str = u'Please fill %s to attach a new file' % self.required_label
|
||||
html += u'<span style="display: none" class="attachDisabledLabel">%s</span>' % required_str
|
||||
html += u'<input type="button" class="addAttachmentWidget" value="%s" />' % self.label
|
||||
html += u'<span style="display: none" class="attachRequiredField">%s</span>' % conditional_escape(i)
|
||||
required_str = u'Please fill in %s to attach a new file' % conditional_escape(self.required_label)
|
||||
html += u'<span style="display: none" class="attachDisabledLabel">%s</span>' % conditional_escape(required_str)
|
||||
html += u'<input type="button" class="addAttachmentWidget" value="%s" />' % conditional_escape(self.label)
|
||||
return mark_safe(html)
|
||||
|
||||
|
||||
|
@ -71,8 +74,8 @@ class ShowAttachmentsWidget(Widget):
|
|||
html += u'<span style="display: none" class="showAttachmentsEmpty">No files attached</span>'
|
||||
html += u'<div class="attachedFiles">'
|
||||
if value and isinstance(value, QuerySet):
|
||||
for attach in value:
|
||||
html += u'<a class="initialAttach" href="%sfile%s%s">%s</a><br />' % (settings.LIAISON_ATTACH_URL, attach.file_id, attach.file_extension, attach.file_title, )
|
||||
for attachment in value:
|
||||
html += u'<a class="initialAttach" href="%s%s">%s</a><br />' % (settings.LIAISON_ATTACH_URL, conditional_escape(attachment.external_url), conditional_escape(attachment.title))
|
||||
else:
|
||||
html += u'No files attached'
|
||||
html += u'</div></div>'
|
||||
|
@ -88,23 +91,21 @@ class RelatedLiaisonWidget(TextInput):
|
|||
noliaison = 'inline'
|
||||
deselect = 'none'
|
||||
else:
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
from ietf.liaisons.proxy import LiaisonDetailProxy as LiaisonDetail
|
||||
liaison = LiaisonDetail.objects.get(pk=value)
|
||||
liaison = LiaisonStatement.objects.get(pk=value)
|
||||
title = liaison.title
|
||||
if not title:
|
||||
files = liaison.uploads_set.all()
|
||||
if files:
|
||||
title = files[0].file_title
|
||||
attachments = liaison.attachments.all()
|
||||
if attachments:
|
||||
title = attachments[0].title
|
||||
else:
|
||||
title = 'Liaison #%s' % liaison.pk
|
||||
noliaison = 'none'
|
||||
deselect = 'inline'
|
||||
html = u'<span class="noRelated" style="display: %s;">No liaison selected</span>' % noliaison
|
||||
html += u'<span class="relatedLiaisonWidgetTitle">%s</span>' % title
|
||||
html += u'<input type="hidden" name="%s" class="relatedLiaisonWidgetValue" value="%s" /> ' % (name, value)
|
||||
html += u'<span style="display: none;" class="listURL">%s</span> ' % reverse('ajax_liaison_list')
|
||||
html = u'<span class="noRelated" style="display: %s;">No liaison selected</span>' % conditional_escape(noliaison)
|
||||
html += u'<span class="relatedLiaisonWidgetTitle">%s</span>' % conditional_escape(title)
|
||||
html += u'<input type="hidden" name="%s" class="relatedLiaisonWidgetValue" value="%s" /> ' % (conditional_escape(name), conditional_escape(value))
|
||||
html += u'<span style="display: none;" class="listURL">%s</span> ' % urlreverse('ajax_liaison_list')
|
||||
html += u'<div style="display: none;" class="relatedLiaisonWidgetDialog" id="related-dialog" title="Select a liaison"></div> '
|
||||
html += '<input type="button" id="id_%s" value="Select liaison" /> ' % name
|
||||
html += '<input type="button" style="display: %s;" id="id_no_%s" value="Deselect liaison" />' % (deselect, name)
|
||||
html += '<input type="button" id="id_%s" value="Select liaison" /> ' % conditional_escape(name)
|
||||
html += '<input type="button" style="display: %s;" id="id_no_%s" value="Deselect liaison" />' % (conditional_escape(deselect), conditional_escape(name))
|
||||
return mark_safe(html)
|
||||
|
|
10
ietf/templates/liaisons/approval_detail.html
Normal file
10
ietf/templates/liaisons/approval_detail.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
{% extends "liaisons/detail.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% block content %}
|
||||
{{ block.super }}
|
||||
|
||||
<form method="post">
|
||||
<input type="submit" value="Approve" name='do_approval' />
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,4 +1,4 @@
|
|||
{% extends "liaisons/liaisondetail_list.html" %}
|
||||
{% extends "liaisons/overview.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% block title %}Pending Liaison Statements{% endblock %}
|
||||
|
120
ietf/templates/liaisons/detail.html
Normal file
120
ietf/templates/liaisons/detail.html
Normal file
|
@ -0,0 +1,120 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block title %}Liaison Statement: {% include 'liaisons/liaison_title.html' %}{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" type="text/css" href="/css/liaisons.css"></link>
|
||||
|
||||
<meta name="description" content="Liaison Statement from {{ liaison.from_name }}{% if liaison.from_contact %} to {{ liaison.to_name }}{% endif %} ({{ liaison.submitted|date:"Y" }})" />
|
||||
{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ietf-liaison-details tr { vertical-align:top; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Liaison Statement: {% include 'liaisons/liaison_title.html' %}</h1>
|
||||
|
||||
<table class="ietf-liaison-details">
|
||||
<tr>
|
||||
<td style="width:18ex;">Submission Date:</td>
|
||||
<td>{{ liaison.submitted|date:"Y-m-d" }}</td></tr>
|
||||
<tr>
|
||||
<td>From:</td>
|
||||
<td>{{ liaison.from_name }}
|
||||
{% if liaison.from_contact %}(<a href="mailto:{{ liaison.from_contact.address }}">{{ liaison.from_contact.person }}</a>){% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>To:</td>
|
||||
<td>
|
||||
{% if liaison.from_contact %}
|
||||
{{ liaison.to_name }} ({{ liaison.to_contact|parse_email_list }})
|
||||
{% else %}
|
||||
{{ liaison.to_name|urlize }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% if liaison.from_contact %}
|
||||
<tr>
|
||||
<td>Cc:</td><td>{{ liaison.cc|parse_email_list|make_one_per_line|safe|linebreaksbr }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Response Contact:</td>
|
||||
<td>{{ liaison.response_contact|parse_email_list|make_one_per_line|safe|linebreaksbr }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Technical Contact:</td>
|
||||
<td>{{ liaison.technical_contact|parse_email_list|make_one_per_line|safe|linebreaksbr }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Purpose:</td>
|
||||
<td>{{ liaison.purpose.name }}</td>
|
||||
</tr>
|
||||
|
||||
{% if liaison.deadline %}
|
||||
<tr>
|
||||
<td>Deadline:</td>
|
||||
<td>{{ liaison.deadline }}
|
||||
{% if liaison.action_taken %}<span class="actionTaken">Action Taken</span>{% else %}<span class="noActionTaken">Action Needed</span>{% endif %}
|
||||
{% if can_take_care %}
|
||||
<form method="post" style="display:inline">
|
||||
<input type="submit" value="Mark as Action Taken" name='do_action_taken' />
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if relations %}
|
||||
<tr>
|
||||
<td>Liaisons referring to this one:</td>
|
||||
<td>
|
||||
{% for rel in relations %}
|
||||
<a href="{% url liaison_detail rel.pk %}">{% if rel.title %}{{ rel.title }}{% else %}Liaison #{{ rel.pk }}{% endif %}</a><br />
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% if liaison.related_to %}
|
||||
<tr>
|
||||
<td>Referenced liaison:</td>
|
||||
<td>
|
||||
<a href="{% url liaison_detail liaison.related_to.pk %}">{% if liaison.related_to.title %}{{ liaison.related_to.title }}{% else %}Liaison #{{ liaison.related_to.pk }}{% endif %}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>Attachments:</td>
|
||||
<td>
|
||||
{% for doc in liaison.attachments.all %}
|
||||
<a href="https://datatracker.ietf.org/documents/LIAISON/{{ doc.external_url }}">{{ doc.title }}</a>{% if not forloop.last %}<br/>{% endif %}
|
||||
{% empty %}
|
||||
(none)
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% if liaison.from_contact and liaison.body %}
|
||||
<tr>
|
||||
<td>Body:</td>
|
||||
<td><pre>{{ liaison.body|wordwrap:"71" }}</pre></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
{% if can_edit %}
|
||||
<p><a href="{% url liaison_edit object_id=liaison.pk %}">Edit Liaison</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
32
ietf/templates/liaisons/edit.html
Normal file
32
ietf/templates/liaisons/edit.html
Normal file
|
@ -0,0 +1,32 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}{% if liaison %}Edit liaison: {{ liaison }}{% else %}Send Liaison Statement{% endif %}{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" type="text/css" href="/css/liaisons.css"></link>
|
||||
<link rel="stylesheet" type="text/css" href="/css/jquery-ui-themes/jquery-ui-1.8.11.custom.css"></link>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% if liaison %}Edit liaison: {{ liaison }}{% else %}Send Liaison Statement{% endif %}</h1>
|
||||
|
||||
<noscript class="js-info">
|
||||
This page depends on Javascript being enabled to work properly. Please enable Javascript and reload the page.
|
||||
</noscript>
|
||||
|
||||
{% if not liaison %}
|
||||
<ul>
|
||||
<li>If you wish to submit your liaison statement by e-mail, then please send it to <a href="mailto:statements@ietf.org">statements@ietf.org</a></li>
|
||||
<li>Fields marked with <span class="fieldRequired">*</span> are required. For detailed descriptions of the fields see <a href="/liaison/help/fields/">Field help</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{{ form }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script type="text/javascript" src="/js/jquery-ui-1.9.0.custom/minified/jquery-ui.custom.min.js"></script>
|
||||
<script type="text/javascript" src="/js/liaisons.js"></script>
|
||||
{% endblock %}
|
|
@ -1,19 +1,19 @@
|
|||
{% load ietf_filters %}{% autoescape off %}Title: {{ liaison.title|clean_whitespace }}
|
||||
Submission Date: {{ liaison.submitted_date }}
|
||||
Submission Date: {{ liaison.submitted|date:"Y-m-d" }}
|
||||
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 }}
|
||||
{% if liaison.deadline %}Please reply by {{ liaison.deadline }}{% endif %}
|
||||
From: {{ liaison.from_name }} ({{ liaison.from_contact.person }} <{{ liaison.reply_to|default:liaison.from_contact.address }}>)
|
||||
To: {{ liaison.to_name }} ({{ liaison.to_contact }})
|
||||
Cc: {{ liaison.cc }}
|
||||
Response Contact: {{ liaison.response_contact }}
|
||||
Technical Contact: {{ liaison.technical_contact }}
|
||||
Purpose: {% if liaison.purpose_text %}{{ liaison.purpose_text }}{% else %}{{ liaison.purpose }}{% endif %}
|
||||
Purpose: {{ liaison.purpose.name }}
|
||||
{% if liaison.related_to %}Referenced liaison: {% if liaison.related_to.title %}{{ liaison.related_to.title }}{% else %}Liaison #{{ liaison.related_to.pk }}{% endif %} ({{ referenced_url }}){% endif %}
|
||||
Body: {{ liaison.body }}
|
||||
Attachments:
|
||||
{% for file in liaison.uploads_set.all %}
|
||||
{{ file.file_title }}
|
||||
https://datatracker.ietf.org/documents/LIAISON/{{ file.filename }}
|
||||
{% for doc in liaison.attachments.all %}
|
||||
{{ doc.title }}
|
||||
https://datatracker.ietf.org/documents/LIAISON/{{ doc.external_url }}
|
||||
{% empty %}
|
||||
No document has been attached
|
||||
{% endfor %}{% endautoescape %}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}{{ liaison.title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Simulated Mail for Liaison Statement</h1>
|
||||
|
||||
<p>
|
||||
Demo version of this tool does NOT actually send the liaison statement to the recipients.
|
||||
</p>
|
||||
<p>
|
||||
Rather, the actual email body (including mail header) is displayed below.
|
||||
</p>
|
||||
<p>
|
||||
In production mode, you will not see this screen.
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
From: {{ message.From }}
|
||||
To: {{ message.To }}
|
||||
Cc: {{ message.Cc }}
|
||||
Bcc: {{ message.Bcc }}
|
||||
Subject: {{ message.Subject }}
|
||||
|
||||
{{ mail.body }}
|
||||
</pre>
|
||||
|
||||
<a href="{% url liaison_list %}">Return to liaison list</a>
|
||||
|
||||
{% endblock %}
|
|
@ -1,62 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}Liaison Management{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Liaison Management</h1>
|
||||
|
||||
{% if can_send_incoming or can_send_outgoing %}
|
||||
<div class="liaison-box">
|
||||
<h1>Add new liaison</h1>
|
||||
<ul>
|
||||
{% if can_send_incoming %}<li><a href="{% url add_liaison %}?incoming">Add new incoming liaison</a></li>{% endif %}
|
||||
{% if can_send_outgoing %}<li><a href="{% url add_liaison %}">Add new outgoing liaison</a></li>{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if to_aprove %}
|
||||
<div class="liaison-box pending-for-aproval">
|
||||
<h1>Liaisons that need your approval</h1>
|
||||
{% for liaison in to_aprove %}
|
||||
<a href="">{{ liaison }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if to_edit %}
|
||||
<div class="liaison-box edit-liaison-list">
|
||||
<h1>Liaisons you can edit</h1>
|
||||
{% for liaison in to_edit %}
|
||||
<tr class="{% cycle oddrow,evenrow %}">
|
||||
<td style="white-space:nowrap;">{{ liaison.submitted_date|date:"Y-m-d" }}</td>
|
||||
<td>{{ liaison.from_body|escape }}</td>
|
||||
<td>
|
||||
{% if liaison.by_secretariat %}
|
||||
{% if liaison.submitter_email %}
|
||||
<a href="mailto:{{ liaison.submitter_email}}">{{ liaison.submitter_name|escape }}</a>
|
||||
{% else %}
|
||||
{{ liaison.submitter_name|escape }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ liaison.to_body|escape }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<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/>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<a href="{{ liaison.detail_id }}/">{{ liaison.title|escape }}</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
39
ietf/templates/liaisons/liaison_table.html
Normal file
39
ietf/templates/liaisons/liaison_table.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% load ietf_filters %}
|
||||
|
||||
<table class="ietf-table" width="100%">
|
||||
<tr>
|
||||
<th width="9%" class="sort{% if sort == "submitted" %} sorted{% endif %}"><a href="?sort=submitted">Date</a></th>
|
||||
<th width="15%" class="sort{% if sort == "from_name" %} sorted{% endif %}"><a href="?sort=from_name">From</a></th>
|
||||
<th width="15%" class="sort{% if sort == "to_name" %} sorted{% endif %}"><a href="?sort=to_name">To</a></th>
|
||||
<th width="9%" class="sort{% if sort == "deadline" %} sorted{% endif %}"><a href="?sort=deadline">Deadline</a></th>
|
||||
<th width="50%" class="sort{% if sort == "title" %} sorted{% endif %}"><a href="?sort=title">Title</a></th>
|
||||
</tr>
|
||||
|
||||
{% for liaison in liaisons %}
|
||||
<tr class="{% cycle oddrow,evenrow %}">
|
||||
<td style="white-space:nowrap;">{{ liaison.submitted|date:"Y-m-d" }}</td>
|
||||
<td>{{ liaison.from_name }}</td>
|
||||
<td>
|
||||
{% if liaison.from_contact_id %}
|
||||
{{ liaison.to_name }}
|
||||
{% else %}
|
||||
{{ liaison.to_name|strip_email }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ liaison.deadline|default:"-"|date:"Y-m-d" }}
|
||||
</td>
|
||||
<td>
|
||||
{% if not liaison.from_contact_id %}
|
||||
{% for doc in liaison.attachments.all %}
|
||||
<a href="https://datatracker.ietf.org/documents/LIAISON/{{ doc.external_url }}">{{ doc.title }}</a><br/>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<a href="{% if liaison.approved %}{% url liaison_detail object_id=liaison.pk %}{% else %}{% url liaison_approval_detail object_id=liaison.pk %}{% endif %}">{{ liaison.title }}</a>
|
||||
{% endif %}
|
||||
<span style="display: none" class="liaisonPK">{{ liaison.pk }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
|
@ -1,5 +1,5 @@
|
|||
{% if object.by_secretariat %}
|
||||
Liaison statement submitted by email from {{ object.from_body|escape }} to {{ object.submitter_name|escape }} on {{ object.submitted_date }}
|
||||
{% load ietf_filters %}{% if not liaison.from_contact %}
|
||||
Liaison statement submitted by email from {{ liaison.from_name }} to {{ liaison.to_name|strip_email }} on {{ liaison.submitted|date:"Y-m-d" }}
|
||||
{% else %}
|
||||
{{ object.title }}
|
||||
{{ liaison.title }}
|
||||
{% endif %}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{% extends "liaisons/liaisondetail_detail.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
|
||||
{% block content %}
|
||||
{{ block.super }}
|
||||
|
||||
<form method="post" action="">
|
||||
<input type="submit" value="Approve" name='do_approval' />
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,110 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}Liaison Statement: {% include 'liaisons/liaison_title.html' %}{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
<link rel="stylesheet" type="text/css" href="/css/liaisons.css"></link>
|
||||
|
||||
<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" }})" />
|
||||
{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ietf-liaison-details tr { vertical-align:top; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Liaison Statement: {% include 'liaisons/liaison_title.html' %}</h1>
|
||||
<table class="ietf-liaison-details">
|
||||
<tr>
|
||||
<td style="width:18ex;">Submission Date:</td><td>{{ object.submitted_date }}</td></tr>
|
||||
<tr>
|
||||
<td>From:</td><td>{{ object.from_body }} (<a href="mailto:{{ object.from_email|fix_ampersands }}">{{ object.person }}</a>)</td></tr>
|
||||
|
||||
<tr>
|
||||
<td>To:</td><td>
|
||||
{% if object.by_secretariat %}
|
||||
{% if object.submitter_email %}
|
||||
<a href="mailto:{{ object.submitter_email}}">{{ object.submitter_name }}</a>
|
||||
{% else %}
|
||||
{{ object.submitter_name }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ object.to_body }} ({{ object.to_poc|parse_email_list|safe }})</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if not object.by_secretariat %}
|
||||
|
||||
<tr>
|
||||
<td>Cc:</td><td>{{ object.cc1|parse_email_list|make_one_per_line|safe|linebreaksbr }}</td></tr>
|
||||
<tr>
|
||||
<td>Response Contact:</td>
|
||||
<td>
|
||||
{{ object.response_contact|parse_email_list|make_one_per_line|safe|linebreaksbr }}
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td>Technical Contact:</td>
|
||||
<td>{{ object.technical_contact|parse_email_list|make_one_per_line|safe|linebreaksbr }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Purpose:</td><td>{% if object.purpose_text %}{{ object.purpose_text }}{% else %}{{ object.purpose }}{% endif %}</td></tr>
|
||||
{% if object.deadline_date %}
|
||||
<tr>
|
||||
<td>Deadline:</td>
|
||||
{% if can_take_care %}
|
||||
<td><form method="post" action="">
|
||||
{{ object.deadline_date }}
|
||||
{% if object.action_taken %}<span class="actionTaken">Action Taken</span>{% else %}<span class="noActionTaken">Action Required</span>{% endif %}
|
||||
<input type="submit" value="Mark as Action Taken" name='do_action_taken' />
|
||||
</form></td>
|
||||
{% else %}
|
||||
<td>{{ object.deadline_date }}
|
||||
{% if object.action_taken %}<span class="actionTaken">Action Taken</span>{% else %}<span class="noActionTaken">Action Needed</span>{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
{% if relations %}
|
||||
<tr>
|
||||
<td>Liaisons referring to this one:</td>
|
||||
<td>
|
||||
{% for liaison in relations %}
|
||||
<a href="../{{ liaison.pk }}">{% if liaison.title %}{{ object.title }}{% else %}Liaison #{{ liaison.pk }}{% endif %}</a><br />
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
|
||||
{% if object.related_to %}
|
||||
<tr>
|
||||
<td>Referenced liaison:</td>
|
||||
<td>
|
||||
<a href="../{{ object.related_to.pk }}">{% if object.related_to.title %}{{ object.related_to.title }}{% else %}Liaison #{{ object.related_to.pk }}{% endif %}</a>
|
||||
</td></tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>Attachments:</td>
|
||||
<td>
|
||||
{% for file in object.uploads_set.all %}
|
||||
<a href="https://datatracker.ietf.org/documents/LIAISON/{{ file.filename }}">{{ file.file_title }}</a>{% if not forloop.last %}<br/>{% endif %}
|
||||
{% empty %}
|
||||
(none)
|
||||
{% endfor %}
|
||||
</td></tr>
|
||||
|
||||
{% if not object.by_secretariat and object.body %}
|
||||
<tr>
|
||||
<td>Body:</td><td><pre>{{ object.body|wordwrap:"71"|escape }}</pre></td></tr>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
||||
{% if can_edit %}
|
||||
<form method="get" action="{% url liaison_edit object.pk %}">
|
||||
<input type="submit" value="Edit" />
|
||||
</form>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -1,31 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}{% if liaison %}Edit liaison: {{ liaison }}{% else %}Send Liaison Statement{% endif %}{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{{ form.media }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% if liaison %}Edit liaison: {{ liaison }}{% else %}Send Liaison Statement{% endif %}</h1>
|
||||
|
||||
<div class="js-info">
|
||||
Your browser has Javascript disabled. Please enable javascript and reload the page.
|
||||
<script type="text/javascript">
|
||||
(function ($) {
|
||||
$(".js-info").hide();
|
||||
})(jQuery);
|
||||
</script>
|
||||
</div>
|
||||
|
||||
{% if not liaison %}
|
||||
<ul>
|
||||
<li>If you wish to submit your liaison statement by e-mail, then please send it to <a href="mailto:statements@ietf.org">statements@ietf.org</a></li>
|
||||
<li>Fields marked with <span class="fieldRequired">*</span> are required. For detailed descriptions of the fields see <a href="/liaison/help/fields/">Field help</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{{ form }}
|
||||
|
||||
{% endblock %}
|
|
@ -1,51 +0,0 @@
|
|||
<table class="ietf-table" width="100%">
|
||||
<tr>
|
||||
<th width="9%" class="orderField orderField{{ submitted_date|yesno:"Active,Inactive,Reversed" }}">
|
||||
<a href="?order_by={{ submitted_date|default_if_none:"" }}submitted_date">Date</a>
|
||||
</th>
|
||||
<th width="15%" class="orderField orderField{{ from_raw_body|yesno:"Active,Inactive,Reversed" }}">
|
||||
<a href="?order_by={{ from_raw_body|default_if_none:"" }}from_raw_body">From</a>
|
||||
</th>
|
||||
<th width="15%" class="orderField orderField{{ to_body|yesno:"Active,Inactive,Reversed" }}">
|
||||
<a href="?order_by={{ to_body|default_if_none:"" }}to_body">To</a>
|
||||
</th>
|
||||
<th width="9%" class="orderField orderField{{ deadline_date|yesno:"Active,Inactive,Reversed" }}">
|
||||
<a href="?order_by={{ deadline_date|default_if_none:"" }}deadline_date">Deadline</a>
|
||||
</th>
|
||||
<th width="50%" class="orderField orderField{{ title|yesno:"Active,Inactive,Reversed" }}">
|
||||
<a href="?order_by={{ title|default_if_none:"" }}title">Title</a>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
{% for liaison in object_list %}
|
||||
<tr class="{% cycle oddrow,evenrow %}">
|
||||
<td style="white-space:nowrap;">{{ liaison.submitted_date|date:"Y-m-d" }}</td>
|
||||
<td>{{ liaison.from_body|escape }}</td>
|
||||
<td>
|
||||
{% if liaison.by_secretariat %}
|
||||
{% if liaison.submitter_email %}
|
||||
<a href="mailto:{{ liaison.submitter_email}}">{{ liaison.submitter_name|escape }}</a>
|
||||
{% else %}
|
||||
{{ liaison.submitter_name|escape }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ liaison.to_body|escape }}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{{ liaison.deadline_date|default:"--" }}
|
||||
</td>
|
||||
<td>
|
||||
{% if liaison.by_secretariat %}
|
||||
{% for file in liaison.uploads_set.all %}
|
||||
<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>
|
||||
{% endif %}
|
||||
<span style="display: none" class="liaisonPK">{{ liaison.pk }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
|
@ -18,12 +18,12 @@
|
|||
<ul>
|
||||
{% if can_send_incoming %}<li><a href="{% url add_liaison %}?incoming">Add new incoming liaison</a></li>{% endif %}
|
||||
{% if can_send_outgoing %}<li><a href="{% url add_liaison %}">Add new outgoing liaison</a></li>{% endif %}
|
||||
{% if can_approve %}<li><a href="{% url liaison_approval_list %}">You have {{ can_approve }} pending liaison statement{{ can_approve|pluralize }} that need{{ can_approve|pluralize:"s," }} your approval</a></li>{% endif %}
|
||||
{% if approvable %}<li><a href="{% url liaison_approval_list %}">You have {{ approvable }} pending liaison statement{{ approvable|pluralize }} that need{{ approvable|pluralize:"s," }} your approval</a></li>{% endif %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% include "liaisons/liaisondetail_simple_list.html" %}
|
||||
{% include "liaisons/liaison_table.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -96,30 +96,17 @@ span.fieldRequired {
|
|||
background-color: #ffdd88;
|
||||
}
|
||||
|
||||
th.orderField a {
|
||||
th.sort a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
display: block;
|
||||
padding-right: 20px;
|
||||
background: url(/images/sort-header-clear.png) no-repeat right center;
|
||||
}
|
||||
|
||||
th.orderFieldReversed a {
|
||||
background: #2647A0 url(/images/arrow-down.gif) no-repeat left center;
|
||||
padding-left: 20px;
|
||||
th.sorted a {
|
||||
background: url(/images/sort-header-filled.png) no-repeat right center;
|
||||
}
|
||||
|
||||
th.orderFieldActive a {
|
||||
background: #2647A0 url(/images/arrow-up.gif) no-repeat left center;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.noActionTaken,
|
||||
.actionTaken {
|
||||
border: 1px solid green;
|
||||
padding: 2px 5px;
|
||||
background-color: #ccffbb;
|
||||
}
|
||||
|
||||
.noActionTaken {
|
||||
border: 1px solid red;
|
||||
background-color: #ffccbb;
|
||||
}
|
||||
.noActionTaken, .actionTaken { padding: 2px 5px; }
|
||||
.actionTaken { border: 1px solid green; background-color: #ccffbb; }
|
||||
.noActionTaken { border: 1px solid red; background-color: #ffccbb; }
|
||||
|
|
Loading…
Reference in a new issue