Port wginfo views

- Legacy-Id: 3160
This commit is contained in:
Ole Laursen 2011-05-27 21:33:48 +00:00
parent 68d0e4c801
commit 5dcc94e5a4
23 changed files with 685 additions and 228 deletions

View file

@ -378,9 +378,10 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
# canonical name
for r in results:
if r.pk in rfc_aliases:
r.canonical_name = rfc_aliases[r.pk]
# lambda weirdness works around lambda binding in local for loop scope
r.canonical_name = (lambda x: lambda: x)(rfc_aliases[r.pk])
else:
r.canonical_name = r.name
r.canonical_name = (lambda x: lambda: x)(r.name)
result_map = dict((r.pk, r) for r in results)
@ -419,12 +420,13 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
# sort
def sort_key(d):
if d.canonical_name.startswith('rfc'):
return (2, "%06d" % int(d.canonical_name[3:]))
n = d.canonical_name()
if n.startswith('rfc'):
return (2, "%06d" % int(n[3:]))
elif d.state_id == "active":
return (1, d.canonical_name)
return (1, n)
else:
return (3, d.canonical_name)
return (3, n)
results.sort(key=sort_key)

View file

@ -95,7 +95,8 @@ class IETFWGAdmin(admin.ModelAdmin):
list_display=('group_acronym', 'group_type', 'status', 'area_acronym', 'start_date', 'concluded_date')
search_fields=['group_acronym__acronym', 'group_acronym__name']
list_filter=['status', 'group_type']
admin.site.register(IETFWG, IETFWGAdmin)
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
admin.site.register(IETFWG, IETFWGAdmin)
class IRTFAdmin(admin.ModelAdmin):
pass

View file

@ -1096,8 +1096,9 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
AreaOld = Area
AcronymOld = Acronym
IESGLoginOld = IESGLogin
IETFWGOld = IETFWG
from redesign.doc.proxy import InternetDraft, IDInternal, BallotInfo, IDState, IDSubState, Rfc
from redesign.group.proxy import Area, Acronym
from redesign.group.proxy import Area, Acronym, IETFWG
from redesign.person.proxy import IESGLogin

View file

@ -1,14 +1,9 @@
# Copyright The IETF Trust 2007, All Rights Reserved
from django.conf.urls.defaults import patterns
from django.conf import settings
from ietf.idtracker.models import IETFWG
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from redesign.group.proxy import IETFWG
http_archive_wg_queryset = IETFWG.objects.filter(list_pages__startswith='http')
else:
http_archive_wg_queryset = IETFWG.objects.filter(email_archive__startswith='http')
http_archive_wg_queryset = IETFWG.objects.filter(email_archive__startswith='http')
urlpatterns = patterns('django.views.generic.list_detail',
(r'^wg/$', 'object_list', { 'queryset': http_archive_wg_queryset, 'template_name': 'mailinglists/wgwebmail_list.html' }),

View file

@ -2,14 +2,9 @@
IETF Working Group Summary (By Acronym)
The following Area Abreviations are used in this document
The following Area Abbreviations are used in this document
{% for area in area_list %}
{{ area }} - {{ area.area_acronym.name }}{% endfor %}
{{ area|upper }} - {{ area.area_acronym.name }}{% endfor %}
{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.start_date %}
{{ wg.group_acronym.name|safe }} ({{ wg }}) -- {{ wg.area.area|upper }}
{% for chair in wg.wgchair_set.all %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person|safe }} <{{ chair.person.email.1 }}>
{% endfor %} WG Mail: {{ wg.email_address }}
To Join: {{ wg.email_subscribe }}{%if wg.email_keyword %}
In Body: {{ wg.email_keyword|safe }}{% endif %}
Archive: {{ wg.email_archive }}
{% endif %}{% endfor %}
{% include "wginfo/wg_summary.txt" %}{% endif %}{% endfor %}

View file

@ -5,9 +5,4 @@
{{ ad.person }} <{{ ad.person.email.1 }}>{% endfor %}
{% endif %}{% if wg.start_date %}
{{ wg.group_acronym.name|safe }} ({{ wg }})
{% for chair in wg.wgchair_set.all %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person|safe }} <{{ chair.person.email.1 }}>
{% endfor %} WG Mail: {{ wg.email_address }}
To Join: {{ wg.email_subscribe }}{%if wg.email_keyword %}
In Body: {{ wg.email_keyword|safe }}{% endif %}
Archive: {{ wg.email_archive }}
{% endif %}{% endifequal %}{% endfor %}{% endfor %}
{% include "wginfo/wg_summary.txt" %}{% endif %}{% endifequal %}{% endfor %}{% endfor %}

View file

@ -1,4 +1,4 @@
{% load ietf_filters %}{{wg.group_acronym.name|safe}} ({{wg}})
{% if USE_DB_REDESIGN_PROXY_CLASSES %}{% include "wginfo/wg-charterREDESIGN.txt" %}{% else %}{% load ietf_filters %}{{wg.group_acronym.name|safe}} ({{wg}})
{{ wg.group_acronym.name|dashify }}{{ wg.group_acronym.acronym|dashify }}---
Charter
@ -44,4 +44,4 @@ Internet-Drafts:
* {{obs.action}} RFC{{obs.rfc_acted_on_id}}{% endfor %}{% for obs in rfc.obsoleted_by%}
* {%ifequal obs.action 'Obsoletes'%}OBSOLETED BY{%else%}Updated by{%endifequal%} RFC{{obs.rfc_id}}{% endfor %}
{%endfor%}
{%else%}No Requests for Comments{% endif %}
{%else%}No Requests for Comments{% endif %}{% endif %}

View file

@ -0,0 +1,47 @@
{% load ietf_filters %}{{wg.name|safe}} ({{wg.acronym}})
{{ wg.name|dashify }}{{ wg.acronym|dashify }}---
Charter
Last Modified: {{ wg.time.date }}
Current Status: {{ wg.state.name }}
Chair{{ wg.chairs|pluralize }}:
{% for chair in wg.chairs %} {{ chair.person.name|safe }} <{{chair.address}}>
{% endfor %}
{{wg.area.area.area_acronym.name}} Directors:
{% for ad in wg.area_directors %} {{ ad.person|safe }} <{{ad.person.email.1}}>
{% endfor %}
{{wg.area.area.area_acronym.name}} Advisor:
{{ wg.areadirector.person.name|safe }} <{{wg.areadirector.address}}>
{% if wg.techadvisors %}
Tech Advisor{{ wg.techadvisors|pluralize }}:
{% for techadvisor in wg.techadvisors %} {{ techadvisor.person.name|safe }} <{{techadvisor.address}}>
{% endfor %}{% endif %}{% if wg.editors %}
Editor{{ wg.editors|pluralize }}:
{% for editor in wg.editors %} {{ editor.person.name|safe }} <{{editor.person.address}}>
{% endfor %}{% endif %}{% if wg.secretaries %}
Secretar{{ wg.secretaries|pluralize:"y,ies" }}:
{% for secretary in wg.secretaries %} {{ secretary.person.name|safe }} <{{secretary.person.address}}>
{% endfor %}{% endif %}
Mailing Lists:
General Discussion: {{ wg.email_address }}
To Subscribe: {{ wg.email_subscribe }}
Archive: {{ wg.email_archive }}
Description of Working Group:
{{ wg.charter_text|indent|safe }}
Goals and Milestones:
{% for milestone in wg.milestones %} {% if milestone.done %}Done {% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }}
{% endfor %}
Internet-Drafts:
{% for alias in wg.drafts %} - {{alias.document.title|safe}} [{{alias.name}}-{{alias.document.rev}}] ({{ alias.document.pages }} pages)
{% endfor %}
{% if wg.rfcs %}Requests for Comments:
{% for alias in wg.rfcs %} {{ alias.name.upper }}: {{ alias.document.title|safe}} ({{ alias.document.pages }} pages){% for r in alias.rel %}
* {{ r.action }} {{ r.target.name|upper }}{% endfor %}{% for r in alias.invrel %}
* {% ifequal r.relationsship "obs" %}{{ r.inverse_action|upper }}{% else %}{{ r.action }}{% endifequal %} {{ r.source.canonical_name|upper }}{% endfor %}
{%endfor%}
{%else%}No Requests for Comments{% endif %}

View file

@ -0,0 +1,92 @@
{% extends "base.html" %}
{# Copyright The IETF Trust 2009, All Rights Reserved #}
{% comment %}
Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the Nokia Corporation and/or its
subsidiary(-ies) nor the names of its contributors may be used
to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endcomment %}
{% block title %}Active IETF Working Groups{% endblock %}
{% block morecss %}
.ietf-wg-table { width: 100%; max-width:50em; }
.ietf-wg-table tr { vertical-align:top; }
{% endblock morecss %}
{% block content %}
<h1>Active IETF Working Groups</h1>
<p>See also: <a href="http://www.ietf.org/wg/concluded/">Concluded
Working Groups (www.ietf.org)</a>, <a href="http://tools.ietf.org/wg/concluded/">Concluded Working Groups (tools.ietf.org)</a>, <a href="http://www.ietf.org/dyn/wg/charter/history/">Historic Charters</a>.</p>
{% for area in areas %}
<h2 class="ietf-divider" id="{{ area.name|cut:" " }}">{{ area.name }}</h2>
{% for ad in area.ads %}
{% if forloop.first %}
<p>Area Director{{ forloop.revcounter|pluralize }}:</p>
<p style="margin-left: 2em">
{% endif %}
<a href="mailto:{{ ad.address }}">{{ ad.person.name }} &lt;{{ ad.address }}&gt;</a>{% if not forloop.last %}<br/>{% endif %}
{% if forloop.last %}
</p>
{% endif %}
{% endfor %}
{% for url in area.urls %}
{% if forloop.first %}
<p>Area Specific Web Page{{ forloop.revcounter|pluralize}}:</p>
<p style="margin-left: 2em">
{% endif %}
<a href="{{url.url}}">{{ url.name }}</a>{% if not forloop.last %}<br/>{% endif %}
{% if forloop.last %}
</p>
{% endif %}
{% endfor %}
{% for wg in area.wgs %}
{% if forloop.first %}
<p>Active Working Groups:</p>
<div style="margin-left:2em;">
<table class="ietf-wg-table">
{% endif %}
<tr><td width="10%;"><a href="/wg/{{ wg.acronym }}/">{{ wg.acronym }}</a></td><td width="50%">{{ wg.name }}</td>
<td width="39%">{% for chair in wg.chairs %}<a href="mailto:{{ chair.address }}">{{ chair.person.name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
{% if forloop.last %}
</table>
</div>
{% endif %}
{% empty %}
<p>No Active Working Groups</p>
{% endfor %}{# wg #}
{% endfor %}{# area #}
{% endblock %}

View file

@ -0,0 +1,137 @@
{% extends "wginfo/wg_base.html" %}
{% comment %}
Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the Nokia Corporation and/or its
subsidiary(-ies) nor the names of its contributors may be used
to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endcomment %}
{% load ietf_filters %}
{% block wg_titledetail %}Charter{% endblock %}
{% block wg_content %}
<div class="ietf-box ietf-wg-details">
{% if concluded %}
<span class="ietf-concluded-warning">Note: The data for concluded WGs
is occasionally incorrect.</span>
{% endif %}
<table>
<tr>
<td colspan="2">
<b>Personnel</b>
</td>
</tr>
<tr valign="top">
<td style="width:14ex;">Chair{{ wg.chairs|pluralize }}:</td>
<td>
{% for chair in wg.chairs %}
<a href="mailto:{{ chair.address }}">{{ chair.person.name }} &lt;{{ chair.address }}&gt;</a><br/>
{% endfor %}
</td></tr>
<tr><td>Area Director:</td>
<td>
{% if not wg.ad %}?{% else %}
<a href="mailto:{{ wg.ad_email }}">{{ wg.ad.name }} &lt;{{ wg.ad_email }}&gt;</a>{% endif %}
</td>
</tr>
{% if wg.techadvisors %}
<tr>
<td>Tech Advisor{{ wg.techadvisors|pluralize }}:</td>
<td>
{% for techadvisor in wg.techadvisors %}
<a href="mailto:{{ techadvisor.address }}">{{ techadvisor.person.name }} &lt;{{ techadvisor.address }}&gt;</a><br/>
{% endfor %}
</td></tr>
{% endif %}
{% if wg.editors %}
<td>Editor{{ wg.editors|pluralize }}:</td>
<td>
{% for editor in wg.editors %}
<a href="mailto:{{ editor.address }}">{{ editor.person.name }} &lt;{{ editor.address }}&gt;</a><br/>
{% endfor %}
</td></tr>
{% endif %}
{% if wg.secretaries %}
<tr><td>Secretar{{ wg.secretaries|pluralize:"y,ies" }}:</td>
<td>
{% for secretary in wg.secretaries %}
<a href="mailto:{{ secretary.address }}">{{ secretary.person.name }} &lt;{{ secretary.address }}&gt;</a><br/>
{% endfor %}
</td></tr>
{% endif %}
<tr>
<td colspan="2">
<br/><b>Mailing List</b>
</td>
</tr>
<tr><td>Address:</td><td>{{ wg.email_address|urlize }}</td></tr>
<tr><td>To Subscribe:</td><td>{{ wg.email_subscribe|urlize }}</td></tr>
<tr><td>Archive:</td><td>{{ wg.clean_email_archive|urlize }}</td></tr>
{% if not concluded %}
<tr>
<td colspan="2">
<br/><b>Jabber Chat</b>
</td>
</tr>
<tr><td>Room Address:</td><td><a href="xmpp:{{wg}}@jabber.ietf.org">xmpp:{{wg}}@jabber.ietf.org</a></td></tr>
<tr><td>Logs:</td><td><a href="http://jabber.ietf.org/logs/{{wg}}/">http://jabber.ietf.org/logs/{{wg}}/</a></td></tr>
{% endif %}
</table>
</div>
{% if wg.additional_urls %}
<p>In addition to the charter maintained by the IETF Secretariat, there is additional information about this working group on the Web at:
{% for url in wg.additional_urls %}
<a href="{{ url.url }}">{{ url.description}}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
<h2>Description of Working Group</h2>
<p>{{ wg.charter_text|escape|format_charter|safe }}</p>
<h2>Goals and Milestones</h2>
<table>
{% for milestone in wg.milestones %}
<tr>
<td width="80px">
{% if milestone.done %}Done{% else %}{{ milestone.expected_due_date|date:"M Y" }}{% endif %}
</td>
<td>{{ milestone.desc|escape }}
</td></tr>
{% endfor %}
</table>
{% endblock wg_content %}

View file

@ -0,0 +1,5 @@
{% for chair in wg.wgchair_set.all %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person|safe }} <{{ chair.person.email.1 }}>
{% endfor %} WG Mail: {{ wg.email_address }}
To Join: {{ wg.email_subscribe }}{%if wg.email_keyword %}
In Body: {{ wg.email_keyword|safe }}{% endif %}
Archive: {{ wg.email_archive }}

View file

@ -32,13 +32,37 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from ietf.idtracker.models import Area, IETFWG
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext, loader
from django.http import HttpResponse
from django.conf import settings
from ietf.idtracker.models import Area, IETFWG
from ietf.idrfc.views_search import SearchForm, search_query
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper
def fill_in_charter_info(wg, include_drafts=False):
from redesign.person.models import Email
from redesign.doc.models import DocAlias, RelatedDocument
wg.areadirector = wg.ad.role_email("ad", wg.parent) if wg.ad else None
wg.chairs = Email.objects.filter(role__group=wg, role__name="chair")
wg.techadvisors = Email.objects.filter(role__group=wg, role__name="techadv")
wg.editors = Email.objects.filter(role__group=wg, role__name="editor")
wg.secretaries = Email.objects.filter(role__group=wg, role__name="secr")
wg.milestones = wg.groupmilestone_set.all().order_by('expected_due_date')
if include_drafts:
aliases = DocAlias.objects.filter(document__type="draft", document__group=wg).select_related('document').order_by("name")
wg.drafts = []
wg.rfcs = []
for a in aliases:
if a.name.startswith("draft"):
wg.drafts.append(a)
else:
wg.rfcs.append(a)
a.rel = RelatedDocument.objects.filter(source=a.document).distinct()
a.invrel = RelatedDocument.objects.filter(target=a).distinct()
def wg_summary_acronym(request):
areas = Area.active_areas()
wgs = IETFWG.objects.filter(status=IETFWG.ACTIVE)
@ -50,16 +74,39 @@ def wg_summary_area(request):
def wg_charters(request):
wgs = IETFWG.objects.filter(status='1',start_date__isnull=False)
return HttpResponse(loader.render_to_string('wginfo/1wg-charters.txt', {'wg_list': wgs}),mimetype='text/plain; charset=UTF-8')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
for wg in wgs:
fill_in_charter_info(wg, include_drafts=True)
return HttpResponse(loader.render_to_string('wginfo/1wg-charters.txt', {'wg_list': wgs, 'USE_DB_REDESIGN_PROXY_CLASSES': settings.USE_DB_REDESIGN_PROXY_CLASSES}),mimetype='text/plain; charset=UTF-8')
def wg_charters_by_acronym(request):
wgs = IETFWG.objects.filter(status='1',start_date__isnull=False)
return HttpResponse(loader.render_to_string('wginfo/1wg-charters-by-acronym.txt', {'wg_list': wgs}),mimetype='text/plain; charset=UTF-8')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
for wg in wgs:
fill_in_charter_info(wg, include_drafts=True)
return HttpResponse(loader.render_to_string('wginfo/1wg-charters-by-acronym.txt', {'wg_list': wgs, 'USE_DB_REDESIGN_PROXY_CLASSES': settings.USE_DB_REDESIGN_PROXY_CLASSES}),mimetype='text/plain; charset=UTF-8')
def wg_dir(request):
areas = Area.active_areas()
return render_to_response('wginfo/wg-dir.html', {'areas':areas}, RequestContext(request))
def wg_dirREDESIGN(request):
from redesign.group.models import Group, GroupURL
from redesign.person.models import Email
areas = Group.objects.filter(type="area", state="active").order_by("name")
for area in areas:
area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=lambda e: e.person.name_parts()[3])
area.wgs = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym")
area.urls = area.groupurl_set.all().order_by("name")
for wg in area.wgs:
wg.chairs = sorted(Email.objects.filter(role__group=wg, role__name="chair").select_related("person"), key=lambda e: e.person.name_parts()[3])
return render_to_response('wginfo/wg-dirREDESIGN.html', {'areas':areas}, RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
wg_dir = wg_dirREDESIGN
def wg_documents(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
concluded = (wg.status_id != 1)
@ -88,4 +135,13 @@ def wg_documents(request, acronym):
def wg_charter(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
concluded = (wg.status_id != 1)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
fill_in_charter_info(wg)
return render_to_response('wginfo/wg_charterREDESIGN.html',
dict(wg=wg,
concluded=concluded,
selected='charter'),
RequestContext(request))
return render_to_response('wginfo/wg_charter.html', {'wg': wg, 'concluded':concluded, 'selected':'charter'}, RequestContext(request))

View file

@ -42,19 +42,16 @@ class DocumentInfo(models.Model):
abstract = True
def author_list(self):
return ", ".join(email.address for email in self.authors.all())
def latest_event(self, *args, **filter_args):
"""Get latest event of optional Python type and with filter
arguments, e.g. d.latest_event(type="xyz") returns an Event
while d.latest_event(WriteupEvent, type="xyz") returns a
WriteupEvent event."""
model = args[0] if args else Event
e = model.objects.filter(doc=self).filter(**filter_args).order_by('-time', '-id')[:1]
return e[0] if e else None
class RelatedDocument(models.Model):
source = models.ForeignKey('Document')
target = models.ForeignKey('DocAlias')
relationship = models.ForeignKey(DocRelationshipName)
def action(self):
return self.relationship.name
def inverse_action():
infinitive = self.relationship.name[:-1]
return u"%sd by" % infinitive
def __unicode__(self):
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)
@ -89,6 +86,21 @@ class Document(DocumentInfo):
# FIXME: compensate for tombstones?
return u"<%s-%s.txt>" % (self.name, self.rev)
def latest_event(self, *args, **filter_args):
"""Get latest event of optional Python type and with filter
arguments, e.g. d.latest_event(type="xyz") returns an Event
while d.latest_event(WriteupEvent, type="xyz") returns a
WriteupEvent event."""
model = args[0] if args else Event
e = model.objects.filter(doc=self).filter(**filter_args).order_by('-time', '-id')[:1]
return e[0] if e else None
def canonical_name(self):
if self.type_id == "draft" and self.state_id == "rfc":
return self.docalias_set.get(name__startswith="rfc").name
else:
return self.name
class RelatedDocHistory(models.Model):
source = models.ForeignKey('DocHistory')
target = models.ForeignKey('DocAlias', related_name="reversely_related_document_history_set")

View file

@ -1,6 +1,7 @@
from redesign.doc.models import *
from redesign.person.models import Email
from redesign.proxy_utils import TranslatingManager
from redesign.name.proxy import *
from django.conf import settings
@ -86,8 +87,7 @@ class InternetDraft(Document):
#status = models.ForeignKey(IDStatus)
@property
def status(self):
from redesign.name.proxy import IDStatus
return IDStatus(self.state) if self.state else None
return IDStatus().from_object(self.state) if self.state else None
@property
def status_id(self):
@ -132,11 +132,8 @@ class InternetDraft(Document):
@property
def rfc_number(self):
# simple optimization for search results
if hasattr(self, "canonical_name"):
return int(self.canonical_name[3:]) if self.canonical_name.startswith('rfc') else None
aliases = self.docalias_set.filter(name__startswith="rfc")
return int(aliases[0].name[3:]) if aliases else None
n = self.canonical_name()
return int(n[3:]) if n.startswith("rfc") else None
#comments = models.TextField(blank=True) # unused
@ -857,100 +854,6 @@ class Position(BallotPositionEvent):
class Meta:
proxy = True
class IDState(IesgDocStateName):
PUBLICATION_REQUESTED = 10
LAST_CALL_REQUESTED = 15
IN_LAST_CALL = 16
WAITING_FOR_WRITEUP = 18
WAITING_FOR_AD_GO_AHEAD = 19
IESG_EVALUATION = 20
IESG_EVALUATION_DEFER = 21
APPROVED_ANNOUNCEMENT_SENT = 30
AD_WATCHING = 42
DEAD = 99
DO_NOT_PUBLISH_STATES = (33, 34)
objects = TranslatingManager(dict(pk="order"))
def from_object(self, base):
for f in base._meta.fields:
setattr(self, f.name, getattr(base, f.name))
return self
#document_state_id = models.AutoField(primary_key=True)
@property
def document_state_id(self):
return self.order
#state = models.CharField(max_length=50, db_column='document_state_val')
@property
def state(self):
return self.name
#equiv_group_flag = models.IntegerField(null=True, blank=True) # unused
#description = models.TextField(blank=True, db_column='document_desc')
@property
def description(self):
return self.desc
@property
def nextstate(self):
# simulate related queryset
from name.models import get_next_iesg_states
return IDState.objects.filter(pk__in=[x.pk for x in get_next_iesg_states(self)])
@property
def next_state(self):
# simulate IDNextState
return self
def __str__(self):
return self.state
@staticmethod
def choices():
return [(state.slug, state.name) for state in IDState.objects.all()]
class Meta:
proxy = True
class IDSubStateManager(TranslatingManager):
def __init__(self, *args):
super(IDSubStateManager, self).__init__(*args)
def all(self):
return self.filter(slug__in=['extpty', 'need-rev', 'ad-f-up', 'point'])
class IDSubState(DocInfoTagName):
objects = IDSubStateManager(dict(pk="order"))
def from_object(self, base):
for f in base._meta.fields:
setattr(self, f.name, getattr(base, f.name))
return self
#sub_state_id = models.AutoField(primary_key=True)
@property
def sub_state_id(self):
return self.order
#sub_state = models.CharField(max_length=55, db_column='sub_state_val')
@property
def sub_state(self):
return self.name
#description = models.TextField(blank=True, db_column='sub_state_desc')
@property
def description(self):
return self.desc
def __str__(self):
return self.sub_state
class Meta:
proxy = True
class DraftLikeDocAlias(DocAlias):
# this class is mostly useful for the IPR part

View file

@ -7,14 +7,17 @@ from redesign.person.models import Email, Person
import datetime
class Group(models.Model):
time = models.DateTimeField(default=datetime.datetime.now) # should probably have auto_now=True
name = models.CharField(max_length=80)
acronym = models.CharField(max_length=16, db_index=True)
state = models.ForeignKey(GroupStateName, null=True)
type = models.ForeignKey(GroupTypeName, null=True)
charter = models.OneToOneField('doc.Document', related_name='chartered_group', blank=True, null=True)
parent = models.ForeignKey('Group', blank=True, null=True)
ad = models.ForeignKey(Person, blank=True, null=True)
list_email = models.CharField(max_length=64, blank=True)
list_pages = models.CharField(max_length=255, blank=True)
list_subscribe = models.CharField(max_length=255, blank=True)
list_archive = models.CharField(max_length=255, blank=True)
comments = models.TextField(blank=True)
def __unicode__(self):
return self.name
@ -24,6 +27,22 @@ class Group(models.Model):
e = GroupEvent.objects.filter(group=self).filter(**filter_args).order_by('-time', '-id')[:1]
return e[0] if e else None
class GroupURL(models.Model):
group = models.ForeignKey(Group)
name = models.CharField(max_length=255)
url = models.URLField(verify_exists=False)
class GroupMilestone(models.Model):
group = models.ForeignKey(Group)
desc = models.TextField()
expected_due_date = models.DateField()
done = models.BooleanField()
done_date = models.DateField(null=True, blank=True)
time = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.desc[:20] + "..."
class Meta:
ordering = ['expected_due_date']
GROUP_EVENT_CHOICES = [("proposed", "Proposed group"),
("started", "Started group"),
@ -48,6 +67,7 @@ class GroupEvent(models.Model):
# This will record the new state and the date it occurred for any changes
# to a group. The group acronym must be unique and is the invariant used
# to select group history from this table.
# FIXME: this class needs to be updated
class GroupHistory(models.Model):
group = models.ForeignKey('Group', related_name='group_history')
# Event related

View file

@ -1,3 +1,5 @@
from redesign.proxy_utils import TranslatingManager
from models import *
class Acronym(Group):
@ -47,8 +49,14 @@ class Area(Group):
#start_date = models.DateField(auto_now_add=True)
#concluded_date = models.DateField(null=True, blank=True)
#status = models.ForeignKey(AreaStatus)
@property
def status_id(self):
return { "active": 1, "dormant": 2, "conclude": 3 }[self.state_id]
#comments = models.TextField(blank=True)
#last_modified_date = models.DateField(auto_now=True)
@property
def last_modified_date(self):
return self.time.date()
#extra_email_addresses = models.TextField(blank=True,null=True)
#def additional_urls(self):
@ -68,8 +76,22 @@ class Area(Group):
class Meta:
proxy = True
def proxied_role_emails(emails):
for e in emails:
e.person.email = { 1: e }
return emails
class IETFWG(Group):
objects = TranslatingManager(dict(group_acronym="id",
group_acronym__acronym="acronym",
email_archive__startswith="list_archive__startswith",
group_type=lambda v: ("type", { 1: "wg" }[int(v)]),
status=lambda v: ("state", { 1: "active" }[int(v)]),
areagroup__area__status=lambda v: ("parent__state", { 1: "active" }[v]),
start_date__isnull=lambda v: None if v else ("groupevent__type", "started")
),
always_filter=dict(type="wg"))
ACTIVE=1
#group_acronym = models.OneToOneField(Acronym, primary_key=True, editable=False)
@property
@ -79,9 +101,17 @@ class IETFWG(Group):
#group_type = models.ForeignKey(WGType)
#proposed_date = models.DateField(null=True, blank=True)
#start_date = models.DateField(null=True, blank=True)
@property
def start_date(self):
e = self.latest_event(type="started")
return e.time.date() if e else None
#dormant_date = models.DateField(null=True, blank=True)
#concluded_date = models.DateField(null=True, blank=True)
#status = models.ForeignKey(WGStatus)
@property
def status_id(self):
return { "active": 1, "dormant": 2, "conclude": 3 }[self.state_id]
#area_director = models.ForeignKey(AreaDirector, null=True)
#meeting_scheduled = models.CharField(blank=True, max_length=3)
#email_address = models.CharField(blank=True, max_length=60)
@ -89,66 +119,79 @@ class IETFWG(Group):
def email_address(self):
return self.list_email
#email_subscribe = models.CharField(blank=True, max_length=120)
@property
def email_subscribe(self):
return self.list_subscribe
#email_keyword = models.CharField(blank=True, max_length=50)
#email_archive = models.CharField(blank=True, max_length=95)
@property
def email_archive(self):
return self.list_pages
return self.list_archive
#comments = models.TextField(blank=True)
#last_modified_date = models.DateField()
@property
def last_modified_date(self):
return self.time.date()
#meeting_scheduled_old = models.CharField(blank=True, max_length=3)
#area = FKAsOneToOne('areagroup', reverse=True)
@property
def area(self):
class AreaGroup: pass
if self.parent:
areagroup = AreaGroup()
areagroup.area = Area().from_object(self.parent)
return areagroup
else:
return None
def __str__(self):
return self.group_acronym.acronym
def __unicode__(self):
return self.group_acronym.acronym
# everything below here is not fixed yet
def active_drafts(self):
return self.group_acronym.internetdraft_set.all().filter(status__status="Active")
def choices():
return [(wg.group_acronym_id, wg.group_acronym.acronym) for wg in IETFWG.objects.all().filter(group_type__type='WG').select_related().order_by('acronym.acronym')]
choices = staticmethod(choices)
from redesign.doc.proxy import InternetDraft
return InternetDraft.objects.filter(group=self, state="active")
# def choices():
# return [(wg.group_acronym_id, wg.group_acronym.acronym) for wg in IETFWG.objects.all().filter(group_type__type='WG').select_related().order_by('acronym.acronym')]
# choices = staticmethod(choices)
def area_acronym(self):
areas = AreaGroup.objects.filter(group__exact=self.group_acronym)
if areas:
return areas[areas.count()-1].area.area_acronym
else:
return None
return Area().from_object(self.parent) if self.parent else None
def area_directors(self):
areas = AreaGroup.objects.filter(group__exact=self.group_acronym)
if areas:
return areas[areas.count()-1].area.areadirector_set.all()
else:
if not self.parent:
return None
return proxied_role_emails(sorted(Email.objects.filter(role__group=self.parent, role__name="ad"), key=lambda e: e.person.name_parts()[3]))
def chairs(self): # return a set of WGChair objects for this work group
return WGChair.objects.filter(group_acronym__exact=self.group_acronym)
def secretaries(self): # return a set of WGSecretary objects for this group
return WGSecretary.objects.filter(group_acronym__exact=self.group_acronym)
def milestones(self): # return a set of GoalMilestone objects for this group
return GoalMilestone.objects.filter(group_acronym__exact=self.group_acronym)
def rfcs(self): # return a set of Rfc objects for this group
return Rfc.objects.filter(group_acronym__exact=self.group_acronym)
def drafts(self): # return a set of Rfc objects for this group
return InternetDraft.objects.filter(group__exact=self.group_acronym)
return proxied_role_emails(sorted(Email.objects.filter(role__group=self, role__name="chair"), key=lambda e: e.person.name_parts()[3]))
# def secretaries(self): # return a set of WGSecretary objects for this group
# return WGSecretary.objects.filter(group_acronym__exact=self.group_acronym)
# def milestones(self): # return a set of GoalMilestone objects for this group
# return GoalMilestone.objects.filter(group_acronym__exact=self.group_acronym)
# def rfcs(self): # return a set of Rfc objects for this group
# return Rfc.objects.filter(group_acronym__exact=self.group_acronym)
# def drafts(self): # return a set of Rfc objects for this group
# return InternetDraft.objects.filter(group__exact=self.group_acronym)
def charter_text(self): # return string containing WG description read from file
# get file path from settings. Syntesize file name from path, acronym, and suffix
try:
filename = os.path.join(settings.IETFWG_DESCRIPTIONS_PATH, self.group_acronym.acronym) + ".desc.txt"
filename = os.path.join(settings.IETFWG_DESCRIPTIONS_PATH, self.acronym) + ".desc.txt"
desc_file = open(filename)
desc = desc_file.read()
except BaseException:
desc = 'Error Loading Work Group Description'
desc = 'Error Loading Work Group Description'
return desc
def additional_urls(self):
return AreaWGURL.objects.filter(name=self.group_acronym.acronym)
return self.groupurl_set.all().order_by("name")
def clean_email_archive(self):
x = self.email_archive
# remove "current/" and "maillist.html"
x = re.sub("^(http://www\.ietf\.org/mail-archive/web/)([^/]+/)(current/)?([a-z]+\.html)?$", "\\1\\2", x)
return x
return self.list_archive
def wgchair_set(self):
# gross hack ...
class Dummy: pass
d = Dummy()
d.all = self.chairs()
return d
class Meta:
proxy = True

View file

@ -1,6 +1,6 @@
#!/usr/bin/python
import sys, os
import sys, os, datetime
basedir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
sys.path = [ basedir ] + sys.path
@ -15,9 +15,10 @@ management.setup_environ(settings)
from redesign.group.models import *
from redesign.name.models import *
from redesign.name.utils import name
from ietf.idtracker.models import AreaGroup, IETFWG, Area, AreaGroup, Acronym, AreaWGURL, IRTF, ChairsHistory, Role
from redesign.importing.utils import old_person_to_person
from ietf.idtracker.models import AreaGroup, IETFWG, Area, AreaGroup, Acronym, AreaWGURL, IRTF, ChairsHistory, Role, AreaDirector
# imports IETFWG, Area, AreaGroup, Acronym, IRTF
# imports IETFWG, Area, AreaGroup, Acronym, IRTF, AreaWGURL
# also creates nomcom groups
@ -67,8 +68,6 @@ system = Person.objects.get(name="(System)")
# NomCom
#Group.objects.filter(acronym__startswith="nomcom").exclude(acronym="nomcom").delete()
for o in ChairsHistory.objects.filter(chair_type=Role.NOMCOM_CHAIR).order_by("start_year"):
print "importing ChairsHistory/Nomcom", o.pk, "nomcom%s" % o.start_year
group, _ = Group.objects.get_or_create(acronym="nomcom%s" % o.start_year)
@ -83,6 +82,8 @@ for o in ChairsHistory.objects.filter(chair_type=Role.NOMCOM_CHAIR).order_by("st
group.save()
# we need start/end year so fudge events
group.groupevent_set.all().delete()
e = GroupEvent(group=group, type="started")
e.time = datetime.datetime(o.start_year, 5, 1, 12, 0, 0)
e.by = system
@ -104,7 +105,9 @@ for o in Area.objects.all():
except Group.DoesNotExist:
group = Group(acronym=o.area_acronym.acronym)
group.id = o.area_acronym_id # transfer id
if o.last_modified_date:
group.time = datetime.datetime.combine(o.last_modified_date, datetime.time(12, 0, 0))
group.name = o.area_acronym.name
if o.status.status == "Active":
s = state_names["active"]
@ -119,6 +122,11 @@ for o in Area.objects.all():
group.save()
for u in o.additional_urls():
url, _ = GroupURL.objects.get_or_create(group=group, url=u.url)
url.name = u.description.strip()
url.save()
# import events
group.groupevent_set.all().delete()
@ -129,7 +137,7 @@ for o in Area.objects.all():
e.desc = e.get_type_display()
e.save()
# FIXME: missing fields from old: last_modified_date, extra_email_addresses
# FIXME: missing fields from old: extra_email_addresses
# IRTF
@ -162,6 +170,8 @@ for o in IETFWG.objects.all().order_by("pk"):
group = Group(acronym=o.group_acronym.acronym)
group.id = o.group_acronym_id # transfer id
if o.last_modified_date:
group.time = datetime.datetime.combine(o.last_modified_date, datetime.time(12, 0, 0))
group.name = o.group_acronym.name
# state
if o.group_type.type == "BOF":
@ -208,30 +218,57 @@ for o in IETFWG.objects.all().order_by("pk"):
elif not group.parent:
print "no area/parent for", group.acronym, group.name, group.type, group.state
try:
area_director = o.area_director
except AreaDirector.DoesNotExist:
area_director = None
if area_director and not area_director.area_id:
area_director = None # fake TBD guy
group.ad = old_person_to_person(area_director.person) if area_director else None
group.list_email = o.email_address if o.email_address else ""
l = o.email_archive.strip() if o.email_archive else ""
group.list_subscribe = (o.email_subscribe or "").replace("//listinfo", "/listinfo").strip()
l = o.clean_email_archive().strip() if o.email_archive else ""
if l in ("none", "not available"):
l = ""
group.list_pages = l
group.list_archive = l
group.comments = o.comments.strip() if o.comments else ""
group.save()
for u in o.additional_urls():
url, _ = GroupURL.objects.get_or_create(group=group, url=u.url)
url.name = u.description.strip()
url.save()
for m in o.milestones():
desc = m.description.strip()
try:
milestone = GroupMilestone.objects.get(group=group, desc=desc)
except GroupMilestone.DoesNotExist:
milestone = GroupMilestone(group=group, desc=desc)
milestone.expected_due_date = m.expected_due_date
milestone.done = m.done == "Done"
milestone.done_date = m.done_date
milestone.time = datetime.datetime.combine(m.last_modified_date, datetime.time(12, 0, 0))
milestone.save()
# import events
group.groupevent_set.all().delete()
def import_date_event(name):
def import_date_event(name, type_name):
d = getattr(o, "%s_date" % name)
if d:
e = GroupEvent(group=group, type=name)
e = GroupEvent(group=group, type=type_name)
e.time = datetime.datetime.combine(d, datetime.time(12, 0, 0))
e.by = system
e.desc = e.get_type_display()
e.save()
import_date_event("proposed")
import_date_event("start")
import_date_event("concluded")
import_date_event("proposed", "proposed")
import_date_event("start", "started")
import_date_event("concluded", "concluded")
# dormant_date is empty on all so don't bother with that
# FIXME: missing fields from old: meeting_scheduled, email_subscribe, email_keyword, last_modified_date, meeting_scheduled_old
# FIXME: missing fields from old: meeting_scheduled, email_keyword, meeting_scheduled_old

View file

@ -11,12 +11,17 @@ settings.USE_DB_REDESIGN_PROXY_CLASSES = False
from django.core import management
management.setup_environ(settings)
from ietf.idtracker.models import AreaDirector, IETFWG
from redesign.person.models import *
from redesign.importing.utils import get_or_create_email
# creates system person and email
# imports AreaDirector persons that are connected to an IETFWG
# should probably also import the old person/email tables
print "creating (System) person and email"
try:
system_person = Person.objects.get(name="(System)")
except Person.DoesNotExist:
@ -33,7 +38,6 @@ if system_person.id != 0: # work around bug in Django
Person.objects.filter(id=system_person.id).update(id=0)
system_person = Person.objects.get(id=0)
system_alias = Alias.objects.get_or_create(
person=system_person,
name=system_person.name
@ -41,6 +45,10 @@ system_alias = Alias.objects.get_or_create(
system_email = Email.objects.get_or_create(
address="",
person=system_person,
active=True
defaults=dict(active=True, person=system_person)
)
for o in AreaDirector.objects.filter(ietfwg__in=IETFWG.objects.all()).exclude(area_acronym=None).distinct().order_by("pk").iterator():
print "importing AreaDirector (from IETFWG) persons", o.pk
get_or_create_email(o, create_fake=False)

View file

@ -11,12 +11,12 @@ settings.USE_DB_REDESIGN_PROXY_CLASSES = False
from django.core import management
management.setup_environ(settings)
from redesign import unaccent
from redesign.person.models import *
from redesign.group.models import *
from redesign.name.models import *
from redesign.name.utils import name
from redesign.importing.utils import old_person_to_email, clean_email_address
from redesign.importing.utils import old_person_to_email, clean_email_address, get_or_create_email
from ietf.idtracker.models import IESGLogin, AreaDirector, IDAuthor, PersonOrOrgInfo, WGChair, WGEditor, WGSecretary, WGTechAdvisor, ChairsHistory, Role as OldRole, Acronym, IRTFChair
@ -41,36 +41,6 @@ editor_role = name(RoleName, "editor", "Editor")
secretary_role = name(RoleName, "secr", "Secretary")
techadvisor_role = name(RoleName, "techadv", "Tech Advisor")
# helpers for creating the objects
def get_or_create_email(o, create_fake):
email = old_person_to_email(o.person)
if not email:
if create_fake:
email = u"unknown-email-%s-%s" % (o.person.first_name, o.person.last_name)
print ("USING FAKE EMAIL %s for %s %s %s" % (email, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
else:
print ("NO EMAIL FOR %s %s %s %s %s" % (o.__class__, o.pk, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
return None
e, _ = Email.objects.select_related("person").get_or_create(address=email)
if not e.person:
n = u"%s %s" % (o.person.first_name, o.person.last_name)
asciified = unaccent.asciify(n)
aliases = Alias.objects.filter(name__in=(n, asciified))
if aliases:
p = aliases[0].person
else:
p = Person.objects.create(id=o.person.pk, name=n, ascii=asciified)
# FIXME: fill in address?
Alias.objects.create(name=n, person=p)
if asciified != n:
Alias.objects.create(name=asciified, person=p)
e.person = p
e.save()
return e
# WGEditor
for o in WGEditor.objects.all():

View file

@ -1,4 +1,5 @@
from person.models import Person
from redesign import unaccent
from redesign.person.models import Person, Email, Alias
def clean_email_address(addr):
addr = addr.replace("!", "@").replace("(at)", "@") # some obvious @ replacements
@ -16,4 +17,34 @@ def old_person_to_email(person):
hardcoded_emails = { 'Dinara Suleymanova': "dinaras@ietf.org" }
return clean_email_address(person.email()[1] or hardcoded_emails.get("%s %s" % (person.first_name, person.last_name)) or "")
def get_or_create_email(o, create_fake):
# take person on o and get or create new Email and Person objects
email = old_person_to_email(o.person)
if not email:
if create_fake:
email = u"unknown-email-%s-%s" % (o.person.first_name, o.person.last_name)
print ("USING FAKE EMAIL %s for %s %s %s" % (email, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
else:
print ("NO EMAIL FOR %s %s %s %s %s" % (o.__class__, o.pk, o.person.pk, o.person.first_name, o.person.last_name)).encode('utf-8')
return None
e, _ = Email.objects.select_related("person").get_or_create(address=email)
if not e.person:
n = u"%s %s" % (o.person.first_name, o.person.last_name)
asciified = unaccent.asciify(n)
aliases = Alias.objects.filter(name__in=(n, asciified))
if aliases:
p = aliases[0].person
else:
p = Person.objects.create(id=o.person.pk, name=n, ascii=asciified)
# FIXME: fill in address?
Alias.objects.create(name=n, person=p)
if asciified != n:
Alias.objects.create(name=asciified, person=p)
e.person = p
e.save()
return e

View file

@ -2,10 +2,11 @@ from redesign.proxy_utils import TranslatingManager
from models import *
class IDStatus(DocStateName):
def __init__(self, base):
def from_object(self, base):
for f in base._meta.fields:
setattr(self, f.name, getattr(base, f.name))
return self
#status_id = models.AutoField(primary_key=True)
#status = models.CharField(max_length=25, db_column='status_value')
@ -18,3 +19,98 @@ class IDStatus(DocStateName):
class Meta:
proxy = True
class IDState(IesgDocStateName):
PUBLICATION_REQUESTED = 10
LAST_CALL_REQUESTED = 15
IN_LAST_CALL = 16
WAITING_FOR_WRITEUP = 18
WAITING_FOR_AD_GO_AHEAD = 19
IESG_EVALUATION = 20
IESG_EVALUATION_DEFER = 21
APPROVED_ANNOUNCEMENT_SENT = 30
AD_WATCHING = 42
DEAD = 99
DO_NOT_PUBLISH_STATES = (33, 34)
objects = TranslatingManager(dict(pk="order"))
def from_object(self, base):
for f in base._meta.fields:
setattr(self, f.name, getattr(base, f.name))
return self
#document_state_id = models.AutoField(primary_key=True)
@property
def document_state_id(self):
return self.order
#state = models.CharField(max_length=50, db_column='document_state_val')
@property
def state(self):
return self.name
#equiv_group_flag = models.IntegerField(null=True, blank=True) # unused
#description = models.TextField(blank=True, db_column='document_desc')
@property
def description(self):
return self.desc
@property
def nextstate(self):
# simulate related queryset
from name.models import get_next_iesg_states
return IDState.objects.filter(pk__in=[x.pk for x in get_next_iesg_states(self)])
@property
def next_state(self):
# simulate IDNextState
return self
def __str__(self):
return self.state
@staticmethod
def choices():
return [(state.slug, state.name) for state in IDState.objects.all()]
class Meta:
proxy = True
class IDSubStateManager(TranslatingManager):
def __init__(self, *args):
super(IDSubStateManager, self).__init__(*args)
def all(self):
return self.filter(slug__in=['extpty', 'need-rev', 'ad-f-up', 'point'])
class IDSubState(DocInfoTagName):
objects = IDSubStateManager(dict(pk="order"))
def from_object(self, base):
for f in base._meta.fields:
setattr(self, f.name, getattr(base, f.name))
return self
#sub_state_id = models.AutoField(primary_key=True)
@property
def sub_state_id(self):
return self.order
#sub_state = models.CharField(max_length=55, db_column='sub_state_val')
@property
def sub_state(self):
return self.name
#description = models.TextField(blank=True, db_column='sub_state_desc')
@property
def description(self):
return self.desc
def __str__(self):
return self.sub_state
class Meta:
proxy = True

View file

@ -44,6 +44,14 @@ class Person(models.Model):
else:
prefix, first, middle, last, suffix = self.ascii_parts()
return (first and first[0]+"." or "")+(middle or "")+" "+last+(suffix and " "+suffix or "")
def role_email(self, role_name, group):
e = Email.objects.filter(person=self, role__group=group, role__name=role_name)
if e:
return e[0]
e = self.email_set.order("-active")
if e:
return e[0]
return None
def email_address(self):
e = self.email_set.filter(active=True)
if e:

View file

@ -150,13 +150,16 @@ class TranslatingManager(Manager):
hand side can either be a string or a function which is called
with the right-hand side to transform it."""
def __init__(self, trans):
def __init__(self, trans, always_filter=None):
super(TranslatingManager, self).__init__()
self.translated_attrs = trans
self.always_filter = always_filter
def get_query_set(self):
qs = TranslatingQuerySet(self.model)
qs.translated_attrs = self.translated_attrs
if self.always_filter:
qs = qs.filter(**self.always_filter)
return qs
# def dates(self, *args, **kwargs):