Merge changes from attic/shimfree into new branch to complete rebasing shimfree on trunk
- Legacy-Id: 6215
This commit is contained in:
commit
019ca2ae03
|
@ -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 ","}')"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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']:
|
||||
|
|
|
@ -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, {}),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -176,7 +176,6 @@ INSTALLED_APPS = (
|
|||
'ietf.wginfo',
|
||||
'ietf.submit',
|
||||
'ietf.ietfworkflows',
|
||||
'ietf.wgchairs',
|
||||
'ietf.wgcharter',
|
||||
'ietf.sync',
|
||||
'ietf.community',
|
||||
|
|
|
@ -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%">
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
|
@ -1 +0,0 @@
|
|||
{{ state.name }}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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>
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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%}
|
|
@ -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>
|
|
@ -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 %}
|
||||
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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 %}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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("–");
|
||||
toggler.html("– customize");
|
||||
toggled.slideDown(300);
|
||||
}
|
||||
else {
|
||||
toggler.html("+");
|
||||
toggler.html("+ customize");
|
||||
toggled.slideUp(300);
|
||||
}
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 »</a> |
|
||||
{% endif %}
|
||||
<a href="http://tools.ietf.org/wg/{{ wg.group_acronym.acronym }}/">Tools WG Page »</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 »</a> |
|
||||
{% endif %}
|
||||
<a href="http://tools.ietf.org/wg/{{ group.acronym }}/">Tools WG Page »</a>
|
||||
</div>
|
||||
|
||||
{% block wg_content %}
|
||||
{% endblock wg_content %}
|
||||
{% block group_content %}
|
||||
{% endblock group_content %}
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
182
ietf/templates/wginfo/group_charter.html
Normal file
182
ietf/templates/wginfo/group_charter.html
Normal 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 }} <{{ chair.address }}></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 }} <{{ group.areadirector.address }}></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 }} <{{ techadvisor.address }}></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 }} <{{ editor.address }}></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 }} <{{ secretary.address }}></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 }} <{{ delegate.address }}></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 %}
|
18
ietf/templates/wginfo/group_documents.html
Normal file
18
ietf/templates/wginfo/group_documents.html
Normal 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 %}
|
4
ietf/templates/wginfo/group_entry.txt
Normal file
4
ietf/templates/wginfo/group_entry.txt
Normal 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 }}
|
48
ietf/templates/wginfo/group_entry_with_charter.txt
Normal file
48
ietf/templates/wginfo/group_entry_with_charter.txt
Normal 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 %}
|
|
@ -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>
|
||||
|
|
|
@ -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 %}
|
|
@ -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 %}
|
|
@ -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}}"> </span></td> <td><a href="mailto:{{ ad.person.email.1 }}">{{ ad.person }} <{{ ad.person.email.1 }}></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 %}
|
|
@ -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 }} <{{ chair.address }}></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 }} <{{ wg.areadirector.address }}></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 }} <{{ techadvisor.address }}></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 }} <{{ editor.address }}></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 }} <{{ secretary.address }}></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 %}
|
|
@ -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 %}
|
|
@ -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 %}
|
||||
|
|
@ -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 %}
|
|
@ -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 }}
|
1
ietf/wgchairs/.gitignore
vendored
1
ietf/wgchairs/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/*.pyc
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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()
|
1
ietf/wgchairs/migrations/.gitignore
vendored
1
ietf/wgchairs/migrations/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/*.pyc
|
|
@ -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']
|
|
@ -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']
|
|
@ -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
|
1
ietf/wgchairs/templatetags/.gitignore
vendored
1
ietf/wgchairs/templatetags/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/*.pyc
|
|
@ -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),
|
||||
}
|
|
@ -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
|
|
@ -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'),
|
||||
)
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
)
|
||||
)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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),
|
||||
)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue