Merge changes from attic/shimfree into new branch to complete rebasing shimfree on trunk

- Legacy-Id: 6215
This commit is contained in:
Ole Laursen 2013-09-20 09:48:58 +00:00
commit 019ca2ae03
76 changed files with 942 additions and 2814 deletions

View file

@ -9,7 +9,7 @@ trap 'echo "$program($LINENO): Command failed with error code $? ($0 $*)"; exit
if [ "$*" ]; then apps="$@"; graph="${1%.*}"; else apps=$(ls */models.py | sed 's!/models.py!!'); graph="models"; fi
newapps="doc group meeting message person name"
legacyapps="announcements idindex idrfc idtracker iesg ietfauth ietfworkflows ipr liaisons mailinglists proceedings redirects submit wgchairs wgcharter wginfo"
legacyapps="announcements idindex idrfc idtracker iesg ietfauth ietfworkflows ipr liaisons mailinglists proceedings redirects submit wgcharter wginfo"
proxy="$(grep ^class */proxy.py | tr '()' ' ' | awk '{printf $2 ","}')"
names="$(grep ^class name/models.py | tr '()' ' ' | awk '{printf $2 ","}')"

View file

@ -194,11 +194,6 @@ class InternetDraft(Document):
def authors(self):
return IDAuthor.objects.filter(document=self)
@property
def protowriteup_set(self):
from ietf.wgchairs.models import ProtoWriteUpProxy
return ProtoWriteUpProxy.objects.filter(doc=self, type="changed_protocol_writeup")
# methods from InternetDraft
def displayname(self):
return self.name

View file

@ -9,6 +9,7 @@ from django.template.defaultfilters import linebreaksbr, wordwrap, stringfilter,
from django.template import resolve_variable
from django.utils.safestring import mark_safe, SafeData
from django.utils import simplejson
from django.utils.html import strip_tags
try:
from email import utils as emailutils
except ImportError:
@ -475,6 +476,14 @@ def state(doc, slug):
slug = "%s-stream-%s" % (doc.type_id, doc.stream_id)
return doc.get_state(slug)
@register.filter
def statehelp(state):
"Output help icon with tooltip for state."
from django.core.urlresolvers import reverse as urlreverse
tooltip = escape(strip_tags(state.desc))
url = urlreverse("state_help", kwargs=dict(type=state.type_id)) + "#" + state.slug
return mark_safe('<a class="state-help-icon" href="%s" title="%s">?</a>' % (url, tooltip))
def _test():
import doctest
doctest.testmod()
@ -483,11 +492,10 @@ if __name__ == "__main__":
_test()
@register.filter
def plural(text, list, arg=u's'):
def plural(text, seq, arg=u's'):
"Similar to pluralize, but looks at the text, too"
from django.template.defaultfilters import pluralize
if text.endswith('s'):
return text
else:
return text + pluralize(len(list), arg)
return text + pluralize(len(seq), arg)

View file

@ -3,12 +3,14 @@ from django.shortcuts import render_to_response, get_object_or_404
from django.template import RequestContext
from ietf.doc.models import *
from ietf.doc.utils import get_tags_for_stream_id
def state_help(request, type):
slug, title = {
"draft-iesg": ("draft-iesg", "IESG States For Internet-Drafts"),
"draft-rfceditor": ("draft-rfceditor", "RFC Editor States For Internet-Drafts"),
"draft-iana-action": ("draft-iana-action", "IANA Action States For Internet-Drafts"),
"draft-stream-ietf": ("draft-stream-ietf", "IETF Stream States For Internet-Drafts"),
"charter": ("charter", "Charter States"),
"conflict-review": ("conflrev", "Conflict Review States"),
"status-change": ("statchg", "RFC Status Change States"),
@ -35,6 +37,9 @@ def state_help(request, type):
states.insert(0, fake_state)
tags = DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS)
elif state_type.slug.startswith("draft-stream-"):
possible = get_tags_for_stream_id(state_type.slug.replace("draft-stream-", ""))
tags = DocTagName.objects.filter(slug__in=possible)
return render_to_response("doc/state_help.html", {
"title": title,
@ -42,5 +47,4 @@ def state_help(request, type):
"states": states,
"has_next_states": has_next_states,
"tags": tags,
},
context_instance=RequestContext(request))
}, context_instance=RequestContext(request))

View file

@ -94,6 +94,19 @@ def proxied_role_emails(emails):
proxy_role_email(e)
return emails
class WGDelegateProxy(Role):
#person = models.ForeignKey(PersonOrOrgInfo) # same name
#wg = models.ForeignKey(IETFWG)
@property
def wg(self):
return self.group
def __unicode__(self):
return u"%s" % self.person
class Meta:
proxy = True
class IETFWG(Group):
objects = TranslatingManager(dict(group_acronym="id",
group_acronym__acronym="acronym",
@ -211,8 +224,7 @@ class IETFWG(Group):
return d
@property
def wgdelegate_set(self):
from ietf.wgchairs.models import WGDelegate
return WGDelegate.objects.filter(group=self, name="delegate")
return WGDelegateProxy.objects.filter(group=self, name="delegate")
class Meta:
proxy = True

View file

@ -7,7 +7,6 @@ from workflows.models import State
from workflows.utils import set_workflow_for_object
from ietf.idtracker.models import PersonOrOrgInfo, IETFWG, InternetDraft
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.models import Stream, StreamDelegate
from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_workflow_for_wg,
get_state_for_draft, get_state_by_name,
@ -33,7 +32,10 @@ class StreamDraftForm(forms.Form):
def __init__(self, *args, **kwargs):
self.draft = kwargs.pop('draft', None)
self.user = kwargs.pop('user', None)
self.person = get_person_for_user(self.user)
try:
self.person = self.user.get_profile()
except:
self.person = None
self.workflow = get_workflow_for_draft(self.draft)
self.message = {}
super(StreamDraftForm, self).__init__(*args, **kwargs)

View file

@ -5,8 +5,6 @@ from django.core.urlresolvers import reverse as urlreverse
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper
from ietf.ietfworkflows.utils import (get_workflow_for_draft,
get_state_for_draft)
from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document)
from ietf.ietfworkflows.streams import get_stream_from_wrapper
from ietf.ietfworkflows.models import Stream
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream,

View file

@ -5,8 +5,6 @@ from django.core.urlresolvers import reverse as urlreverse
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper
from ietf.ietfworkflows.utils import (get_workflow_for_draft,
get_state_for_draft)
from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document)
from ietf.ietfworkflows.streams import get_stream_from_wrapper
from ietf.ietfworkflows.models import Stream
from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream,

View file

@ -7,7 +7,6 @@ from ietf.secr.utils.group import current_nomcom
from ietf.message.models import Message
from ietf.ietfauth.decorators import has_role
from ietf.wgchairs.accounts import get_person_for_user
# ---------------------------------------------
# Globals
@ -180,7 +179,7 @@ class AnnounceForm(forms.ModelForm):
def save(self, *args, **kwargs):
user = kwargs.pop('user')
message = super(AnnounceForm, self).save(commit=False)
message.by = get_person_for_user(user)
message.by = user.get_profile()
if self.cleaned_data['to'] == 'Other...':
message.to = self.cleaned_data['to_custom']
if kwargs['commit']:

View file

@ -6,7 +6,6 @@ from django.template import RequestContext
from ietf.ietfauth.decorators import has_role
from ietf.utils.mail import send_mail_text
from ietf.wgchairs.accounts import get_person_for_user
from ietf.group.models import Group
from ietf.secr.utils.group import current_nomcom
from ietf.secr.utils.decorators import check_for_cancel
@ -111,4 +110,4 @@ def confirm(request):
'message': data,
'to': to},
RequestContext(request, {}),
)
)

View file

@ -176,7 +176,6 @@ INSTALLED_APPS = (
'ietf.wginfo',
'ietf.submit',
'ietf.ietfworkflows',
'ietf.wgchairs',
'ietf.wgcharter',
'ietf.sync',
'ietf.community',

View file

@ -25,7 +25,7 @@
{% if snapshot %}Snapshot of{% endif %}
{% if doc.get_state_slug != "approved" %}Proposed{% endif %}
Charter for "{{ group.name }}"
(<a {% if group.type.slug == "wg" %}href="{% url ietf.wginfo.views.wg_charter acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
(<a {% if group.type.slug == "wg" %}href="{% url ietf.wginfo.views.group_charter acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
</div>
<table id="metatable" width="100%">

View file

@ -24,7 +24,7 @@
{% for state in states %}
<tr id="{{ state.slug }}" class="{{ forloop.counter|divisibleby:2|yesno:"evenrow,oddrow" }}">
<td class="name">{{ state.name }}</td>
<td class="desc">{{ state.desc|linebreaksbr }}</td>
<td class="desc">{{ state.desc|safe|linebreaksbr }}</td>
{% if has_next_states %}
<td class="name">
{% for s in state.next_states.all %}

View file

@ -1,55 +0,0 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters wgchairs_tags %}
{% block title %}Change shepherd write-up for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
</p>
<h1>Updating write-up for {{ doc }}</h1>
<p>
Before you modify the shepherd write-up <strong>please revise the 'Doc Shepherd Follow-up Underway' annotation tag and set or reset it if appropriate</strong>.
</p>
<p>
Remember that you must provide a comment if you change the annotation tag state.
</p>
<form action="" method="POST">
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 50%;">
<table class="ietf-table" style="width: 100%;">
<tr><th>Doc Shepherd Follow-up Underway</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>
<input type="hidden" value="{{ form.get_writeup }}" name="writeup" />
<input type="hidden" value="confirm" name="confirm" />
<input type="checkbox" name="followup" id="followup_id" value="1"{% if followup %} checked="checked"{% endif %} />
<label for="followup_id">Doc Shepherd Follow-up Underway</label>
</td></tr><tr><td>
{{ form.comment }}
</td></tr>
</table>
<p>
<strong>Change write-up and ...</strong><br />
<input type="submit" name="modify_tag" value="Modify 'Doc Shepherd Follow-up Underway'" />
<input type="submit" name="change_writeup" value="Leave 'Doc Shepherd Follow-up Underway' untouched" /><br />
<a href="">Cancel, I don't want to do any change!</a>
</p>
</td><td style="width: 50%;">
<table class="ietf-table" style="width: 100%;">
<tr><th>New shepherd write-up</th></tr>
<tr style="vertical-align: top;"><td>{{ form.get_writeup|linebreaksbr }}</td></tr>
</table>
</td></tr></table>
</form>
{% endblock %}

View file

@ -1 +0,0 @@
{{ state.name }}

View file

@ -1,41 +0,0 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters %}
{% block title %}Change shepherd for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
<a href="{{ doc.get_absolute_url }}">Return to {{ doc }}</a>
</p>
<h1>Change shepherd for {{ doc }}</h1>
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 50%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Actual shepherd</th></tr>
<tr><td>{% if doc.shepherd %}{{ doc.shepherd }}{% else %}No shepherd assigned{% endif %}</td></tr>
</table>
<input type="hidden" name="update_shepherd" value="1" />
<input type="submit" name="remove_shepherd" value="Unassign shepherd" />
<input type="submit" name="setme" value="Set me as shepherd of this document" />
</form>
</td><td style="width: 50%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Change shepherd</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>{{ form.as_p }}</td></tr>
</table>
<input type="submit" name="change_shepherd" value="Change shepherd" />
{% if form.can_cancel %}<a href="">No! I don't want to continue</a>{% endif %}
</form>
</td></tr></table>
{% endblock %}

View file

@ -1,67 +0,0 @@
{% extends "wginfo/wg_base.html" %}
{% load ietf_filters wgchairs_tags %}
{% block title %} {% if can_edit %} Change {% else %} View {% endif %} shepherd write-up for {{ doc }}{% endblock %}
{% block wg_content %}
<p>
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Return to shepherd list</a>
</p>
<h1> {% if can_edit %} Change {% else %} View {% endif %} shepherd write-up for {{ doc }}</h1>
<table class="ietf-table" style="width: 100%;">
<tr><th>Draft state</th><th>Actual shepherd write-up</th><th>Last updated</th></tr>
<tr style="vertical-align: top;"><td>{% show_state doc %}</td><td>{{ writeup.writeup|linebreaksbr }}</td><td>{% if writeup %}{{ writeup.date }} by {{ writeup.person }}{% endif %}</td></tr>
</table>
<p>
Please, <strong>note</strong> that the <strong>'Doc Shepherd Follow-up Underway'</strong> annotation tag is {% if not followup %}<strong>NOT</strong>{% endif %} set for {{ doc }}.
</p>
{% if can_edit %}
<table style="width: 100%;"><tr style="vertical-align: top;"><td style="width: 75%;">
<form action="" method="POST">
<table class="ietf-table" style="width: 100%;">
<tr><th>Edit shepherd write-up</th></tr>
{% if form.message %}
<tr><td class="message message-{{ form.message.type }}">
{{ form.message.value }}
</td></tr>
{% endif %}
<tr><td>
<textarea name="writeup" style="border: 1px solid #cccccc; width: 100%; height: 15em;">{{ form.get_writeup }}</textarea></td></tr>
</table>
<input type="submit" name="change_writeup" value="Change write-up" />
</form>
</td><td style="width: 25%;">
<form action="" method="POST" enctype="multipart/form-data">
<table class="ietf-table" style="width: 100%;">
<tr><th>Upload a new shepherd write-up</th></tr>
<tr><td>
<p>Replace the current write-up with the contents of a plain ascii file:</p>
<input type="file" name="uploaded_writeup" /></td></tr>
</table>
<input type="submit" name="upload_writeup" value="Upload write-up" />
</form>
</td></tr></table>
{% else %}
{% if authorized_user %}
<table class="ietf-table" style="width: 100%;">
<tr><th>Edit shepherd write-up</th></tr>
<tr><td>
<p>
You can not edit or upload the shepherd write-up for {{ doc }} because the draft is not on "WG Consensus: Waiting for Write-Up" state.
</p>
<p>
Please contact with the {{ wg }} Working Group chair.
</p>
</td></tr>
</table>
{% endif %}
{% endif %}
{% endblock %}

View file

@ -1,60 +0,0 @@
{% extends "wginfo/wg_base.html" %}
{% block wg_titledetail %}Delegates{% endblock %}
{% block wg_content %}
<div class="wg-chair-management">
<h2>Manage delegates</h2>
<p>
Sometimes, a WG has one (or more) WG Secretaries, in addition to the WG Chairs.
This page lets the WG Chairs delegate the authority to do updates to the WG state of WG documents in the datatracker.
</p>
<p>
You may at most delegate the datatracker update rights to {{ max_delegates }} persons at any given time.
</p>
<table style="width: 100%;">
<tr style="vertical-align: top;"><td>
{% if delegates %}
<form action="" method="POST">
<table class="ietf-table" style="width: 100%">
<tr><th>Remove</th><th style="Width: 100%">Delegate name</th></tr>
{% for delegate in delegates %}
<tr class="{% cycle "oddrow" "evenrow" %}"><td><input type="checkbox" name="delete" value="{{ delegate.pk }}" /></td><td>{{ delegate.person }}</td></tr>
{% endfor %}
</table>
<input type="submit" value="Remove delegate(s)" name="remove" />
</form>
{% else %}
No delegates
{% endif %}
</td>
<td>
<table class="ietf-table" style="width: 100%;">
<tr><th>Add new delegate</th></tr>
{% if add_form.message %}
<tr><td class="message message-{{ add_form.message.type }}">
{{ add_form.message.value }}
</td></tr>
{% endif %}
<tr><td>
{% if can_add %}
<form action="" method="POST">
{{ add_form.as_p }}
<p>
<input type="submit" value="{% if add_form.submit_msg %}{{ add_form.submit_msg }}{% else %}Add delegate{% endif %}" name="add" />
{% if add_form.can_cancel %}<a href="">No! I don't want to continue</a>{% endif %}
</p>
</form>
{% else %}
You can only assign {{ max_delegates }} delegates. Please remove delegates to add a new one.
{% endif %}
</td></tr>
</table>
</td></tr>
</table>
</div>
{% endblock %}

View file

@ -1,165 +0,0 @@
{% extends "wginfo/wg_base.html" %}
{% block wg_titledetail %}Manage Workflow{% endblock %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block wg_content %}
<div class="wg-workflow-management">
<h2>Edit workflow</h2>
<div id="mytabs" class="yui-navset">
<ul class="yui-nav">
<li class="selected"><a href="#info"><em>Info</em></a></li>
<li><a href="#states"><em>Select states</em></a></li>
<li><a href="#transitions"><em>Edit transitions</em></a></li>
<li><a href="#tags"><em>Select Annotation Tags</em></a></li>
</ul>
<div class="yui-content">
<div id="info">
<table style="width: 100%;"><tr style="vertical-align: top;"><td>
<table class="ietf-table" style="width: 100%">
<tr>
<th>States used in {{ wg }} Working Group</th>
</tr>
{% for state in states %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>{{ state.name }}</td>
</tr>
{% endfor %}
</table><br />
<table class="ietf-table" style="width: 100%;">
<tr>
<th>Annotation tags used in {{ wg }} Working Group</th>
</tr>
{% for tag in tags %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>{{ tag.name }}</td>
</tr>
{% endfor %}
</table>
</td><td>
<table class="ietf-table" style="width: 100%;">
<tr>
<th>Transition name</th><th>Initial states</th><th>Destination state</th>
</tr>
{% for transition in workflow.transitions.all %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td>
{{ transition.name }}
</td>
<td>
{% for state in transition.states.all %}
{{state.name }}{% if not forloop.last %}<br />{% endif %}
{% endfor %}
</td>
<td>
{{ transition.destination.name }}
</td>
</tr>
{% endfor %}
{% if not workflow.transitions.all.count %}
<tr class="oddrow"><td colspan="3">There are no transitions defined so any state change is allowed</td></tr>
{% endif %}
</table>
</td></tr></table>
</div>
<div id="states">
<p>
Please note that the states you can not uncheck are needed in all IETF WGs.
</p>
<p>
You can see the default Working Group I-D State Diagram in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>
</p>
<form action="#info" method="POST">
<table class="ietf-table">
<tr>
<th>Used in {{ wg }}</th><th>Available states</th><th>Definition</th>
</tr>
{% for state in default_states %}
<tr class="{% cycle "oddrow" "evenrow" %}" style="vertical-align: top;">
<td><input type="checkbox" id="id_states_{{ state.pk }}" name="states" value="{{ state.pk }}" {% if state.used %}checked="checked" {% endif %}{% if state.freeze %} disabled="disabled"{% endif %}/></td>
<td><label for="id_states_{{ state.pk }}">{{ state.name }}</label></td>
<td>
<div class="statedefinition" style="height: 1em; overflow: hidden;">
<pre style="margin-top: 0px;"><a class="showDefinition" href="#">[+]</a><a class="hideDefinition" style="display: none;" href="#">[-]</a> {{ state.statedescription_set.all.0.definition|safe }}</pre>
</div>
</td>
</tr>
{% endfor %}
</table>
<input type="submit" name="update_states" value="Update states" />
</form>
</div>
<div id="transitions">
<p>
You can see the default Working Group I-D State Diagram in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>
</p>
<form action="#transitions" method="POST">
<table class="ietf-table">
<tr>
<th>Delete</th><th>Transition name</th><th>Initial states</th><th>Destination state</th>
</tr>
{{ formset.as_table }}
</table>
<input type="submit" name="update_transitions" value="Update transitions" />
</form>
</div>
<div id="tags">
<form action="#info" method="POST">
<table class="ietf-table">
<tr>
<th>Used in {{ wg }}</th><th>Available annotation tags</th>
</tr>
{% for tag in default_tags %}
<tr class="{% cycle "oddrow" "evenrow" %}">
<td><input type="checkbox" id="id_tags_{{ tag.pk }}" name="tags" value="{{ tag.pk }}" {% if tag.used %}checked="checked" {% endif %}/></td>
<td><label for="id_tags_{{ tag.pk }}">{{ tag.name }}</label></td>
</tr>
{% endfor %}
</table>
<input type="submit" name="update_tags" value="Update tags" />
</form>
</div>
</div>
</div>
<script type="text/javascript">
//<![CDATA[
var tabView = new YAHOO.widget.TabView('mytabs');
var url = location.href.split('#');
if (url[1]) {
url[1] = "#"+url[1];
var tabs = tabView.get('tabs');
for (var i = 0; i < tabs.length; i++) {
if (url[1].indexOf(tabs[i].get('href')) == 0) {
tabView.set('activeIndex', i);
break;
}
}
}
jQuery('.showDefinition').click(function() {
jQuery(this).parent().parent().css('height', 'auto');
jQuery(this).hide();
jQuery(this).next().show();
return false;
});
jQuery('.hideDefinition').click(function() {
jQuery(this).parent().parent().css('height', '1em');
jQuery(this).hide();
jQuery(this).prev().show();
return false;
});
//]]>
</script>
{% endblock %}

View file

@ -1,28 +0,0 @@
{% if shepherd %}
<p>
The shepherd you are trying to designate does not have a personal user-id and password to log-on to the Datatracker.
</p>
<p>
An email will be sent to the following addresses to inform that
the person you have designated to be one of your document shepherds
currently does not have login credentials for the Datatracker
and should contact the Secretariat to obtain their own user-id and
password for the Datatracker.
</p>
{% else %}
<p>
The delegate you are trying to designate does not have a personal user-id and password to log-on to the Datatracker.
</p>
<p>
An email will be sent to the following addresses to inform that
the person you have designated to be one of your delegates
currently does not have login credentials for the Datatracker
and should contact the Secretariat to obtain their own user-id and
password for the Datatracker.
</p>
{% endif %}
<ul>
{% for email in email_list %}
<li>{{ email }}</li>
{% endfor %}
</ul>

View file

@ -1,10 +0,0 @@
{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add you as a {{ wg }} {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
You don't have an user/password to log into the datatracker so you must contact
the Secretariat at iesg-secretary@ietf.org in order to get your credentials.
When you get your credentials, please inform {{ chair }} at
{{ chair.email.1 }} so he/she can finish the designate process.
Thank you.
{% endautoescape %}

View file

@ -1,15 +0,0 @@
{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email
{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
This person don't have an user/password to log into the datatracker so
an email has been seent to {{ delegate_email }} in order to he/she contacs the
Secretariat to request his/her credentials.
{% if delegate_persons %}
Please, note that the following persons with {{ delegate_email }} email address
already exists in the system but they can not log in.
{% for person in delegate_persons %}
{{ person.pk }} - {{ person }}
{% endfor %}
{% endif %}
{% endautoescape %}

View file

@ -1,12 +0,0 @@
{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email
{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
This person don't have an user/password to log into the datatracker so
an email has been seent to {{ delegate_email }} in order to he/she contacs the
Secretariat to request his/her credentials.
When he/she gets her credentials then he/she will send an email to
{{ chair }} at {{ chair.email.1 }}.
{{ chair }} could then assign this person as {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}.
{% endautoescape%}

View file

@ -1,17 +0,0 @@
{% load wgchairs_tags %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="title">
<a href="{% url doc_view doc.filename %}">{{ doc.title }}</a>
</td>
<td class="shepherd">
<a href="{% url doc_edit_shepherd doc %}">Change shepherd</a>
</td>
<td class="writeup">
{% writeup doc %}
<a href="{% url doc_edit_shepherd_writeup doc %}" style="display: block;" href="">[Edit]</a>
</td>
<td class="writeup_date">
{% writeupdate doc %}
</td>
</tr>

View file

@ -1,122 +0,0 @@
{% 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 %}
{% block wg_titledetail %}Documents{% endblock %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block wg_content %}
<h2>Documents by its shepherd</h2>
<div id="mytabs" class="yui-navset">
<ul class="yui-nav">
<li class="selected"><a href="#noshepherd"><em>Without shepherd</em></a></li>
<li><a href="#mydocs"><em>Shepherded by me</em></a></li>
<li><a href="#othershepherds"><em>Shepherded by others</em></a></li>
</ul>
<div class="yui-content">
<div id="noshepherd">
<table class="ietf-table ietf-doctable" style="margin-top:16px; width: 100%;">
<tr>
<th class="title">Document</th>
<th class="shepherd">Change shepherd</th>
<th class="writeup">Shepherd write-up</th>
<th class="writeup_date">Shepherd write-up last update</th>
</tr>
{% for doc in no_shepherd %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
</div>
<div id="mydocs">
<table class="ietf-table ietf-doctable" style="margin-top:16px; width: 100%;">
<tr>
<th class="title">Document</th>
<th class="status">Status</th>
<th class="writeup">Shepherd write-up</th>
<th class="writeup_date">Shepherd write-up last update</th>
</tr>
{% for doc in my_documents %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
</div>
<div id="othershepherds">
{% regroup other_shepherds by shepherd as regrouped %}
{% for documents in regrouped %}
<h3 style="margin-bottom: 0px;">{{ documents.grouper }}</h3>
<table class="ietf-table ietf-doctable" style="width: 100%;">
<tr>
<th class="title">Document</th>
<th class="status">Status</th>
<th class="writeup">Shepherd write-up</th>
<th class="writeup_date">Shepherd write-up last update</th>
</tr>
{% for doc in documents.list %}
{% include "wgchairs/shepherd_document_row.html" %}
{% endfor %}
</table>
{% endfor %}
</div>
<script type="text/javascript">
//<![CDATA[
var tabView = new YAHOO.widget.TabView('mytabs');
var url = location.href.split('#');
if (url[1]) {
url[1] = "#"+url[1];
var tabs = tabView.get('tabs');
for (var i = 0; i < tabs.length; i++) {
if (url[1].indexOf(tabs[i].get('href')) == 0) {
tabView.set('activeIndex', i);
break;
}
}
}
//]]>
</script>
{% endblock wg_content %}

View file

@ -1,23 +0,0 @@
{% if can_manage_workflow %}
{% ifequal selected "manage_workflow" %}
<span class="selected">Manage workflow</span>
{% else %}
<a href="{% url manage_workflow wg.group_acronym.acronym %}">Manage workflow</a>
{% endifequal %} |
{% endif %}
{% if can_manage_delegates %}
{% ifequal selected "manage_delegates" %}
<span class="selected">Manage delegations</span>
{% else %}
<a href="{% url manage_delegates wg.group_acronym.acronym %}">Manage delegations</a>
{% endifequal %} |
{% endif %}
{% if can_manage_shepherds %}
{% ifequal selected "manage_shepherds" %}
<span class="selected">Manage shepherds</span>
{% else %}
<a href="{% url manage_shepherds wg.group_acronym.acronym %}">Manage shepherds</a>
{% endifequal %} |
{% endif %}

View file

@ -1,4 +1,4 @@
{% load ietf_filters %}{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{{ wg }}
{% endif %}{% endif %}{% endfor %}
{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{% include "wginfo/wg-charter.txt" %}
{% endif %}{% endif %}{% endfor %}
{% autoescape off %}{% load ietf_filters %}{% for group in groups %}{{ group.acronym }}
{% endfor %}
{% for group in groups %}{% include "wginfo/group_entry_with_charter.txt" %}{% endfor %}{% endautoescape %}

View file

@ -1,7 +1,6 @@
{% load ietf_filters %}{% regroup wg_list|dictsort:"area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.name" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{{ wg }}
{% endif %}{% endif %}{% endfor %}{% endfor %}
{% autoescape off %}{% load ietf_filters %}{% for area in areas %}{% for group in area.groups %}{{ group.acronym }}
{% endfor %}{% endfor %}
{% for area in areas %}{% for group in area.groups %}{% include "wginfo/group_entry_with_charter.txt" %}{% endfor %}{% endfor %}{% endautoescape %}
{% regroup wg_list|dictsort:"area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.name" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}
{% include "wginfo/wg-charter.txt" %}
{% endif %}{% endif %}{% endfor %}{% endfor %}

View file

@ -1,10 +1,10 @@
{% load ietf_filters %}
{% autoescape off %}{% load ietf_filters %}
IETF Working Group Summary (By Acronym)
The following Area Abbreviations are used in this document
{% for area in area_list %}
{{ 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 }}
{% include "wginfo/wg_summary.txt" %}{% endif %}{% endfor %}
{% for area in areas %}
{{ area.acronym|upper }} - {{ area.name }}{% endfor %}
{% for group in groups %}
{{ group.name }} ({{ group.acronym }}) -- {{ group.parent.acronym|upper }}
{% include "wginfo/group_entry.txt" %}{% endfor %}{% endautoescape %}

View file

@ -1,8 +1,11 @@
{% load ietf_filters %} IETF Working Group Summary (By Area)
{% regroup wg_list|dictsort:"area.area.area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.acronym" %}{% ifequal wg.area.area.status_id 1 %}{% if forloop.first %}
{{ wg.area_acronym.name }} ({{ wg.area_acronym }})
{{ wg.area_acronym.name|dashify }}------{% for ad in wg.area_directors %}
{{ ad.person }} <{{ ad.person.email.1 }}>{% endfor %}
{% endif %}{% if wg.start_date %}
{{ wg.group_acronym.name|safe }} ({{ wg }})
{% include "wginfo/wg_summary.txt" %}{% endif %}{% endifequal %}{% endfor %}{% endfor %}
{% autoescape off %}{% load ietf_filters %}
IETF Working Group Summary (By Area)
{% for area in areas %}{{ area.name }} ({{ area.acronym }})
{{ area.name|dashify }}------{% for ad in area.ads %}
{{ ad.person }} <{{ ad.address }}>{% endfor %}
{% for group in area.groups %}{{ group.name }} ({{ group.acronym }})
{% include "wginfo/group_entry.txt" %}
{% endfor %}{% endfor %}{% endautoescape %}

View file

@ -25,7 +25,7 @@
{% for g in groups %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="acronym">
<a href="{% url wg_charter acronym=g.acronym %}">{{ g.acronym }}</a>
<a href="{% url group_charter acronym=g.acronym %}">{{ g.acronym }}</a>
</td>
<td class="title">
<a {%comment%}href="{% url doc_view name=g.charter.name %}"{%endcomment%}>{{ g.name }}</a>

View file

@ -28,7 +28,7 @@
{% for g in groups %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="acronym">
<a href="{% url wg_charter acronym=g.acronym %}">{{ g.acronym }}</a>
<a href="{% url group_charter acronym=g.acronym %}">{{ g.acronym }}</a>
</td>
<td class="title">
<a href="{% url doc_view name=g.charter.name %}">{{ g.name }}</a>

View file

@ -28,7 +28,7 @@ form.conclude .actions {
{{ form.as_table }}
<tr>
<td colspan="2" class="actions">
<a href="{% url wg_charter acronym=wg.acronym %}">Back</a>
<a href="{% url group_charter acronym=wg.acronym %}">Back</a>
<input type="submit" value="Send request"/>
</td>
</tr>

View file

@ -1,65 +1,45 @@
{% extends "wginfo/wg_base.html" %}
{% extends "base.html" %}
{% block wg_titledetail %}Manage Workflow{% endblock %}
{% block pagehead %}
{{ block.super }}
<script type="text/javascript" src="/js/lib/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="/js/yui/yui-20100305.js"></script>
<script type="text/javascript" src="/js/base.js"></script>
{% endblock pagehead %}
{% block title %}Customize Workflow for {{ group.acronym }} {{ group.type.name }}{% endblock %}
{% block morecss %}
{{ block.super }}
.state-table .inactive,
.tag-table .inactive {
font-style: italic;
color: #666;
}
.state-table .state {
padding-right: 0.6em;
}
.set-next-states {
margin-top: 1em;
}
.set-next-states label {
display: block;
cursor: pointer;
}
.set-next-states label input {
vertical-align: middle;
}
.set-state input, .set-tag input {
width: 6em;
}
.toggled {
display: none;
}
.toggler {
color: #000;
.tag-table .inactive { font-style: italic; color: #666; }
.state-table .state { margin-bottom: 0.1em; }
.state-table .set-next-states label { display: block; cursor: pointer; }
.state-table .set-next-states label input { vertical-align: middle; }
.state-table .set-state input, .set-tag input { width: 6em; }
.state-table .toggled { display: none; }
.state-table .toggler {
color: #444;
background: #ddd;
font-weight: bold;
text-decoration: none;
padding: 0px 3px;
padding: 1px 3px;
display: inline-block;
margin-left: 0.5em;
font-size: 15px;
font-weight: bold;
}
.inactive .toggler {
color: #666;
}
.toggler:hover {
background-color: #999;
color: #fff;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.state-table .inactive .toggler { color: #aaa; background: #eee; }
.state-table .toggler:hover { color: #fff; background-color: #999; }
{% endblock %}
{% block wg_content %}
<div class="wg-workflow-management">
<h2>Edit workflow</h2>
{% block content %}
{% load ietf_filters %}
<p>Below you can customize the draft states and tags used in the {{ wg.acronym }} WG. Note that some states are mandatory for WG operation and cannot be deactivated.</p>
<div class="group-customize-workflow">
<h1>Customize Workflow for {{ group.acronym }} {{ group.type.name }}</h1>
<p>Below you can customize the draft states and tags used in the
<a href="{% url group_charter group.acronym %}">{{ group.acronym }} {{ group.type.name }}</a>. Note that some states are
mandatory for group operation and cannot be deactivated.</p>
<p>You can see the default Working Group I-D State Diagram
in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>.</p>
<p>You can see the default Working Group I-D State Diagram in <a href="http://tools.ietf.org/html/rfc6174#section-4.1">Section 4.1 of RFC6174</a>.</p>
<h3>States</h3>
@ -90,20 +70,16 @@
{% endif %}
</td>
<td>
<div>
<span>{{ state.name }} {% if not state.used %} (not used in {{ wg.acronym }}){% endif %}</span>
<a class="toggler" title="Click to show description of state" href="">+</a>
</div>
<div class="toggled">{{ state.desc|safe|linebreaks }}</div>
{{ state.name }} {% if not state.used %} (not used in {{ group.acronym }}){% endif %} {{ state|statehelp }}
</td>
<td>
<div>
{% if state.used_next_states %}
{% for n in state.used_next_states %}<span class="state">{{ n.name }}</span>{% if not forloop.last %} {% endif %}{% endfor %}
{% for n in state.used_next_states %}<div class="state">{{ n.name }}</div>{% endfor %}
{% else %}
<i>None</i>
<div><i>None</i></div>
{% endif %}
<a class="toggler" title="Click to set next states for state" href="">+</a>
<a class="toggler" title="Click to set next states for state" href="">+ customize</a>
</div>
<form class="toggled set-next-states" method="post" action="">
Select the next states:
@ -142,11 +118,14 @@
<input type="hidden" name="action" value="settagactive" />
</form>
</td>
<td><span>{{ tag.name }} {% if not tag.used %} (not used in {{ wg.acronym }}){% endif %}</span></td>
<td><span>{{ tag.name }} {% if not tag.used %} (not used in {{ group.acronym }}){% endif %}</span></td>
</tr>
{% endfor %}
</table>
{% endblock content %}
{% block js %}
<script type="text/javascript">
//<![CDATA[
jQuery('.state-table .toggler').click(function(e) {
@ -154,15 +133,14 @@ jQuery('.state-table .toggler').click(function(e) {
var toggler = jQuery(this),
toggled = toggler.parent().siblings(".toggled");
if (toggled.is(":hidden")) {
toggler.html("&ndash;");
toggler.html("&ndash; customize");
toggled.slideDown(300);
}
else {
toggler.html("+");
toggler.html("+ customize");
toggled.slideUp(300);
}
});
//]]>
</script>
{% endblock %}

View file

@ -9,6 +9,7 @@ Start chartering new WG
{% endblock %}
{% block morecss %}
form.edit td { padding-bottom: .5em; }
form.edit #id_name,
form.edit #id_list_email,
form.edit #id_list_subscribe,
@ -16,8 +17,7 @@ form.edit #id_list_archive,
form.edit #id_urls,
form.edit #id_comments { width: 400px; }
form.edit input[type=checkbox] { vertical-align: middle; }
ul.errorlist { border-width: 0px; padding: 0px; margin: 0px;}
ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; }
form.edit #id_urls { height: 4em; }
{% endblock %}
{% block pagehead %}
@ -27,28 +27,30 @@ ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; }
{% block content %}
{% load ietf_filters %}
<h1>
{% ifequal action "edit" %}
{% if action == "edit" %}
Edit WG {{ wg.acronym }}
{% else %}
{% ifequal action "charter" %}
{% if action == "charter" %}
Start chartering new WG
{% else %}
Create new WG or BoF
{% endifequal %}
{% endifequal %}
{% endif %}
{% endif %}
</h1>
<p>Note that persons with authorization to manage information, e.g.
chairs and delegates, need a Datatracker account to actually do
so. New accounts can be <a href="{% url create_account %}">created here</a>.</p>
<form class="edit" action="" method="POST">
<table>
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}: {% if field.field.required %}*{% endif %}</th>
<td>{{ field }}
{% ifequal field.name "ad" %}
{% if user|has_role:"Area Director" %}
{% if field.name == "ad" and user|has_role:"Area Director" %}
<label><input type="checkbox" name="ad" value="{{ login.pk }}" /> Assign to me</label>
{% endif %}
{% endifequal %}
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
{{ field.errors }}
</td>
@ -65,16 +67,16 @@ Create new WG or BoF
<tr>
<td></td>
<td class="actions">
{% ifequal action "edit" %}
<a href="{% url wg_charter acronym=wg.acronym %}">Back</a>
<input type="submit" value="Save"/>
{% if action == "edit" %}
<a class="button" href="{% url group_charter acronym=wg.acronym %}">Cancel</a>
<input class="button" type="submit" value="Save"/>
{% else %}
{% ifequal action "charter" %}
{% if action == "charter" %}
<input type="submit" value="Start chartering"/>
{% else %}
<input type="submit" value="Create group or bof"/>
{% endifequal %}
{% endifequal %}
{% endif %}
{% endif %}
</td>
</tr>
</table>

View file

@ -42,7 +42,7 @@ tr.milestone.add { font-style: italic; }
<noscript>This page depends on Javascript being enabled to work properly.</noscript>
<p>Links:
<a href="{% url wg_charter acronym=group.acronym %}">{{ group.acronym }} {{ group.type.name }}</a>
<a href="{% url group_charter acronym=group.acronym %}">{{ group.acronym }} {{ group.type.name }}</a>
- <a href="{% url doc_view name=group.charter.canonical_name %}">{{ group.charter.canonical_name }}</a>
</p>
@ -91,7 +91,7 @@ this list</a> to the milestones currently in use for the {{ group.acronym }} {{
</table>
<div class="actions">
<a class="button" href="{% if milestone_set == "charter" %}{% url doc_view name=group.charter.canonical_name %}{% else %}{% url wg_charter acronym=group.acronym %}{% endif %}">Cancel</a>
<a class="button" href="{% if milestone_set == "charter" %}{% url doc_view name=group.charter.canonical_name %}{% else %}{% url group_charter acronym=group.acronym %}{% endif %}">Cancel</a>
<input class="button" type="submit" data-labelsave="Save" data-labelreview="Review changes" value="Save" style="display:none"/>
<input type="hidden" name="action" value="save">
</div>

View file

@ -32,8 +32,8 @@ 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 wgchairs_tags %}
{% block title %}{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}) - {% block wg_titledetail %}{% endblock %}{% endblock %}
{% load ietf_filters %}
{% block title %}{{ group.name }} ({{ group.acronym }}) - {% block group_subtitle %}{% endblock %}{% endblock %}
{% block morecss %}
.ietf-navset {
@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.ietf-navset .selected { font-weight:bold; padding: 0 3px; }
.ietf-navset a, .ietf-navset a:visited { color: white; padding:0 3px; }
.ietf-wg-details { float:right; padding: 4px;margin-top:16px; margin-left: 16px; }
.ietf-wg-details tr { vertical-align: top; }
.ietf-group-details { float:right; padding: 4px;margin-top:16px; margin-left: 16px; }
.ietf-group-details tr { vertical-align: top; }
.ietf-concluded-bg {background-color: #F8F8D0; }
.ietf-concluded-warning { background:red;color:white;padding:2px 2px;}
.ietf-proposed-bg { }
@ -62,22 +62,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% endblock morecss %}
{% block content %}
<div {% if concluded %}class="ietf-concluded-bg"{% endif %} {% if proposed %}class="ietf-proposed-bg"{% endif %}>
<h1>{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}){% if concluded %}<br/><span class="ietf-concluded-warning">(concluded WG)</span>{% endif %}{% if proposed %}<br/><span class="ietf-proposed-warning">(proposed WG)</span>{% endif %}</h1>
<div {% if group.state_id == "dormant" or group.state_id == "conclude" %}class="ietf-concluded-bg"{% endif %} {% if group.state_id == "proposed" %}class="ietf-proposed-bg"{% endif %}>
<h1>{{ group.name}} ({{ group.acronym }})
{% if group.state_id == "dormant" or group.state_id == "conclude" %}<br/><span class="ietf-concluded-warning">(concluded {{ group.type.name }})</span>{% endif %}
{% if group.state_id == "proposed" %}<br/><span class="ietf-proposed-warning">(proposed {{ group.type.name }})</span>{% endif %}
</h1>
<div class="ietf-navset">
{% ifequal selected "documents" %}<span class="selected">Documents</span>{% else %}<a href="{% url ietf.wginfo.views.wg_documents_html acronym=wg.group_acronym.acronym %}">Documents</a>{% endifequal %} |
{% ifequal selected "charter" %}<span class="selected">Charter</span>{% else %}<a href="{% url ietf.wginfo.views.wg_charter acronym=wg.group_acronym.acronym %}">Charter</a>{% endifequal %} |
{% wgchairs_admin_options wg %}
<a {% if selected == "history" %}class="selected"{% else %}href="{% url ietf.wginfo.views.history acronym=wg.group_acronym.acronym %}"{% endif %}>History</a> |
{% if wg.clean_email_archive|startswith:"http:" or wg.clean_email_archive|startswith:"https:" or wg.clean_email_archive|startswith:"ftp:" %}
<a href="{{ wg.clean_email_archive }}">List Archive &#187;</a> |
{% endif %}
<a href="http://tools.ietf.org/wg/{{ wg.group_acronym.acronym }}/">Tools WG Page &#187;</a>
<a {% if selected == "documents" %}class="selected"{% else %}href="{% url ietf.wginfo.views.group_documents acronym=group.acronym %}"{% endif %}>Documents</a> |
<a {% if selected == "charter" %}class="selected"{% else %}href="{% url ietf.wginfo.views.group_charter acronym=group.acronym %}"{% endif %}>Charter</a> |
<a {% if selected == "history" %}class="selected"{% else %}href="{% url ietf.wginfo.views.history acronym=group.acronym %}"{% endif %}>History</a> |
{% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %}
<a href="{{ group.list_archive }}">List Archive &raquo;</a> |
{% endif %}
<a href="http://tools.ietf.org/wg/{{ group.acronym }}/">Tools WG Page &raquo;</a>
</div>
{% block wg_content %}
{% endblock wg_content %}
{% block group_content %}
{% endblock group_content %}
</div>
{% endblock content %}

View file

@ -0,0 +1,182 @@
{% extends "wginfo/group_base.html" %}
{% load ietf_filters %}
{% block group_subtitle %}Charter{% endblock %}
{% block morecss %}
{{ block.super }}
h2 a.button { margin-left: 0.5em; font-size: 13px; }
{% endblock %}
{% block group_content %}
<div class="ietf-box ietf-group-details">
{% if group.state_id == "conclude" %}
<span class="ietf-concluded-warning">Note: The data for concluded WGs
is occasionally incorrect.</span>
{% endif %}
<table>
<tr><th colspan="2">Group</th></tr>
<tr valign="top">
<td style="width:14ex;">Name:</td>
<td>{{ group.name }}</td>
</tr>
<tr><td>Acronym:</td><td>{{ group.acronym }}</td></tr>
{% if group.parent %}
<tr><td>{{ group.parent.type.name }}:</td><td>{{ group.parent.name }} ({{ group.parent.acronym }})</td></tr>
{% endif %}
<tr>
<td>State:</td>
<td>{{ group.state.name }}
{% if requested_close %}
(but in the process of being closed)
{% endif %}
</td>
</tr>
<tr>
<td>Charter:</td>
<td>
{% if group.charter %}
<a href="{% url doc_view name=group.charter.name %}">{{ group.charter.name }}-{{ group.charter.rev }}</a> ({{ group.charter.get_state.name }})
{% else %}
none
{% if user|has_role:"Area Director,Secretariat" %}
- <a href="{% url ietf.wginfo.edit.submit_initial_charter acronym=group.acronym %}">Submit Charter</a>
{% endif %}
{% endif %}
</td>
</tr>
<tr><th colspan="2">Personnel</th></tr>
<tr valign="top">
<td>Chair{{ group.chairs|pluralize }}:</td>
<td>
{% for chair in group.chairs %}
<a href="mailto:{{ chair.address }}">{{ chair.person.plain_name }} &lt;{{ chair.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
<tr><td>Area Director:</td>
<td>
{% if group.areadirector %}
<a href="mailto:{{ group.areadirector.address }}">{{ group.areadirector.person.plain_name }} &lt;{{ group.areadirector.address }}&gt;</a>
{% else %}?{% endif %}
</td>
</tr>
{% if group.techadvisors %}
<tr>
<td>Tech Advisor{{ group.techadvisors|pluralize }}:</td>
<td>
{% for techadvisor in group.techadvisors %}
<a href="mailto:{{ techadvisor.address }}">{{ techadvisor.person.plain_name }} &lt;{{ techadvisor.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
{% endif %}
{% if group.editors %}
<tr>
<td>Editor{{ group.editors|pluralize }}:</td>
<td>
{% for editor in group.editors %}
<a href="mailto:{{ editor.address }}">{{ editor.person.plain_name }} &lt;{{ editor.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
{% endif %}
{% if group.secretaries %}
<tr>
<td>Secretar{{ group.secretaries|pluralize:"y,ies" }}:</td>
<td>
{% for secretary in group.secretaries %}
<a href="mailto:{{ secretary.address }}">{{ secretary.person.plain_name }} &lt;{{ secretary.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
{% endif %}
{% if group.delegates %}
<tr>
<td>Delegate{{ group.delegates|pluralize }}:</td>
<td>
{% for delegate in group.delegates %}
<a href="mailto:{{ delegate.address }}">{{ delegate.person.plain_name }} &lt;{{ delegate.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
{% endif %}
<tr><th colspan="2">Mailing List</th></tr>
<tr><td>Address:</td><td>{{ group.list_email|urlize }}</td></tr>
<tr><td>To Subscribe:</td><td>{{ group.list_subscribe|urlize }}</td></tr>
<tr><td>Archive:</td><td>{{ group.list_archive|urlize }}</td></tr>
{% if group.state_id != "conclude" %}
<tr><th colspan="2">Jabber Chat</th></tr>
<tr>
<td>Room Address:</td>
<td><a href="xmpp:{{ group.acronym }}@jabber.ietf.org">xmpp:{{ group.acronym }}@jabber.ietf.org</a></td>
</tr>
<tr>
<td>Logs:</td>
<td><a href="http://jabber.ietf.org/logs/{{ group.acronym }}/">http://jabber.ietf.org/logs/{{ group.acronym }}/</a></td>
</tr>
{% endif %}
</table>
{% if user|has_role:"Area Director,Secretariat" %}
<div style="margin: 2px; margin-top: 2em;">
{% for name, url in actions %}
<a href="{{ url }}">{{ name }}</a> {% if not forloop.last %} | {% endif %}
{% endfor %}
</div>
{% endif %}
</div>
{% with group.groupurl_set.all as urls %}
{% if 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 urls %}
<a href="{{ url.url }}">{{ url.name }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
{% endwith %}
<h2>Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} Working Group</h2>
<p>{{ group.charter_text|escape|format_charter|safe }}</p>
<h2>{% if group.state_id == "proposed" %}Proposed{% endif %} Milestones
{% if group.state_id != "proposed" %}
{% if user|has_role:"Area Director,Secretariat" or is_chair %}
<a class="button" href="{% url wg_edit_milestones acronym=group.acronym %}">Add or edit milestones</a>
{% endif %}
{% endif %}
</h2>
{% with group.milestones as milestones %}
{% include "wginfo/milestones.html" %}
{% endwith %}
{% if milestones_in_review %}
<p>+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }}
currently in Area Director review.</p>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,18 @@
{% extends "wginfo/group_base.html" %}
{% block group_subtitle %}Documents{% endblock %}
{% block group_content %}
<div class="group-documents">
{% include "doc/search/search_results.html" %}
{% with docs_related as docs %}{% with meta_related as meta %}{% include "doc/search/search_results.html" %}{% endwith %}{% endwith %}
</div>
{% endblock group_content %}
{% block js %}
<script type="text/javascript" src="/js/utils.js"></script>
<script type="text/javascript" src="/js/doc-search.js"></script>
{% endblock %}

View file

@ -0,0 +1,4 @@
{% for chair in group.chairs %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person.plain_name }} <{{ chair.address }}>
{% endfor %} WG Mail: {{ group.list_email }}
To Join: {{ group.list_subscribe }}
Archive: {{ group.list_archive }}

View file

@ -0,0 +1,48 @@
{% autoescape off %}{% load ietf_filters %}{{ group.name }} ({{group.acronym}})
{{ group.name|dashify }}{{ group.acronym|dashify }}---
Charter
Last Modified: {{ group.time.date|date }}
Current Status: {{ group.state.name }}
Chair{{ group.chairs|pluralize }}:
{% for chair in group.chairs %} {{ chair.person.name }} <{{chair.address}}>
{% endfor %}
{{ group.area.name}} Directors:
{% for ad in group.area.ads %} {{ ad.person.plain_name }} <{{ ad }}>
{% endfor %}
{% if group.areadirector %} {{ group.area.name }} Advisor:
{{ group.areadirector.person.plain_name }} <{{ group.areadirector.address }}>
{% endif %}{% if group.techadvisors %}
Tech Advisor{{ group.techadvisors|pluralize }}:
{% for techadvisor in group.techadvisors %} {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
{% endfor %}{% endif %}{% if group.editors %}
Editor{{ group.editors|pluralize }}:
{% for editor in group.editors %} {{ editor.person.plain_name }} <{{ editor.address}}>
{% endfor %}{% endif %}{% if group.secretaries %}
Secretar{{ group.secretaries|pluralize:"y,ies" }}:
{% for secretary in group.secretaries %} {{ secretary.person.plain_name }} <{{ secretary.address }}>
{% endfor %}{% endif %}
Mailing Lists:
General Discussion: {{ group.list_email }}
To Subscribe: {{ group.list_subscribe }}
Archive: {{ group.list_archive }}
Description of Working Group:
{{ group.charter_text|indent }}
Goals and Milestones:
{% for milestone in group.milestones %} {% if milestone.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc }}
{% endfor %}
Internet-Drafts:
{% for alias in group.drafts %} - {{ alias.document.title }} [{{ alias.name }}-{{ alias.document.rev }}] ({{ alias.document.pages }} pages)
{% endfor %}
{% if group.rfcs %}Requests for Comments:
{% for alias in group.rfcs %} {{ alias.name.upper }}: {{ alias.document.title}} ({{ alias.document.pages }} pages){% for r in alias.rel %}
* {{ r.action }} {{ r.target.name|upper }}{% endfor %}{% for r in alias.invrel %}
* {% if r.relationsship == "obs" %}{{ r.inverse_action|upper }}{% else %}{{ r.action }}{% endif %} {{ r.source.canonical_name|upper }}{% endfor %}
{% endfor %}
{% else %}No Requests for Comments{% endif %}
{% endautoescape %}

View file

@ -1,15 +1,16 @@
{% extends "wginfo/wg_base.html" %}
{% extends "wginfo/group_base.html" %}
{% load ietf_filters %}
{% block wg_titledetail %}History{% endblock %}
{% block group_subtitle %}History{% endblock %}
{% block wg_content %}
{% block group_content %}
{% load ietf_filters %}
<h2>WG History</h2>
<h2>Group History</h2>
<table class="ietf-table history">
<tr><th>Date</th><th>By</th><th>Text</th></tr>
{% for e in events %}
<tr class="{% cycle oddrow,evenrow %}">
<td>{{ e.time|date:"Y-m-d"}}</td>

View file

@ -1,47 +0,0 @@
{% 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
Last Modified: {{ wg.last_modified_date }}
Current Status: {{ wg.status }}
Chair{{ wg.chairs.count|pluralize:",s" }}:
{% for chair in wg.chairs %} {{ chair.person|safe }} <{{chair.person.email.1}}>
{% 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.area_director.person|safe }} <{{wg.area_director.person.email.1}}>
{% if wg.wgtechadvisor_set.count %}
Tech Advisor{{ wg.wgtechadvisor_set.count|pluralize:",s" }}:
{% for techadvisor in wg.wgtechadvisor_set.all %} {{ techadvisor.person|safe }} <{{techadvisor.person.email.1}}>
{% endfor %}{% endif %}{% if wg.wgeditor_set.count %}
Editor{{ wg.wgeditor_set.count|pluralize:",s" }}:
{% for editor in wg.wgeditor_set.all %} {{ editor.person|safe }} <{{editor.person.email.1}}>
{% endfor %}{% endif %}{% if wg.secretaries %}
Secretar{{ wg.secretaries.count|pluralize:"y,ies" }}:
{% for secretary in wg.secretaries %} {{ secretary.person|safe }} <{{secretary.person.email.1}}>
{% 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 %} {% ifequal milestone.done 'Done' %}Done {% else %}{%ifequal milestone.expected_due_date.month 1 %}Jan{% endifequal %}{%ifequal milestone.expected_due_date.month 2 %}Feb{% endifequal %}{%ifequal milestone.expected_due_date.month 3 %}Mar{% endifequal %}{%ifequal milestone.expected_due_date.month 4 %}Apr{% endifequal %}{%ifequal milestone.expected_due_date.month 5 %}May{% endifequal %}{%ifequal milestone.expected_due_date.month 6 %}Jun{% endifequal %}{%ifequal milestone.expected_due_date.month 7 %}Jul{% endifequal %}{%ifequal milestone.expected_due_date.month 8 %}Aug{% endifequal %}{%ifequal milestone.expected_due_date.month 9 %}Sep{% endifequal %}{%ifequal milestone.expected_due_date.month 10 %}Oct{% endifequal %}{%ifequal milestone.expected_due_date.month 11 %}Nov{% endifequal %}{%ifequal milestone.expected_due_date.month 12 %}Dec{% endifequal %} {{ milestone.expected_due_date.year }}{% endifequal %} - {{ milestone.description|safe }}
{% endfor %}
Internet-Drafts:
{% for draft in wg.drafts %} - {{draft.title|safe}} [{{draft.filename}}-{{draft.revision}}] ({{ draft.txt_page_count }} pages)
{% endfor %}
{% if wg.rfcs %}Requests for Comments:
{% for rfc in wg.rfcs %} {{rfc}}: {{rfc.title|safe}} ({{ rfc.txt_page_count }} pages){% for obs in rfc.obsoletes%}
* {{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 %}{% endif %}

View file

@ -1,47 +0,0 @@
{% 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.address}}>
{% 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.plain_name|safe }} <{{techadvisor.address}}>
{% endfor %}{% endif %}{% if wg.editors %}
Editor{{ wg.editors|pluralize }}:
{% for editor in wg.editors %} {{ editor.person.plain_name|safe }} <{{editor.address}}>
{% endfor %}{% endif %}{% if wg.secretaries %}
Secretar{{ wg.secretaries|pluralize:"y,ies" }}:
{% for secretary in wg.secretaries %} {{ secretary.person.plain_name|safe }} <{{secretary.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.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|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

@ -1,99 +0,0 @@
{% 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|dictsort:"area_acronym.name" %}
<h2 class="ietf-divider" id="{{area.area_acronym.name|cut:" "}}">{{ area.area_acronym.name }}</h2>
{% for ad in area.areadirector_set.all|dictsort:"person.last_name" %}
{% if forloop.first %}
<p>Area Director{{ forloop.revcounter|pluralize }}:</p>
<table style="margin-left: 2em" class="ietf-wg-table">
{% endif %}
<tr><td><span class="square bgcolor{{forloop.counter}}">&nbsp;</span></td> <td><a href="mailto:{{ ad.person.email.1 }}">{{ ad.person }} &lt;{{ ad.person.email.1 }}&gt;</a></td></tr>
{% if forloop.last %}
</table>
{% endif %}
{% endfor %}
{% for url in area.additional_urls %}
{% if forloop.first %}
<p>Area Specific Web Page{{ forloop.revcounter|pluralize}}:</p>
<p style="margin-left: 2em">
{% endif %}
<a href="{{url.url}}">{{ url.description }}</a>{% if not forloop.last %}<br/>{% endif %}
{% if forloop.last %}
</p>
{% endif %}
{% endfor %}
{% for wg in area.active_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}}/">{{ wg }}</a></td>
<td width="1%">{% for ad in area.areadirector_set.all|dictsort:"person.last_name" %}{% ifequal ad wg.area_director %}<span title="AD for {{wg}}: {{ad.person}}" class="square bgcolor{{forloop.counter}}"></span>{% endifequal %}{% endfor %}</td>
<td width="50%">{{ wg.group_acronym.name }}</td>
<td width="39%">{% for chair in wg.chairs %}<a href="mailto:{{chair.person.email.1}}">{{chair.person}}</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

@ -1,182 +0,0 @@
{% 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 morecss %}
{{ block.super }}
h2 a.button { margin-left: 0.5em; font-size: 13px; }
{% 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><th colspan="2">Group</th></tr>
<tr valign="top">
<td style="width:14ex;">Name:</td>
<td>{{ wg.name }}</td>
</tr>
<tr><td>Acronym:</td><td>{{ wg.acronym }}</td></tr>
{% if wg.parent %}
<tr><td>Area:</td><td>{{ wg.parent.name }} ({{ wg.parent.acronym }})</td></tr>
{% endif %}
<tr>
<td>State:</td>
<td>{{ wg.state.name }}
{% if requested_close %}
(but in the process of being closed)
{% endif %}
</td>
</tr>
<tr>
<td>Charter:</td>
<td>
{% if wg.charter %}
<a href="{% url doc_view name=wg.charter.name %}">{{ wg.charter.name }}-{{ wg.charter.rev }}</a> ({{ wg.charter.get_state.name }})
{% else %}
none
{% if user|has_role:"Area Director,Secretariat" %}
- <a href="{% url ietf.wginfo.edit.submit_initial_charter acronym=wg.acronym %}">Submit Charter</a>
{% endif %}
{% endif %}
</td>
</tr>
<tr><th colspan="2">Personnel</th></tr>
<tr valign="top">
<td>Chair{{ wg.chairs|pluralize }}:</td>
<td>
{% for chair in wg.chairs %}
<a href="mailto:{{ chair.address }}">{{ chair.person.plain_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.areadirector.address }}">{{ wg.ad.plain_name }} &lt;{{ wg.areadirector.address }}&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.plain_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.plain_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.plain_name }} &lt;{{ secretary.address }}&gt;</a><br/>
{% endfor %}
</td>
</tr>
{% endif %}
<tr><th colspan="2">Mailing List</th></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><th colspan="2">Jabber Chat</th></tr>
<tr><td>Room Address:</td><td><a href="xmpp:{{ wg.acronym }}@jabber.ietf.org">xmpp:{{ wg.acronym }}@jabber.ietf.org</a></td></tr>
<tr><td>Logs:</td><td><a href="http://jabber.ietf.org/logs/{{ wg.acronym }}/">http://jabber.ietf.org/logs/{{ wg.acronym }}/</a></td></tr>
{% endif %}
</table>
{% if user|has_role:"Area Director,Secretariat" %}
<div style="margin: 2px; margin-top: 2em;">
{% for name, url in actions %}
<a href="{{ url }}">{{ name }}</a>
{% if not forloop.last %}|{% endif %}
{% endfor %}
</div>
{% endif %}
</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.name }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
<h2>Charter for {% if wg.state_id == "proposed" %}Proposed{% endif %} Working Group</h2>
<p>{{ wg.charter_text|escape|format_charter|safe }}</p>
<h2>{% if wg.state_id == "proposed" %}Proposed{% endif %} Milestones
{% if wg.state_id != "proposed" %}
{% if user|has_role:"Area Director,Secretariat" or is_chair %}
<a class="button" href="{% url wg_edit_milestones acronym=wg.acronym %}">Add or edit milestones</a>
{% endif %}
{% endif %}
</h2>
{% with wg.milestones as milestones %}{% include "wginfo/milestones.html" %}{% endwith %}
{% if milestones_in_review %}
<p>+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }}
currently in Area Director review.</p>
{% endif %}
{% endblock wg_content %}

View file

@ -1,50 +0,0 @@
{% 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 %}
{% block wg_titledetail %}Documents{% endblock %}
{% block wg_content %}
<div class="group-documents">
{% include "doc/search/search_results.html" %}
{% with docs_related as docs %}{% include "doc/search/search_results.html" %}{% endwith %}
</div>
{% endblock wg_content %}
{% block js %}
<script type="text/javascript" src="/js/utils.js"></script>
<script type="text/javascript" src="/js/doc-search.js"></script>
{% endblock %}

View file

@ -1,2 +0,0 @@
{% load ietf_filters %}{% regroup docs by get_state as grouped_docs %}{% for doc_group in grouped_docs %}{% for doc in doc_group.list %}{% include "wginfo/wg_documents_entry.txt" %}{% endfor %}{% endfor %}{% regroup docs_related by get_state as grouped_docs_related %}{% for doc_group in grouped_docs_related %}{% for doc in doc_group.list %}Related {% include "wginfo/wg_documents_entry.txt" %}{% endfor %}{% endfor %}

View file

@ -1 +0,0 @@
{% load ietf_filters %}{{doc_group.grouper}} {% if doc.get_state_slug == "rfc" %}{{doc.rfc_number}} {{doc.title|clean_whitespace}}{% else %}{{doc.name}}-{{doc.rev}} {{doc.title|clean_whitespace}}{% endif %}

View file

@ -1,5 +0,0 @@
{% 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

@ -1 +0,0 @@
/*.pyc

View file

@ -1,18 +0,0 @@
# coding: latin-1
from types import ModuleType
import urls, models, views, forms, accounts
# These people will be sent a stack trace if there's an uncaught exception in
# code any of the modules imported above:
DEBUG_EMAILS = [
('Emilio A. Sánchez', 'esanchez@yaco.es'),
]
for k in locals().keys():
m = locals()[k]
if isinstance(m, ModuleType):
if hasattr(m, "DEBUG_EMAILS"):
DEBUG_EMAILS += list(getattr(m, "DEBUG_EMAILS"))
setattr(m, "DEBUG_EMAILS", DEBUG_EMAILS)

View file

@ -1,108 +0,0 @@
from django.conf import settings
from ietf.group.models import Role
def is_secretariat(user):
if not user or not user.is_authenticated():
return False
return bool(user.groups.filter(name='Secretariat'))
def is_area_director_for_group(person, group):
return bool(group.area.area.areadirector_set.filter(person=person).count())
def is_area_director_for_groupREDESIGN(person, group):
return bool(Role.objects.filter(group=group.parent, person=person, name__in=("ad", "pre-ad")))
def is_group_chair(person, group):
if group.chairs().filter(person=person):
return True
return False
def is_group_chairREDESIGN(person, group):
return bool(Role.objects.filter(group=group, person=person, name="chair"))
def is_group_delegate(person, group):
return bool(group.wgdelegate_set.filter(person=person).count())
def is_group_delegateREDESIGN(person, group):
return bool(Role.objects.filter(group=group, person=person, name="delegate"))
def get_person_for_user(user):
try:
return user.get_profile().person()
except:
return None
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.liaisons.accounts import is_secretariat, get_person_for_user
is_area_director_for_group = is_area_director_for_groupREDESIGN
is_group_chair = is_group_chairREDESIGN
is_group_delegate = is_group_delegateREDESIGN
def can_do_wg_workflow_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_do_wg_workflow_in_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return (is_secretariat(user) or can_do_wg_workflow_in_group(document.group.ietfwg))
def can_manage_workflow_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_delegates_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_shepherds_in_group(user, group):
person = get_person_for_user(user)
if not person:
return False
return (is_secretariat(user) or is_group_chair(person, group))
def can_manage_shepherd_of_a_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return can_manage_shepherds_in_group(user, document.group.ietfwg)
def can_manage_writeup_of_a_document_no_state(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
group = document.group.ietfwg
return (is_secretariat(user) or
is_group_chair(person, group) or
is_area_director_for_group(person, group) or
is_group_delegate(person, group))
def can_manage_writeup_of_a_document(user, document):
person = get_person_for_user(user)
if not person or not document.group:
return False
return (can_manage_writeup_of_a_document_no_state(user, document) or
person == document.shepherd)

View file

@ -1,478 +0,0 @@
import datetime
from django import forms
from django.conf import settings
from django.db.models import Q
from django.forms.models import BaseModelFormSet
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from ietf.wgchairs.models import WGDelegate, ProtoWriteUp
from ietf.wgchairs.accounts import get_person_for_user
from ietf.ietfworkflows.constants import REQUIRED_STATES
from ietf.ietfworkflows.utils import (get_default_workflow_for_wg, get_workflow_for_wg,
update_tags, FOLLOWUP_TAG, get_state_by_name)
from ietf.ietfworkflows.models import AnnotationTag, State
from ietf.idtracker.models import PersonOrOrgInfo
from ietf.utils.mail import send_mail_text
from workflows.models import Transition
from ietf.doc.models import WriteupDocEvent
from ietf.person.models import Person, Email
from ietf.group.models import Group, Role, RoleName
from ietf.group.utils import save_group_in_history
from ietf.name.models import DocTagName
class RelatedWGForm(forms.Form):
can_cancel = False
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
self.message = {}
super(RelatedWGForm, self).__init__(*args, **kwargs)
def get_message(self):
return self.message
def set_message(self, msg_type, msg_value):
self.message = {'type': msg_type,
'value': msg_value,
}
class TagForm(RelatedWGForm):
tags = forms.ModelMultipleChoiceField(AnnotationTag.objects.filter(workflow__name='Default WG Workflow'),
widget=forms.CheckboxSelectMultiple, required=False)
def save(self):
workflow = get_workflow_for_wg(self.wg)
workflow.selected_tags.clear()
for tag in self.cleaned_data['tags']:
workflow.selected_tags.add(tag)
return workflow
class StateForm(RelatedWGForm):
states = forms.ModelMultipleChoiceField(State.objects.filter(workflow__name='Default WG Workflow'),
widget=forms.CheckboxSelectMultiple, required=False)
def update_transitions(self, workflow):
for transition in workflow.transitions.all():
if not workflow.selected_states.filter(pk=transition.destination.pk).count():
transition.delete()
continue
for state in transition.states.all():
if not workflow.selected_states.filter(pk=state.pk).count():
transition.states.remove(state)
if not transition.states.count():
transition.delete()
continue
def save(self):
workflow = get_workflow_for_wg(self.wg)
workflow.selected_states.clear()
for state in self.cleaned_data['states']:
workflow.selected_states.add(state)
for name in REQUIRED_STATES:
rstate = get_state_by_name(name)
if rstate:
workflow.selected_states.add(rstate)
self.update_transitions(workflow)
return workflow
class DeleteTransitionForm(RelatedWGForm):
transitions = forms.ModelMultipleChoiceField(Transition.objects.all(),
widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
super(DeleteTransitionForm, self).__init__(*args, **kwargs)
workflow = get_workflow_for_wg(self.wg)
self.fields['transitions'].queryset = self.fields['transitions'].queryset.filter(workflow=workflow)
def save(self):
for transition in self.cleaned_data['transitions']:
transition.delete()
class TransitionForm(forms.ModelForm):
states = forms.ModelMultipleChoiceField(State.objects.filter(workflow__name='Default WG Workflow'))
class Meta:
model = Transition
fields = ('name', 'states', 'destination', )
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
super(TransitionForm, self).__init__(*args, **kwargs)
workflow = get_workflow_for_wg(self.wg)
self.fields['states'].queryset = workflow.selected_states.all()
self.fields['destination'].queryset = workflow.selected_states.all()
self.fields['destination'].required = True
if self.instance.pk:
self.fields['states'].initial = [i.pk for i in self.instance.states.all()]
self.instance.workflow = workflow
def as_row(self):
return self._html_output(u'<td>%(errors)s%(field)s%(help_text)s</td>', u'<td colspan="2">%s</td>', '</td>', u'<br />%s', False)
def save(self, *args, **kwargs):
instance = super(TransitionForm, self).save(*args, **kwargs)
for state in self.cleaned_data['states']:
state.transitions.add(instance)
class TransitionFormSet(BaseModelFormSet):
form = TransitionForm
can_delete = True
extra = 2
max_num = 0
can_order = False
model = Transition
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.user = kwargs.pop('user', None)
super(TransitionFormSet, self).__init__(*args, **kwargs)
def _construct_form(self, i, **kwargs):
kwargs = kwargs or {}
kwargs.update({'wg': self.wg, 'user': self.user})
return super(TransitionFormSet, self)._construct_form(i, **kwargs)
def as_table(self):
html = u''
csscl = 'oddrow'
for form in self.forms:
html += u'<tr class="%s">' % csscl
html += form.as_row()
html += u'</tr>'
if csscl == 'oddrow':
csscl = 'evenrow'
else:
csscl = 'oddrow'
return mark_safe(u'\n'.join([unicode(self.management_form), html]))
def workflow_form_factory(request, wg, user):
if request.POST.get('update_transitions', None):
return TransitionFormSet(wg=wg, user=user, data=request.POST)
elif request.POST.get('update_states', None):
return StateForm(wg=wg, user=user, data=request.POST)
return TagForm(wg=wg, user=user, data=request.POST)
class RemoveDelegateForm(RelatedWGForm):
delete = forms.MultipleChoiceField()
def __init__(self, *args, **kwargs):
super(RemoveDelegateForm, self).__init__(*args, **kwargs)
self.fields['delete'].choices = [(i.pk, i.pk) for i in self.wg.wgdelegate_set.all()]
def save(self):
delegates = self.cleaned_data.get('delete')
save_group_in_history(Group.objects.get(pk=self.wg.pk))
WGDelegate.objects.filter(pk__in=delegates).delete()
self.set_message('success', 'Delegates removed')
def assign_shepherd(user, internetdraft, shepherd):
if internetdraft.shepherd == shepherd:
return
from ietf.doc.models import save_document_in_history, DocEvent, Document
# saving the proxy object is a bit of a mess, so convert it to a
# proper document
doc = Document.objects.get(name=internetdraft.name)
save_document_in_history(doc)
doc.time = datetime.datetime.now()
doc.shepherd = shepherd
doc.save()
e = DocEvent(type="changed_document")
e.time = doc.time
e.doc = doc
e.by = user.get_profile()
if not shepherd:
e.desc = u"Unassigned shepherd"
else:
e.desc = u"Changed shepherd to %s" % shepherd.plain_name()
e.save()
# update proxy too
internetdraft.shepherd = shepherd
class AddDelegateForm(RelatedWGForm):
email = forms.EmailField()
form_type = forms.CharField(widget=forms.HiddenInput, initial='single')
def __init__(self, *args, **kwargs):
self.shepherd = kwargs.pop('shepherd', False)
super(AddDelegateForm, self).__init__(*args, **kwargs)
self.next_form = self
def get_next_form(self):
return self.next_form
def get_person(self, email):
persons = PersonOrOrgInfo.objects.filter(emailaddress__address=email).filter(
Q(iesglogin__isnull=False)|
Q(legacywgpassword__isnull=False)|
Q(legacyliaisonuser__isnull=False)).distinct()
if not persons:
raise PersonOrOrgInfo.DoesNotExist
if len(persons) > 1:
raise PersonOrOrgInfo.MultipleObjectsReturned
return persons[0]
def save(self):
email = self.cleaned_data.get('email')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
try:
person = Person.objects.filter(email__address=email).exclude(user=None).distinct().get()
except Person.DoesNotExist:
self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system')
return
except Person.MultipleObjectsReturned:
self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('multiple', 'There are multiple users with this email in the system')
return
else:
try:
person = self.get_person(email)
except PersonOrOrgInfo.DoesNotExist:
self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system')
return
except PersonOrOrgInfo.MultipleObjectsReturned:
self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd)
self.next_form.set_message('multiple', 'There are multiple users with this email in the system')
return
if self.shepherd:
self.assign_shepherd(person)
else:
self.create_delegate(person)
def assign_shepherd(self, person):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
assign_shepherd(self.user, self.shepherd, person)
else:
self.shepherd.shepherd = person
self.shepherd.save()
self.next_form = AddDelegateForm(wg=self.wg, user=self.user, shepherd=self.shepherd)
self.next_form.set_message('success', 'Shepherd assigned successfully')
def create_delegate(self, person):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
created = False
e = Email.objects.get(address=self.cleaned_data.get('email'))
if not Role.objects.filter(name="delegate", group=self.wg, person=person, email=e):
created = True
save_group_in_history(Group.objects.get(pk=self.wg.pk))
delegate, _ = Role.objects.get_or_create(
name=RoleName.objects.get(slug="delegate"), group=self.wg, person=e.person, email=e)
else:
(delegate, created) = WGDelegate.objects.get_or_create(wg=self.wg,
person=person)
if not created:
self.set_message('error', 'The email belongs to a person who is already a delegate')
else:
self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
self.next_form.set_message('success', 'A new delegate has been added')
class MultipleDelegateForm(AddDelegateForm):
email = forms.EmailField(widget=forms.HiddenInput)
form_type = forms.CharField(widget=forms.HiddenInput, initial='multiple')
persons = forms.ChoiceField(widget=forms.RadioSelect, help_text='Please select one person from the list')
submit_msg = 'Designate as delegate'
def __init__(self, *args, **kwargs):
self.email = kwargs.pop('email', None)
super(MultipleDelegateForm, self).__init__(*args, **kwargs)
if not self.email:
self.email = self.data.get('email', None)
self.fields['email'].initial = self.email
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
self.fields['persons'].choices = [(i.pk, unicode(i)) for i in Person.objects.filter(email__address=self.email).exclude(user=None).distinct().order_by('name')]
else:
self.fields['persons'].choices = [(i.pk, unicode(i)) for i in PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).filter(
Q(iesglogin__isnull=False)|
Q(legacywgpassword__isnull=False)|
Q(legacyliaisonuser__isnull=False)).distinct().order_by('first_name')]
def save(self):
person_id = self.cleaned_data.get('persons')
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
person = Person.objects.get(pk=person_id)
else:
person = PersonOrOrgInfo.objects.get(pk=person_id)
if self.shepherd:
self.assign_shepherd(person)
else:
self.create_delegate(person)
class NotExistDelegateForm(MultipleDelegateForm):
email = forms.EmailField(widget=forms.HiddenInput)
form_type = forms.CharField(widget=forms.HiddenInput, initial='notexist')
can_cancel = True
submit_msg = 'Send email to these addresses'
def __init__(self, *args, **kwargs):
super(NotExistDelegateForm, self).__init__(*args, **kwargs)
self.email_list = []
del(self.fields['persons'])
def get_email_list(self):
if self.email_list:
return self.email_list
email_list = [self.email]
email_list.append('IETF Secretariat <iesg-secretary@ietf.org>')
email_list += ['%s <%s>' % i.person.email() for i in self.wg.wgchair_set.all() if i.person.email()]
self.email_list = email_list
return email_list
def as_p(self):
email_list = self.get_email_list()
info = render_to_string('wgchairs/notexistdelegate.html', {'email_list': email_list, 'shepherd': self.shepherd})
return info + super(NotExistDelegateForm, self).as_p()
def send_email(self, to_email, template):
if self.shepherd:
subject = 'WG shepherd needs system credentials'
else:
subject = 'WG Delegate needs system credentials'
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
persons = Person.objects.filter(email__address=self.email).distinct()
else:
persons = PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).distinct()
body = render_to_string(template,
{'chair': get_person_for_user(self.user),
'delegate_email': self.email,
'shepherd': self.shepherd,
'delegate_persons': persons,
'wg': self.wg,
})
send_mail_text(self.request, to_email, settings.DEFAULT_FROM_EMAIL, subject, body)
def save(self):
self.next_form = AddDelegateForm(wg=self.wg, user=self.user)
if settings.DEBUG:
self.next_form.set_message('warning', 'Email was not sent cause tool is in DEBUG mode')
else:
# this is ugly...
email_list = self.get_email_list()
delegate = email_list[0]
secretariat = email_list[1]
wgchairs = email_list[2:]
self.send_email(delegate, 'wgchairs/notexistsdelegate_delegate_email.txt')
self.send_email(secretariat, 'wgchairs/notexistsdelegate_secretariat_email.txt')
self.send_email(wgchairs, 'wgchairs/notexistsdelegate_wgchairs_email.txt')
self.next_form.set_message('success', 'Email sent successfully')
def add_form_factory(request, wg, user, shepherd=False):
if request.method != 'POST' or request.POST.get('update_shepehrd'):
return AddDelegateForm(wg=wg, user=user, shepherd=shepherd)
if request.POST.get('form_type', None) == 'multiple':
f = MultipleDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
elif request.POST.get('form_type', None) == 'notexist':
f = NotExistDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
elif request.POST.get('form_type', None) == 'single':
f = AddDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd)
else:
f = AddDelegateForm(wg=wg, user=user, shepherd=shepherd)
f.request = request
return f
class WriteUpEditForm(RelatedWGForm):
writeup = forms.CharField(widget=forms.Textarea, required=False)
followup = forms.BooleanField(required=False)
comment = forms.CharField(widget=forms.Textarea, required=False)
def __init__(self, *args, **kwargs):
self.doc = kwargs.pop('doc', None)
self.doc_writeup = self.doc.protowriteup_set.all()
if self.doc_writeup.count():
self.doc_writeup = self.doc_writeup[0]
else:
self.doc_writeup = None
super(WriteUpEditForm, self).__init__(*args, **kwargs)
self.person = get_person_for_user(self.user)
def get_writeup(self):
return self.data.get('writeup', self.doc_writeup and self.doc_writeup.writeup or '')
def save(self):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
e = WriteupDocEvent(type="changed_protocol_writeup")
e.doc = self.doc
e.by = self.person
e.desc = e.get_type_display()
e.text = self.cleaned_data['writeup']
e.save()
from ietf.wgchairs.models import ProtoWriteUpProxy
self.doc_writeup = ProtoWriteUpProxy.objects.get(pk=e.pk)
else:
if not self.doc_writeup:
self.doc_writeup = ProtoWriteUp.objects.create(
person=self.person,
draft=self.doc,
writeup=self.cleaned_data['writeup'])
else:
self.doc_writeup.writeup = self.cleaned_data['writeup']
self.doc_writeup.save()
if self.data.get('modify_tag', False):
followup = self.cleaned_data.get('followup', False)
comment = self.cleaned_data.get('comment', False)
try:
shepherd = self.doc.shepherd
except PersonOrOrgInfo.DoesNotExist:
shepherd = None
if shepherd:
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
extra_notify = [shepherd.formatted_email()]
else:
extra_notify = ['%s <%s>' % shepherd.email()]
else:
extra_notify = []
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
tags = DocTagName.objects.filter(slug="sheph-u")
else:
tags = [FOLLOWUP_TAG]
if followup:
update_tags(self.request, self.doc, comment, self.person, set_tags=tags, extra_notify=extra_notify)
else:
update_tags(self.request, self.doc, comment, self.person, reset_tags=tags, extra_notify=extra_notify)
return self.doc_writeup
def is_valid(self):
if self.data.get('confirm', False) and self.data.get('modify_tag', False):
self.fields['comment'].required = True
else:
self.fields['comment'].required = False
return super(WriteUpEditForm, self).is_valid()

View file

@ -1 +0,0 @@
/*.pyc

View file

@ -1,110 +0,0 @@
from south.db import db
from django.db import models
from ietf.wgchairs.models import *
class Migration:
def forwards(self, orm):
# Adding model 'WGDelegate'
db.create_table('wgchairs_wgdelegate', (
('id', orm['wgchairs.WGDelegate:id']),
('person', orm['wgchairs.WGDelegate:person']),
('wg', orm['wgchairs.WGDelegate:wg']),
))
db.send_create_signal('wgchairs', ['WGDelegate'])
def backwards(self, orm):
# Deleting model 'WGDelegate'
db.delete_table('wgchairs_wgdelegate')
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
},
'wgchairs.wgdelegate': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"})
}
}
complete_apps = ['wgchairs']

View file

@ -1,163 +0,0 @@
from south.db import db
from django.db import models
from ietf.wgchairs.models import *
class Migration:
def forwards(self, orm):
# Adding model 'ProtoWriteUp'
db.create_table('wgchairs_protowriteup', (
('id', orm['wgchairs.protowriteup:id']),
('person', orm['wgchairs.protowriteup:person']),
('draft', orm['wgchairs.protowriteup:draft']),
('date', orm['wgchairs.protowriteup:date']),
('writeup', orm['wgchairs.protowriteup:writeup']),
))
db.send_create_signal('wgchairs', ['ProtoWriteUp'])
def backwards(self, orm):
# Deleting model 'ProtoWriteUp'
db.delete_table('wgchairs_protowriteup')
models = {
'idtracker.acronym': {
'Meta': {'db_table': "'acronym'"},
'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}),
'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'idtracker.area': {
'Meta': {'db_table': "'areas'"},
'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"})
},
'idtracker.areadirector': {
'Meta': {'db_table': "'area_directors'"},
'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"})
},
'idtracker.areastatus': {
'Meta': {'db_table': "'area_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idintendedstatus': {
'Meta': {'db_table': "'id_intended_status'"},
'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.idstatus': {
'Meta': {'db_table': "'id_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.ietfwg': {
'Meta': {'db_table': "'groups_ietf'"},
'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}),
'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}),
'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}),
'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}),
'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}),
'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"})
},
'idtracker.internetdraft': {
'Meta': {'db_table': "'internet_drafts'"},
'abstract': ('django.db.models.fields.TextField', [], {}),
'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}),
'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}),
'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}),
'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}),
'last_modified_date': ('django.db.models.fields.DateField', [], {}),
'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}),
'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}),
'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}),
'revision_date': ('django.db.models.fields.DateField', [], {}),
'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}),
'start_date': ('django.db.models.fields.DateField', [], {}),
'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}),
'txt_page_count': ('django.db.models.fields.IntegerField', [], {}),
'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'idtracker.personororginfo': {
'Meta': {'db_table': "'person_or_org_info'"},
'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}),
'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}),
'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'})
},
'idtracker.wgstatus': {
'Meta': {'db_table': "'g_status'"},
'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}),
'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'idtracker.wgtype': {
'Meta': {'db_table': "'g_type'"},
'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"})
},
'wgchairs.protowriteup': {
'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now()'}),
'draft': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.InternetDraft']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'writeup': ('django.db.models.fields.TextField', [], {})
},
'wgchairs.wgdelegate': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}),
'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"})
}
}
complete_apps = ['wgchairs']

View file

@ -1,87 +0,0 @@
import datetime
from django.db import models
from django.conf import settings
from ietf.idtracker.models import (IETFWG, PersonOrOrgInfo,
InternetDraft)
class WGDelegate(models.Model):
person = models.ForeignKey(
PersonOrOrgInfo,
)
wg = models.ForeignKey(IETFWG, related_name="old_wgdelegate_set" if settings.USE_DB_REDESIGN_PROXY_CLASSES else None)
def __unicode__(self):
return "%s" % self.person
class Meta:
verbose_name = "WG Delegate"
class ProtoWriteUp(models.Model):
person = models.ForeignKey(
PersonOrOrgInfo,
blank=False,
null=False,
)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.idtracker.models import InternetDraftOld as InternetDraft
draft = models.ForeignKey(
InternetDraft,
blank=False,
null=False,
)
date = models.DateTimeField(
default=datetime.datetime.now(),
blank=False,
null=False,
)
writeup = models.TextField(
blank=False,
null=False,
)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.group.models import Role
class WGDelegateProxy(Role):
#person = models.ForeignKey(PersonOrOrgInfo) # same name
#wg = models.ForeignKey(IETFWG)
@property
def wg(self):
return self.group
def __unicode__(self):
return u"%s" % self.person
class Meta:
proxy = True
from ietf.doc.models import WriteupDocEvent
class ProtoWriteUpProxy(WriteupDocEvent):
#person = models.ForeignKey(PersonOrOrgInfo, blank=False, null=False)
@property
def person(self):
return self.by
#draft = models.ForeignKey(InternetDraft, blank=False, null=False)
@property
def draft(self):
return self.doc
#date = models.DateTimeField(default=datetime.datetime.now(), blank=False, null=False)
@property
def date(self):
return self.time
#writeup = models.TextField(blank=False, null=False)
@property
def writeup(self):
return self.text
class Meta:
proxy = True
#WGDelegateOld = WGDelegate
WGDelegate = WGDelegateProxy

View file

@ -1 +0,0 @@
/*.pyc

View file

@ -1,47 +0,0 @@
from django.conf import settings
from django import template
from ietf.ietfworkflows.utils import get_state_for_draft
from ietf.wgchairs.accounts import (can_manage_workflow_in_group,
can_manage_delegates_in_group,
can_manage_shepherds_in_group)
register = template.Library()
@register.inclusion_tag('wgchairs/wgchairs_admin_options.html', takes_context=True)
def wgchairs_admin_options(context, wg):
request = context.get('request', None)
user = request and request.user
return {'user': user,
'can_manage_delegates': can_manage_delegates_in_group(user, wg),
'can_manage_workflow': can_manage_workflow_in_group(user, wg),
'can_manage_shepherds': can_manage_shepherds_in_group(user, wg),
'wg': wg,
'selected': context.get('selected', None),
}
@register.simple_tag
def writeup(doc):
writeup = doc.protowriteup_set.all()
if not writeup:
return ''
else:
return writeup[0].writeup
@register.simple_tag
def writeupdate(doc):
writeup = doc.protowriteup_set.all()
if not writeup:
return ''
else:
return writeup[0].date
@register.inclusion_tag('wgchairs/draft_state.html', takes_context=True)
def show_state(context, doc):
return {'doc': doc,
'state': get_state_for_draft(doc),
}

View file

@ -1,214 +0,0 @@
import datetime, os, shutil
from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse as urlreverse
import django.test
from StringIO import StringIO
from pyquery import PyQuery
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
from ietf.person.models import Person, Email
from ietf.group.models import Group, GroupHistory, Role, GroupStateTransitions
from ietf.doc.models import Document, State, WriteupDocEvent
from ietf.name.models import DocTagName
class ManageDelegatesTestCase(django.test.TestCase):
fixtures = ['names']
def test_delete_delegate(self):
make_test_data()
url = urlreverse('manage_delegates', kwargs=dict(acronym="mars"))
login_testing_unauthorized(self, "secretary", url)
delegates = Role.objects.filter(name="delegate", group__acronym="mars")
self.assertTrue(len(delegates) > 0)
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=delete]')), len(delegates))
# delete
r = self.client.post(url,
dict(remove="1",
delete=[d.pk for d in delegates]))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=delete]')), 0)
self.assertEquals(Role.objects.filter(name="delegate", group__acronym="mars").count(), 0)
def test_add_not_existing_delegate(self):
make_test_data()
url = urlreverse('manage_delegates', kwargs=dict(acronym="mars"))
login_testing_unauthorized(self, "secretary", url)
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=email]')), 1)
# add non-existing
r = self.client.post(url,
dict(email="unknown@example.com",
form_type="single"))
self.assertEquals(r.status_code, 200)
self.assertTrue("unknown@example.com" in r.content)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[type=submit][value*="Send email"]')), 1)
# we get back a warning and offer to send email, do that
mailbox_before = len(outbox)
r = self.client.post(url,
dict(email="unknown@example.com",
form_type="notexist"))
self.assertEquals(r.status_code, 200)
self.assertTrue("Email sent" in r.content)
self.assertEquals(len(outbox), mailbox_before + 3)
def test_add_delegate(self):
make_test_data()
url = urlreverse('manage_delegates', kwargs=dict(acronym="mars"))
login_testing_unauthorized(self, "secretary", url)
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=email]')), 1)
# add existing person
history_before = GroupHistory.objects.filter(acronym="mars").count()
r = self.client.post(url,
dict(email="plain@example.com",
form_type="single"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue("new delegate" in r.content)
self.assertTrue(Email.objects.get(address="plain@example.com").person.plain_name() in r.content)
self.assertEquals(Role.objects.filter(name="delegate", group__acronym="mars", email__address="plain@example.com").count(), 1)
self.assertEquals(history_before + 1, GroupHistory.objects.filter(acronym="mars").count())
class ManageShepherdsTestCase(django.test.TestCase):
fixtures = ['names']
def test_manage_shepherds(self):
make_test_data()
url = urlreverse('manage_shepherds', kwargs=dict(acronym="mars"))
login_testing_unauthorized(self, "secretary", url)
# setup test documents
group = Group.objects.get(acronym="mars")
from ietf.doc.models import Document
common = dict(group=group,
ad=Person.objects.get(user__username="ad"),
type_id="draft")
Document.objects.create(name="test-shepherd-no",
title="No shepherd",
shepherd=None,
**common)
Document.objects.create(name="test-shepherd-me",
title="Shepherd me",
shepherd=Person.objects.get(user__username="secretary"),
**common)
Document.objects.create(name="test-shepherd-other", title="Shepherd other",
shepherd=Person.objects.get(user__username="plain"),
**common)
for d in Document.objects.filter(name__startswith="test-shepherd"):
d.set_state(State.objects.get(used=True, type="draft", slug="active"))
# get and make sure they are divided correctly
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('div#noshepherd a:contains("No shepherd")')), 1)
self.assertEquals(len(q('div#mydocs a:contains("Shepherd me")')), 1)
self.assertEquals(len(q('div#othershepherds a:contains("Shepherd other")')), 1)
class ManageWorkflowTestCase(django.test.TestCase):
fixtures = ['names']
def test_manage_workflows(self):
make_test_data()
group = Group.objects.get(acronym="mars")
url = urlreverse('manage_workflow', kwargs=dict(acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc")
self.assertTrue(state not in group.unused_states.all())
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='0']")), 1)
# deactivate state
r = self.client.post(url,
dict(action="setstateactive",
state=state.pk,
active="0"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='1']")), 1)
group = Group.objects.get(acronym=group.acronym)
self.assertTrue(state in group.unused_states.all())
# change next states
state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-doc")
next_states = State.objects.filter(used=True, type=b"draft-stream-ietf", slug__in=["parked", "dead", "wait-wgw", 'sub-pub']).values_list('pk', flat=True)
r = self.client.post(url,
dict(action="setnextstates",
state=state.pk,
next_states=next_states))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-next-states").find("input[name=state][value='%s']" % state.pk).parents('form').find("input[name=next_states][checked=checked]")), len(next_states))
transitions = GroupStateTransitions.objects.filter(group=group, state=state)
self.assertEquals(len(transitions), 1)
self.assertEquals(set(transitions[0].next_states.values_list("pk", flat=True)), set(next_states))
# change them back to default
next_states = state.next_states.values_list("pk", flat=True)
r = self.client.post(url,
dict(action="setnextstates",
state=state.pk,
next_states=next_states))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
transitions = GroupStateTransitions.objects.filter(group=group, state=state)
self.assertEquals(len(transitions), 0)
# deactivate tag
tag = DocTagName.objects.get(slug="w-expert")
r = self.client.post(url,
dict(action="settagactive",
tag=tag.pk,
active="0"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1)
group = Group.objects.get(acronym=group.acronym)
self.assertTrue(tag in group.unused_tags.all())
if not settings.USE_DB_REDESIGN_PROXY_CLASSES:
# the above tests only work with the new schema
del ManageDelegatesTestCase
del ManageShepherdsTestCase
del ManageWorkflowTestCase
del ManageWriteupCase

View file

@ -1,9 +0,0 @@
# Copyright The IETF Trust 2008, All Rights Reserved
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('ietf.wgchairs.views',
url(r'^workflows/$', 'manage_workflow', name='manage_workflow'),
url(r'^delegates/$', 'manage_delegates', name='manage_delegates'),
url(r'^shepherds/$', 'wg_shepherd_documents', name='manage_shepherds'),
)

View file

@ -1,200 +0,0 @@
from django.conf import settings
from ietf.idtracker.models import IETFWG, InternetDraft
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.http import HttpResponseForbidden, Http404
from ietf.wgchairs.forms import (RemoveDelegateForm, add_form_factory,
workflow_form_factory, TransitionFormSet,
WriteUpEditForm, assign_shepherd)
from ietf.wgchairs.accounts import (can_manage_delegates_in_group, get_person_for_user,
can_manage_shepherds_in_group,
can_manage_workflow_in_group,
can_manage_shepherd_of_a_document,
can_manage_writeup_of_a_document,
can_manage_writeup_of_a_document_no_state,
)
from ietf.ietfworkflows.constants import REQUIRED_STATES
from ietf.ietfworkflows.utils import (get_workflow_for_wg,
get_default_workflow_for_wg,
get_state_by_name,
get_annotation_tags_for_draft,
get_state_for_draft, WAITING_WRITEUP,
FOLLOWUP_TAG)
from ietf.name.models import DocTagName
from ietf.doc.models import State
from ietf.doc.utils import get_tags_for_stream_id
def manage_delegates(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_delegates_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
delegates = wg.wgdelegate_set.all()
add_form = add_form_factory(request, wg, user)
if request.method == 'POST':
if request.POST.get('remove', None):
form = RemoveDelegateForm(wg=wg, data=request.POST.copy())
if form.is_valid():
form.save()
elif add_form.is_valid():
add_form.save()
add_form = add_form.get_next_form()
max_delegates = getattr(settings, 'MAX_WG_DELEGATES', 3)
return render_to_response('wgchairs/manage_delegates.html',
{'wg': wg,
'delegates': delegates,
'selected': 'manage_delegates',
'can_add': delegates.count() < max_delegates,
'max_delegates': max_delegates,
'add_form': add_form,
}, RequestContext(request))
def manage_workflow(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_workflow_in_group(user, wg):
return HttpResponseForbidden("You don't have permission to access this view")
workflow = get_workflow_for_wg(wg)
default_workflow = get_default_workflow_for_wg()
formset = None
if request.method == 'POST':
form = workflow_form_factory(request, wg=wg, user=user)
if form.is_valid():
form.save()
elif isinstance(form, TransitionFormSet):
formset = form
tags = workflow.selected_tags.all()
default_tags = default_workflow.annotation_tags.all()
states = workflow.selected_states.all().order_by('statedescription__order')
default_states = default_workflow.states.all().order_by('statedescription__order')
for i in default_states:
if states.filter(name=i.name).count() == 1:
i.used = True
if i.name in REQUIRED_STATES:
i.freeze = True
for i in default_tags:
if tags.filter(name=i.name).count() == 1:
i.used = True
if not formset:
formset = TransitionFormSet(queryset=workflow.transitions.all(), user=user, wg=wg)
return render_to_response('wgchairs/manage_workflow.html',
{'wg': wg,
'workflow': workflow,
'default_workflow': default_workflow,
'states': states,
'tags': tags,
'default_states': default_states,
'default_tags': default_tags,
'formset': formset,
'selected': 'manage_workflow',
}, RequestContext(request))
def manage_workflowREDESIGN(request, acronym):
from ietf.doc.models import State
from ietf.group.models import GroupStateTransitions
MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub')
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_workflow_in_group(user, wg):
return HttpResponseForbidden("You don't have permission to access this view")
if request.method == 'POST':
action = request.POST.get("action")
if action == "setstateactive":
active = request.POST.get("active") == "1"
try:
state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state"))
except State.DoesNotExist:
return HttpResponse("Invalid state %s" % request.POST.get("state"))
if active:
wg.unused_states.remove(state)
else:
wg.unused_states.add(state)
if action == "setnextstates":
try:
state = State.objects.get(pk=request.POST.get("state"))
except State.DoesNotExist:
return HttpResponse("Invalid state %s" % request.POST.get("state"))
next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states"))
unused = wg.unused_states.all()
if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)):
# just use the default
wg.groupstatetransitions_set.filter(state=state).delete()
else:
transitions, _ = GroupStateTransitions.objects.get_or_create(group=wg, state=state)
transitions.next_states = next_states
if action == "settagactive":
active = request.POST.get("active") == "1"
try:
tag = DocTagName.objects.get(pk=request.POST.get("tag"))
except DocTagName.DoesNotExist:
return HttpResponse("Invalid tag %s" % request.POST.get("tag"))
if active:
wg.unused_tags.remove(tag)
else:
wg.unused_tags.add(tag)
# put some info for the template on tags and states
unused_tags = wg.unused_tags.all().values_list('slug', flat=True)
tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf"))
for t in tags:
t.used = t.slug not in unused_tags
unused_states = wg.unused_states.all().values_list('slug', flat=True)
states = State.objects.filter(used=True, type="draft-stream-ietf")
transitions = dict((o.state, o) for o in wg.groupstatetransitions_set.all())
for s in states:
s.used = s.slug not in unused_states
s.mandatory = s.slug in MANDATORY_STATES
default_n = s.next_states.all()
if s in transitions:
n = transitions[s].next_states.all()
else:
n = default_n
s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states]
s.used_next_states = [x for x in n if x.slug not in unused_states]
return render_to_response('wgchairs/manage_workflowREDESIGN.html',
{'wg': wg,
'states': states,
'tags': tags,
'selected': 'manage_workflow',
}, RequestContext(request))
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
manage_workflow = manage_workflowREDESIGN
def wg_shepherd_documents(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
user = request.user
if not can_manage_shepherds_in_group(user, wg):
return HttpResponseForbidden('You have no permission to access this view')
current_person = get_person_for_user(user)
base_qs = InternetDraft.objects.filter(group=wg, states__type="draft", states__slug="active").select_related("status").order_by('title')
documents_no_shepherd = base_qs.filter(shepherd=None)
documents_my = base_qs.filter(shepherd=current_person)
documents_other = base_qs.exclude(shepherd=None).exclude(shepherd__pk__in=[current_person.pk, 0])
context = {
'no_shepherd': documents_no_shepherd,
'my_documents': documents_my,
'other_shepherds': documents_other,
'selected': 'manage_shepherds',
'wg': wg,
}
return render_to_response('wgchairs/wg_shepherd_documents.html', context, RequestContext(request))

View file

@ -26,7 +26,7 @@ class GroupChanges(Feed):
def link(self, obj):
if not obj:
raise FeedDoesNotExist
return urlreverse('wg_charter', kwargs={'acronym': obj.acronym})
return urlreverse('group_charter', kwargs={'acronym': obj.acronym})
def description(self, obj):
return self.title(obj)
@ -44,7 +44,7 @@ class GroupChanges(Feed):
if isinstance(obj, DocEvent):
return urlreverse("doc_view", kwargs={'name': obj.doc_id })
elif isinstance(obj, GroupEvent):
return urlreverse('wg_charter', kwargs={'acronym': obj.group.acronym })
return urlreverse('group_charter', kwargs={'acronym': obj.group.acronym })
def item_pubdate(self, obj):
return obj.time

View file

@ -33,7 +33,7 @@ def email_secretariat(request, group, type, text):
"wgcharter/email_secretariat.txt",
dict(text=text,
group=group,
group_url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=group.acronym)),
group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(acronym=group.acronym)),
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)),
)
)

View file

@ -1,8 +1,9 @@
# edit/create view for WGs
import re, os, string, datetime, shutil
import re, os, datetime, shutil
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.http import HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django import forms
@ -20,15 +21,18 @@ from ietf.group.models import *
from ietf.group.utils import save_group_in_history
from ietf.wgcharter.mails import email_secretariat
from ietf.person.forms import EmailsField
from ietf.doc.utils import get_tags_for_stream_id
MAX_GROUP_DELEGATES = 3
class WGForm(forms.Form):
name = forms.CharField(max_length=255, label="WG Name", required=True)
acronym = forms.CharField(max_length=10, label="WG Acronym", required=True)
state = forms.ModelChoiceField(GroupStateName.objects.all(), label="WG State", required=True)
chairs = EmailsField(label="WG Chairs", required=False)
secretaries = EmailsField(label="WG Secretaries", required=False)
techadv = EmailsField(label="WG Technical Advisors", required=False)
name = forms.CharField(max_length=255, label="Name", required=True)
acronym = forms.CharField(max_length=10, label="Acronym", required=True)
state = forms.ModelChoiceField(GroupStateName.objects.all(), label="State", required=True)
chairs = EmailsField(label="Chairs", required=False)
secretaries = EmailsField(label="Secretaries", required=False)
techadv = EmailsField(label="Technical Advisors", required=False)
delegates = EmailsField(label="Delegates", required=False, help_text=mark_safe("Type in name to search for person<br>Chairs can delegate the authority to update the state of group documents - max %s persons at a given time" % MAX_GROUP_DELEGATES))
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Shepherding AD", empty_label="(None)", required=False)
parent = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), label="IETF Area", empty_label="(None)", required=False)
list_email = forms.CharField(max_length=64, required=False)
@ -96,6 +100,13 @@ class WGForm(forms.Form):
def clean_urls(self):
return [x.strip() for x in self.cleaned_data["urls"].splitlines() if x.strip()]
def clean_delegates(self):
if len(self.cleaned_data["delegates"]) > MAX_GROUP_DELEGATES:
raise forms.ValidationError("At most %s delegates can be appointed at the same time, please remove %s delegates." % (
MAX_GROUP_DELEGATES, len(self.cleaned_data["delegates"]) - MAX_GROUP_DELEGATES))
return self.cleaned_data["delegates"]
def format_urls(urls, fs="\n"):
res = []
for u in urls:
@ -220,7 +231,7 @@ def edit(request, acronym=None, action="edit"):
shutil.copy(old, new)
# update roles
for attr, slug, title in [('chairs', 'chair', "Chairs"), ('secretaries', 'secr', "Secretaries"), ('techadv', 'techadv', "Tech Advisors")]:
for attr, slug, title in [('chairs', 'chair', "Chairs"), ('secretaries', 'secr', "Secretaries"), ('techadv', 'techadv', "Tech Advisors"), ('delegates', 'delegate', "Delegates")]:
new = clean[attr]
old = Email.objects.filter(role__group=wg, role__name=slug).select_related("person")
if set(new) != set(old):
@ -258,7 +269,7 @@ def edit(request, acronym=None, action="edit"):
if action=="charter":
return redirect('charter_submit', name=wg.charter.name, option="initcharter")
return redirect('wg_charter', acronym=wg.acronym)
return redirect('group_charter', acronym=wg.acronym)
else: # form.is_valid()
if not new_wg:
from ietf.person.forms import json_emails
@ -268,6 +279,7 @@ def edit(request, acronym=None, action="edit"):
chairs=Email.objects.filter(role__group=wg, role__name="chair"),
secretaries=Email.objects.filter(role__group=wg, role__name="secr"),
techadv=Email.objects.filter(role__group=wg, role__name="techadv"),
delegates=Email.objects.filter(role__group=wg, role__name="delegate"),
ad=wg.ad_id if wg.ad else None,
parent=wg.parent.id if wg.parent else None,
list_email=wg.list_email if wg.list_email else None,
@ -312,7 +324,7 @@ def conclude(request, acronym):
e.desc = "Requested closing group"
e.save()
return redirect('wg_charter', acronym=wg.acronym)
return redirect('group_charter', acronym=wg.acronym)
else:
form = ConcludeForm()
@ -320,3 +332,89 @@ def conclude(request, acronym):
dict(form=form,
wg=wg),
context_instance=RequestContext(request))
def customize_workflow(request, acronym):
MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub')
group = get_object_or_404(Group, acronym=acronym, type="wg")
if not request.user.is_authenticated() or not (has_role(request.user, "Secretariat") or group.role_set.filter(name="chair", person__user=request.user)):
return HttpResponseForbidden("You don't have permission to access this view")
if request.method == 'POST':
action = request.POST.get("action")
if action == "setstateactive":
active = request.POST.get("active") == "1"
try:
state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state"))
except State.DoesNotExist:
return HttpResponse("Invalid state %s" % request.POST.get("state"))
if active:
group.unused_states.remove(state)
else:
group.unused_states.add(state)
# redirect so the back button works correctly, otherwise
# repeated POSTs fills up the history
return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym)
if action == "setnextstates":
try:
state = State.objects.get(pk=request.POST.get("state"))
except State.DoesNotExist:
return HttpResponse("Invalid state %s" % request.POST.get("state"))
next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states"))
unused = group.unused_states.all()
if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)):
# just use the default
group.groupstatetransitions_set.filter(state=state).delete()
else:
transitions, _ = GroupStateTransitions.objects.get_or_create(group=group, state=state)
transitions.next_states = next_states
return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym)
if action == "settagactive":
active = request.POST.get("active") == "1"
try:
tag = DocTagName.objects.get(pk=request.POST.get("tag"))
except DocTagName.DoesNotExist:
return HttpResponse("Invalid tag %s" % request.POST.get("tag"))
if active:
group.unused_tags.remove(tag)
else:
group.unused_tags.add(tag)
return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym)
# put some info for the template on tags and states
unused_tags = group.unused_tags.all().values_list('slug', flat=True)
tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf"))
for t in tags:
t.used = t.slug not in unused_tags
unused_states = group.unused_states.all().values_list('slug', flat=True)
states = State.objects.filter(used=True, type="draft-stream-ietf")
transitions = dict((o.state, o) for o in group.groupstatetransitions_set.all())
for s in states:
s.used = s.slug not in unused_states
s.mandatory = s.slug in MANDATORY_STATES
default_n = s.next_states.all()
if s in transitions:
n = transitions[s].next_states.all()
else:
n = default_n
s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states]
s.used_next_states = [x for x in n if x.slug not in unused_states]
return render_to_response('wginfo/customize_workflow.html', {
'group': group,
'states': states,
'tags': tags,
}, RequestContext(request))

View file

@ -16,7 +16,7 @@ def email_milestones_changed(request, group, changes):
def wrap_up_email(to, text):
text = wrap(strip_tags(text), 70)
text += "\n\n"
text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym)))
text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym)))
send_mail_text(request, to, None,
u"Milestones changed for %s %s" % (group.acronym, group.type.name),
@ -95,7 +95,7 @@ def email_milestones_due(group, early_warning_days):
milestones=milestones,
today=today,
early_warning_days=early_warning_days,
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym))
url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym))
))
def groups_needing_milestones_due_reminder(early_warning_days):
@ -120,7 +120,7 @@ def email_milestones_overdue(group):
"wginfo/reminder_milestones_overdue.txt",
dict(group=group,
milestones=milestones,
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym))
url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym))
))
def groups_needing_milestones_overdue_reminder(grace_period=30):

View file

@ -313,7 +313,7 @@ def edit_milestones(request, acronym, milestone_set="current"):
if milestone_set == "charter":
return redirect('doc_view', name=group.charter.canonical_name())
else:
return redirect('wg_charter', acronym=group.acronym)
return redirect('group_charter', acronym=group.acronym)
else:
for m in milestones:
forms.append(MilestoneForm(instance=m, needs_review=needs_review))

View file

@ -50,36 +50,168 @@ from ietf.name.models import *
from ietf.person.models import *
from ietf.wginfo.mails import *
class WgInfoUrlTestCase(SimpleUrlTestCase):
def testUrls(self):
self.doTestUrls(__file__)
class WgFileTestCase(unittest.TestCase):
def testFileExistence(self):
fpath = os.path.join(settings.IETFWG_DESCRIPTIONS_PATH, "tls.desc.txt")
if not os.path.exists(fpath):
print "\nERROR: charter files not found in "+settings.IETFWG_DESCRIPTIONS_PATH
print "They are needed for testing WG charter pages."
print "Download them to a local directory with:"
print "wget -nd -nc -np -r http://www.ietf.org/wg-descriptions/"
print "And set IETFWG_DESCRIPTIONS_PATH in settings_local.py\n"
class WgOverviewTestCase(django.test.TestCase):
class GroupPagesTests(django.test.TestCase):
fixtures = ["names"]
def test_overview(self):
make_test_data()
def setUp(self):
self.charter_dir = os.path.abspath("tmp-charter-dir")
os.mkdir(self.charter_dir)
settings.CHARTER_PATH = self.charter_dir
wg = Group.objects.get(acronym="mars")
wg.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev"))
def tearDown(self):
shutil.rmtree(self.charter_dir)
def test_active_wgs(self):
draft = make_test_data()
group = draft.group
url = urlreverse('ietf.wginfo.views.active_wgs')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.parent.name in r.content)
self.assertTrue(group.acronym in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(group.ad.plain_name() in r.content)
def test_wg_summaries(self):
draft = make_test_data()
group = draft.group
chair = Email.objects.filter(role__group=group, role__name="chair")[0]
with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f:
f.write("This is a charter.")
url = urlreverse('ietf.wginfo.views.wg_summary_area')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.parent.name in r.content)
self.assertTrue(group.acronym in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(chair.address in r.content)
url = urlreverse('ietf.wginfo.views.wg_summary_acronym')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.acronym in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(chair.address in r.content)
url = urlreverse('ietf.wginfo.views.wg_charters')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.acronym in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(group.ad.plain_name() in r.content)
self.assertTrue(chair.address in r.content)
self.assertTrue("This is a charter." in r.content)
url = urlreverse('ietf.wginfo.views.wg_charters_by_acronym')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.acronym in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(group.ad.plain_name() in r.content)
self.assertTrue(chair.address in r.content)
self.assertTrue("This is a charter." in r.content)
def test_chartering_wgs(self):
draft = make_test_data()
group = draft.group
group.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev"))
url = urlreverse('ietf.wginfo.views.chartering_wgs')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("mars")')), 1)
self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1)
def test_bofs(self):
draft = make_test_data()
group = draft.group
group.state_id = "bof"
group.save()
url = urlreverse('ietf.wginfo.views.bofs')
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1)
def test_group_documents(self):
draft = make_test_data()
group = draft.group
draft2 = Document.objects.create(
name="draft-somebody-mars-test",
time=datetime.datetime.now(),
type_id="draft",
title="Test By Somebody",
stream_id="ietf",
group=Group.objects.get(type="individ"),
abstract="Abstract.",
rev="01",
pages=2,
intended_std_level_id="ps",
shepherd=None,
ad=None,
expires=datetime.datetime.now() + datetime.timedelta(days=10),
notify="",
note="",
)
draft2.set_state(State.objects.get(used=True, type="draft", slug="active"))
DocAlias.objects.create(
document=draft2,
name=draft2.name,
)
url = urlreverse('ietf.wginfo.views.group_documents', kwargs=dict(acronym=group.acronym))
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(draft.name in r.content)
self.assertTrue(group.name in r.content)
self.assertTrue(group.acronym in r.content)
self.assertTrue(draft2.name in r.content)
def test_group_charter(self):
draft = make_test_data()
group = draft.group
with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f:
f.write("This is a charter.")
milestone = GroupMilestone.objects.create(
group=group,
state_id="active",
desc="Get Work Done",
due=datetime.date.today() + datetime.timedelta(days=100))
milestone.docs.add(draft)
url = urlreverse('ietf.wginfo.views.group_charter', kwargs=dict(acronym=group.acronym))
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(group.name in r.content)
self.assertTrue(group.acronym in r.content)
self.assertTrue("This is a charter." in r.content)
self.assertTrue(milestone.desc in r.content)
self.assertTrue(milestone.docs.all()[0].name in r.content)
def test_history(self):
draft = make_test_data()
group = draft.group
e = GroupEvent.objects.create(
group=group,
desc="Something happened.",
type="added_comment",
by=Person.objects.get(name="(System)"))
url = urlreverse('ietf.wginfo.views.history', kwargs=dict(acronym=group.acronym))
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
self.assertTrue(e.desc in r.content)
class WgEditTestCase(django.test.TestCase):
fixtures = ["names"]
@ -178,7 +310,7 @@ class WgEditTestCase(django.test.TestCase):
make_test_data()
group = Group.objects.get(acronym="mars")
url = urlreverse('wg_edit', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit', kwargs=dict(acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
# normal get
@ -223,6 +355,7 @@ class WgEditTestCase(django.test.TestCase):
chairs="aread@ietf.org, ad1@ietf.org",
secretaries="aread@ietf.org, ad1@ietf.org, ad2@ietf.org",
techadv="aread@ietf.org",
delegates="ad2@ietf.org",
list_email="mars@mail",
list_subscribe="subscribe.mars",
list_archive="archive.mars",
@ -243,6 +376,7 @@ class WgEditTestCase(django.test.TestCase):
self.assertEquals(group.ad, ad)
for k in ("chair", "secr", "techadv"):
self.assertTrue(group.role_set.filter(name=k, email__address="aread@ietf.org"))
self.assertTrue(group.role_set.filter(name="delegate", email__address="ad2@ietf.org"))
self.assertEquals(group.list_email, "mars@mail")
self.assertEquals(group.list_subscribe, "subscribe.mars")
self.assertEquals(group.list_archive, "archive.mars")
@ -685,3 +819,75 @@ class MilestoneTestCase(django.test.TestCase):
self.assertTrue(group.acronym in outbox[-1]["Subject"])
self.assertTrue(m1.desc in unicode(outbox[-1]))
self.assertTrue(m2.desc in unicode(outbox[-1]))
class CustomizeWorkflowTestCase(django.test.TestCase):
fixtures = ['names']
def test_customize_workflow(self):
make_test_data()
group = Group.objects.get(acronym="mars")
url = urlreverse('ietf.wginfo.edit.customize_workflow', kwargs=dict(acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc")
self.assertTrue(state not in group.unused_states.all())
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='0']")), 1)
# deactivate state
r = self.client.post(url,
dict(action="setstateactive",
state=state.pk,
active="0"))
self.assertEquals(r.status_code, 302)
r = self.client.get(url)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='1']")), 1)
group = Group.objects.get(acronym=group.acronym)
self.assertTrue(state in group.unused_states.all())
# change next states
state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-doc")
next_states = State.objects.filter(used=True, type=b"draft-stream-ietf", slug__in=["parked", "dead", "wait-wgw", 'sub-pub']).values_list('pk', flat=True)
r = self.client.post(url,
dict(action="setnextstates",
state=state.pk,
next_states=next_states))
self.assertEquals(r.status_code, 302)
r = self.client.get(url)
q = PyQuery(r.content)
self.assertEquals(len(q("form.set-next-states").find("input[name=state][value='%s']" % state.pk).parents('form').find("input[name=next_states][checked=checked]")), len(next_states))
transitions = GroupStateTransitions.objects.filter(group=group, state=state)
self.assertEquals(len(transitions), 1)
self.assertEquals(set(transitions[0].next_states.values_list("pk", flat=True)), set(next_states))
# change them back to default
next_states = state.next_states.values_list("pk", flat=True)
r = self.client.post(url,
dict(action="setnextstates",
state=state.pk,
next_states=next_states))
self.assertEquals(r.status_code, 302)
r = self.client.get(url)
q = PyQuery(r.content)
transitions = GroupStateTransitions.objects.filter(group=group, state=state)
self.assertEquals(len(transitions), 0)
# deactivate tag
tag = DocTagName.objects.get(slug="w-expert")
r = self.client.post(url,
dict(action="settagactive",
tag=tag.pk,
active="0"))
self.assertEquals(r.status_code, 302)
r = self.client.get(url)
q = PyQuery(r.content)
self.assertEquals(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1)
group = Group.objects.get(acronym=group.acronym)
self.assertTrue(tag in group.unused_tags.all())

View file

@ -1,19 +0,0 @@
200 /wg/
404 /wg/nosuchgroup/
200 /wg/tls/
200 /wg/tls/charter/
200 /wg/mobike/ # concluded
200 /wg/mobike/charter/
200 /wg/catnip/ # concluded very long time ago
200 /wg/catnip/charter/ # concluded very long time ago
404 /wg/saag/ # not a WG
404 /wg/saag/charter/ # not a WG
200 /wg/1wg-summary.txt
200 /wg/1wg-summary-by-acronym.txt
301 /wg/summary.txt
301 /wg/summary-by-area.txt
301 /wg/summary-by-acronym.txt
200,heavy /wg/1wg-charters.txt
200,heavy /wg/1wg-charters-by-acronym.txt

View file

@ -6,7 +6,7 @@ from django.views.generic.simple import redirect_to
urlpatterns = patterns('',
(r'^$', views.wg_dir),
(r'^$', views.active_wgs),
(r'^summary.txt', redirect_to, { 'url':'/wg/1wg-summary.txt' }),
(r'^summary-by-area.txt', redirect_to, { 'url':'/wg/1wg-summary.txt' }),
(r'^summary-by-acronym.txt', redirect_to, { 'url':'/wg/1wg-summary-by-acronym.txt' }),
@ -18,17 +18,16 @@ urlpatterns = patterns('',
(r'^bofs/$', views.bofs),
(r'^chartering/create/$', edit.edit, {'action': "charter"}, "wg_create"),
(r'^bofs/create/$', edit.edit, {'action': "create"}, "bof_create"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/documents/txt/$', views.wg_documents_txt),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/$', views.wg_documents_html, None, "wg_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/charter/$', views.wg_charter, None, 'wg_charter'),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/documents/txt/$', views.group_documents_txt),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/$', views.group_documents, None, "wg_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/charter/$', views.group_charter, None, 'group_charter'),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/init-charter/', edit.submit_initial_charter, None, "wg_init_charter"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/history/$', views.history),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/edit/$', edit.edit, {'action': "edit"}, "wg_edit"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/edit/$', edit.edit, {'action': "edit"}, "group_edit"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/conclude/$', edit.conclude, None, "wg_conclude"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/$', milestones.edit_milestones, {'milestone_set': "current"}, "wg_edit_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "wg_edit_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "wg_reset_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "wg_ajax_search_docs"),
(r'^(?P<acronym>[^/]+)/management/', include('ietf.wgchairs.urls')),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/workflow/$', edit.customize_workflow),
)

View file

@ -32,77 +32,111 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import itertools
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext, loader
from django.template import RequestContext
from django.http import HttpResponse
from django.conf import settings
from django.core.urlresolvers import reverse as urlreverse
from ietf.idtracker.models import Area, IETFWG
from ietf.doc.views_search import SearchForm, retrieve_search_results
from ietf.idrfc.idrfc_wrapper import IdRfcWrapper
from ietf.ipr.models import IprDetail
from ietf.group.models import Group
from ietf.doc.models import State
from ietf.group.models import Group, GroupURL
from ietf.doc.models import State, DocAlias, RelatedDocument
from ietf.doc.utils import get_chartering_type
from ietf.person.models import Email
from ietf.group.utils import get_charter_text
from ietf.doc.templatetags.ietf_filters import clean_whitespace
from ietf.ietfauth.utils import has_role
def fill_in_charter_info(wg, include_drafts=False):
from ietf.person.models import Email
from ietf.doc.models import DocAlias, RelatedDocument
def fill_in_charter_info(group, include_drafts=False):
group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None
group.chairs = Email.objects.filter(role__group=group, role__name="chair")
group.techadvisors = Email.objects.filter(role__group=group, role__name="techadv")
group.editors = Email.objects.filter(role__group=group, role__name="editor")
group.secretaries = Email.objects.filter(role__group=group, role__name="secr")
milestone_state = "charter" if group.state_id == "proposed" else "active"
group.milestones = group.groupmilestone_set.filter(state=milestone_state).order_by('due')
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")
milestone_state = "charter" if wg.state_id == "proposed" else "active"
wg.milestones = wg.groupmilestone_set.filter(state=milestone_state).order_by('due')
if group.charter:
group.charter_text = get_charter_text(group)
else:
group.charter_text = u"Not chartered yet."
if include_drafts:
aliases = DocAlias.objects.filter(document__type="draft", document__group=wg).select_related('document').order_by("name")
wg.drafts = []
wg.rfcs = []
aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name")
group.drafts = []
group.rfcs = []
for a in aliases:
if a.name.startswith("draft"):
wg.drafts.append(a)
group.drafts.append(a)
else:
wg.rfcs.append(a)
group.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)
return HttpResponse(loader.render_to_string('wginfo/1wg-summary-by-acronym.txt', {'area_list': areas, 'wg_list': wgs}),mimetype='text/plain; charset=UTF-8')
def extract_last_name(email):
return email.person.name_parts()[3]
def extract_group_chairs(group):
return sorted(Email.objects.filter(role__group=group, role__name="chair").select_related("person"), key=extract_last_name)
def wg_summary_area(request):
wgs = IETFWG.objects.filter(status='1',group_type='1',start_date__isnull=False).exclude(parent=None)
return HttpResponse(loader.render_to_string('wginfo/1wg-summary.txt', {'wg_list': wgs}),mimetype='text/plain; charset=UTF-8')
def wg_charters(request):
wgs = IETFWG.objects.filter(status='1',group_type='1',start_date__isnull=False).exclude(parent=None)
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',group_type='1',start_date__isnull=False)
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 ietf.group.models import Group, GroupURL
from ietf.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=extract_last_name)
area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym")
for group in area.groups:
group.chairs = extract_group_chairs(group)
areas = [a for a in areas if a.groups]
return render_to_response('wginfo/1wg-summary.txt',
{ 'areas': areas },
mimetype='text/plain; charset=UTF-8')
def wg_summary_acronym(request):
areas = Group.objects.filter(type="area", state="active").order_by("name")
groups = Group.objects.filter(type="wg", state="active").order_by("acronym").select_related("parent")
for group in groups:
group.chairs = extract_group_chairs(group)
return render_to_response('wginfo/1wg-summary-by-acronym.txt',
{ 'areas': areas,
'groups': groups },
mimetype='text/plain; charset=UTF-8')
def wg_charters(request):
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=extract_last_name)
area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("name")
for group in area.groups:
fill_in_charter_info(group, include_drafts=True)
group.area = area
return render_to_response('wginfo/1wg-charters.txt',
{ 'areas': areas },
mimetype='text/plain; charset=UTF-8')
def wg_charters_by_acronym(request):
areas = dict((a.id, a) for a in Group.objects.filter(type="area", state="active").order_by("name"))
for area in areas.itervalues():
area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=extract_last_name)
groups = Group.objects.filter(type="wg", state="active").exclude(parent=None).order_by("acronym")
for group in groups:
fill_in_charter_info(group, include_drafts=True)
group.area = areas.get(group.parent_id)
return render_to_response('wginfo/1wg-charters-by-acronym.txt',
{ 'groups': groups },
mimetype='text/plain; charset=UTF-8')
def active_wgs(request):
areas = Group.objects.filter(type="area", state="active").order_by("name")
for area in areas:
# dig out information for template
area.ads = []
for e in Email.objects.filter(role__group=area, role__name="ad").select_related("person"):
e.incoming = False
@ -112,26 +146,22 @@ def wg_dirREDESIGN(request):
e.incoming = True
area.ads.append(e)
area.ads.sort(key=lambda e: (e.incoming, e.person.name_parts()[3]))
area.ads.sort(key=lambda e: (e.incoming, extract_last_name(e)))
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))
wg.chairs = extract_group_chairs(wg)
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
wg_dir = wg_dirREDESIGN
return render_to_response('wginfo/active_wgs.html', {'areas':areas}, RequestContext(request))
def bofs(request):
groups = Group.objects.filter(type="wg", state="bof")
return render_to_response('wginfo/bofs.html',dict(groups=groups),RequestContext(request))
return render_to_response('wginfo/bofs.html',dict(groups=groups), RequestContext(request))
def chartering_wgs(request):
charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev"))
groups = Group.objects.filter(type="wg", charter__states__in=charter_states).select_related("state", "charter")
for g in groups:
g.chartering_type = get_chartering_type(g.charter)
@ -141,32 +171,38 @@ def chartering_wgs(request):
RequestContext(request))
def wg_documents(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
concluded = wg.status_id in [ 2, 3, ]
proposed = (wg.status_id == 4)
form = SearchForm({'by':'group', 'group':str(wg.group_acronym.acronym),
'rfcs':'on', 'activedrafts':'on'})
def construct_group_menu_context(request, group, selected, others):
"""Return context with info for the group menu filled in."""
d = {
"group": group,
"selected": selected,
}
d.update(others)
return d
def search_for_group_documents(group):
form = SearchForm({ 'by':'group', 'group': group.acronym or "", 'rfcs':'on', 'activedrafts': 'on' })
docs, meta = retrieve_search_results(form)
# get the related docs
form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activedrafts':'on'})
docs_related, meta_related = retrieve_search_results(form_related)
docs_related_pruned = []
for d in docs_related:
form_related = SearchForm({ 'by':'group', 'name': u'-%s-' % group.acronym, 'activedrafts': 'on' })
raw_docs_related, meta_related = retrieve_search_results(form_related)
docs_related = []
for d in raw_docs_related:
parts = d.name.split("-", 2);
# canonical form draft-<name|ietf>-wg-etc
if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym + "-"):
if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(group.acronym + "-"):
d.search_heading = "Related Internet-Draft"
docs_related_pruned.append(d)
docs_related = docs_related_pruned
docs_related.append(d)
# move call for WG adoption to related
cleaned_docs = []
docs_related_names = set(d.name for d in docs_related)
for d in docs:
if d.stream_id == "ietf" and d.get_state_slug("draft-stream-ietf") in [ "c-adopt", "wg-cand" ]:
if d.stream_id and d.get_state_slug("draft-stream-%s" % d.stream_id) in ("c-adopt", "wg-cand"):
if d.name not in docs_related_names:
d.search_heading = "Related Internet-Draft"
docs_related.append(d)
@ -177,59 +213,82 @@ def wg_documents(request, acronym):
docs_related.sort(key=lambda d: d.name)
return wg, concluded, proposed, docs, meta, docs_related, meta_related
return docs, meta, docs_related, meta_related
def wg_documents_txt(request, acronym):
wg, concluded, proposed, docs, meta, docs_related, meta_related = wg_documents(request, acronym)
return HttpResponse(loader.render_to_string('wginfo/wg_documents.txt', {'wg': wg, 'concluded':concluded, 'proposed':proposed, 'selected':'documents', 'docs':docs, 'meta':meta, 'docs_related':docs_related, 'meta_related':meta_related}),mimetype='text/plain; charset=UTF-8')
def group_documents(request, acronym):
group = get_object_or_404(Group, type="wg", acronym=acronym)
def wg_documents_html(request, acronym):
wg, concluded, proposed, docs, meta, docs_related, meta_related = wg_documents(request, acronym)
return render_to_response('wginfo/wg_documents.html', {'wg': wg, 'concluded':concluded, 'proposed':proposed, 'selected':'documents', 'docs':docs, 'meta':meta, 'docs_related':docs_related, 'meta_related':meta_related}, RequestContext(request))
docs, meta, docs_related, meta_related = search_for_group_documents(group)
def wg_charter(request, acronym):
wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1)
concluded = wg.status_id in [ 2, 3, ]
proposed = (wg.status_id == 4)
return render_to_response('wginfo/group_documents.html',
construct_group_menu_context(request, group, "documents", {
'docs': docs,
'meta': meta,
'docs_related': docs_related,
'meta_related': meta_related
}), RequestContext(request))
def group_documents_txt(request, acronym):
"""Return tabulator-separated rows with documents for group."""
group = get_object_or_404(Group, type="wg", acronym=acronym)
docs, meta, docs_related, meta_related = search_for_group_documents(group)
for d in docs:
d.prefix = d.get_state().name
for d in docs_related:
d.prefix = u"Related %s" % d.get_state().name
rows = []
for d in itertools.chain(docs, docs_related):
rfc_number = d.rfc_number()
if rfc_number != None:
name = rfc_number
else:
name = "%s-%s" % (d.name, d.rev)
rows.append(u"\t".join((d.prefix, name, clean_whitespace(d.title))))
return HttpResponse(u"\n".join(rows), mimetype='text/plain; charset=UTF-8')
def group_charter(request, acronym):
group = get_object_or_404(Group, type="wg", acronym=acronym)
fill_in_charter_info(group, include_drafts=False)
group.delegates = Email.objects.filter(role__group=group, role__name="delegate")
fill_in_charter_info(wg)
actions = []
if wg.state_id != "conclude":
actions.append(("Edit WG", urlreverse("wg_edit", kwargs=dict(acronym=wg.acronym))))
if group.state_id != "conclude":
actions.append((u"Edit %s" % group.type.name, urlreverse("group_edit", kwargs=dict(acronym=group.acronym))))
e = wg.latest_event(type__in=("changed_state", "requested_close",))
requested_close = wg.state_id != "conclude" and e and e.type == "requested_close"
e = group.latest_event(type__in=("changed_state", "requested_close",))
requested_close = group.state_id != "conclude" and e and e.type == "requested_close"
if wg.state_id in ("active", "dormant"):
actions.append(("Request closing WG", urlreverse("wg_conclude", kwargs=dict(acronym=wg.acronym))))
if group.state_id in ("active", "dormant"):
actions.append((u"Request closing %s" % group.type.name, urlreverse("wg_conclude", kwargs=dict(acronym=group.acronym))))
context = get_wg_menu_context(wg, "charter")
context.update(dict(
actions=actions,
is_chair=request.user.is_authenticated() and wg.role_set.filter(name="chair", person__user=request.user),
milestones_in_review=wg.groupmilestone_set.filter(state="review"),
requested_close=requested_close,
))
is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user)
return render_to_response('wginfo/wg_charter.html',
context,
RequestContext(request))
if is_chair or has_role(request.user, "Secretariat"):
actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym))))
def get_wg_menu_context(wg, selected):
# it would probably be better to refactor wginfo into rendering
# the menu separately instead of each view having to include the information
return render_to_response('wginfo/group_charter.html',
construct_group_menu_context(request, group, "charter", {
"actions": actions,
"is_chair": is_chair,
"milestones_in_review": group.groupmilestone_set.filter(state="review"),
"requested_close": requested_close,
}), RequestContext(request))
return dict(wg=wg, concluded=wg.state_id == "conclude", proposed=wg.state_id == "proposed", selected=selected)
def history(request, acronym):
wg = get_object_or_404(Group, acronym=acronym)
group = get_object_or_404(Group, acronym=acronym)
events = wg.groupevent_set.all().select_related('by').order_by('-time', '-id')
events = group.groupevent_set.all().select_related('by').order_by('-time', '-id')
context = get_wg_menu_context(wg, "history")
context.update(dict(events=events,
))
wg.group_acronym = wg # hack for compatibility with old templates
return render_to_response('wginfo/history.html', context, RequestContext(request))
return render_to_response('wginfo/history.html',
construct_group_menu_context(request, group, "history", {
"events": events,
}), RequestContext(request))

View file

@ -372,6 +372,24 @@ span.fieldRequired {
background-color: #ffcc66;
}
.state-help-icon {
display: inline-block;
margin-left: 0.2em;
padding: 0 0.2em;
font-weight: bold;
font-style: normal;
font-size: 90%;
color: #999;
background-color: #ddd;
text-decoration: none;
}
.state-help-icon:hover {
color: #eee;
background-color: #bbb;
transition-duration: 0.2s;
}
/* js styles */
.js-info {
background-color: #FFDD88;