Parameterize the <wg> in /wg/<acronym> to allow for RGs, add simple /rg/ overview page based on similar /wg/ overview page, fix links and other WG/RG-specific details. All the basic pages under /rg/ now appear to be working for RGs. Edit pages and permissions are not adapted yet, though.

- Legacy-Id: 7535
This commit is contained in:
Ole Laursen 2014-03-22 13:11:23 +00:00
parent 28a3d68c6f
commit ad357e0068
25 changed files with 311 additions and 247 deletions

View file

@ -88,7 +88,7 @@ class WGField(DisplayField):
if raw:
return document.group.acronym
else:
return '<a href="%s">%s</a>' % (urlreverse('wg_docs', kwargs={'acronym':document.group.acronym}), document.group.acronym) if (document.group and document.group.acronym != 'none') else ''
return '<a href="%s">%s</a>' % (urlreverse('group_docs', kwargs=dict(group_type=document.group.type_id, acronym=document.group.acronym)), document.group.acronym) if (document.group and document.group.acronym != 'none') else ''
class ADField(DisplayField):

View file

@ -242,7 +242,7 @@ def document_main(request, name, rev=None):
elif group.type_id in ("rg", "wg"):
submission = "%s %s" % (group.acronym, group.type)
if group.type_id == "wg":
submission = "<a href=\"%s\">%s</a>" % (urlreverse("wg_docs", kwargs=dict(acronym=doc.group.acronym)), submission)
submission = "<a href=\"%s\">%s</a>" % (urlreverse("group_docs", kwargs=dict(group_type=doc.group.type_id, acronym=doc.group.acronym)), submission)
if doc.stream_id and doc.get_state_slug("draft-stream-%s" % doc.stream_id) == "c-adopt":
submission = "candidate for %s" % submission

View file

@ -73,8 +73,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</div></div></li>
<li style="padding-top:0;"><a href="/wg/">Active WGs</a></li>
<li><a href="{% url "ietf.wginfo.views.chartering_wgs" %}">Chartering WGs</a></li>
<li><a href="{% url "ietf.wginfo.views.bofs" %}">BoFs</a></li>
<li><a href="{% url "ietf.wginfo.views.chartering_wgs" group_type="wg" %}">Chartering WGs</a></li>
<li><a href="{% url "ietf.wginfo.views.bofs" group_type="wg" %}">BoFs</a></li>
<li><a href="http://tools.ietf.org/wg/concluded">Concluded WGs</a></li>
<li><a href="http://www.ietf.org/list/nonwg.html">Non-WG Lists</a></li>

View file

@ -25,7 +25,7 @@
{% if snapshot %}Snapshot of{% endif %}
{% if doc.get_state_slug != "approved" %}Proposed{% endif %}
Charter for "{{ group.name }}"
(<a {% if group.type.slug == "wg" %}href="{% url "ietf.wginfo.views.group_charter" acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
(<a {% if group.type.slug == "wg" %}href="{% url "ietf.wginfo.views.group_charter" group_type=group.type_id acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
</div>
<table id="metatable" width="100%">
@ -132,7 +132,7 @@
{% if not snapshot and chartering %}
<h3>Proposed Milestones
{% if user|has_role:"Area Director,Secretariat" %}
<a class="edit" href="{% url "wg_edit_charter_milestones" acronym=doc.group.acronym %}">Edit charter milestones</a>
<a class="edit" href="{% url "group_edit_charter_milestones" group_type=doc.group.type_id acronym=doc.group.acronym %}">Edit charter milestones</a>
{% endif %}
</h3>

View file

@ -15,7 +15,7 @@ div.milestones-for-group { margin: 0.5em 0; }
{% for g in ad.groups_needing_review %}
<div class="milestones-for-group">{{ g.name }} ({{ g.acronym }}) <a href="{% url "wg_edit_milestones" acronym=g.acronym %}">has new milestones</a>:</div>
<div class="milestones-for-group">{{ g.name }} ({{ g.acronym }}) <a href="{% url "group_edit_milestones" group_type=g.type_id acronym=g.acronym %}">has new milestones</a>:</div>
{% include "wginfo/milestones.html" with milestones=g.milestones_needing_review %}

View file

@ -0,0 +1,33 @@
{% extends "base.html" %}
{% block title %}Active IRTF Research 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 IRTF Research Groups</h1>
<p>IRTF Chair:</p>
<div style="margin-left:2em;">
<a href="mailto:irtf-chair@irtf.org">{{ irtf.chair.person.plain_name }}</a>
</div>
<p>Active Research Groups:</p>
<div style="margin-left:2em;">
<table class="ietf-wg-table">
{% for group in groups %}
<tr>
<td width="10%;"><a href="{% url "ietf.wginfo.views.group_documents" group_type=group.type_id acronym=group.acronym %}">{{ group.acronym }}</a></td>
<td width="50%">{{ group.name }}</td>
<td width="40%">{% for chair in group.chairs %}<a href="mailto:{{ chair.email.address }}">{{ chair.person.plain_name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}

View file

@ -80,7 +80,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<table class="ietf-wg-table">
{% for group in area.groups %}
<tr>
<td width="10%;"><a href="/wg/{{ group.acronym }}/">{{ group.acronym }}</a></td>
<td width="10%;"><a href="{% url "ietf.wginfo.views.group_documents" group_type=group.type_id acronym=group.acronym %}">{{ group.acronym }}</a></td>
<td width="1%">{% for ad in area.ads %}{% if ad.person_id == group.ad_id %}<span title="AD for {{ group.acronym }}: {{ ad.person }}" class="square bgcolor{{forloop.counter}}"></span>{% endif %}{% endfor %}</td>
<td width="50%">{{ group.name }}</td>
<td width="39%">{% for chair in group.chairs %}<a href="mailto:{{ chair.email.address }}">{{ chair.person.plain_name }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</td>

View file

@ -10,7 +10,7 @@
<p>Groups in the BoF state</p>
{% if user|has_role:"Area Director,Secretariat" %}
<p><a href="{% url "bof_create" %}">Create a new BoF</a></p>
<p><a href="{% url "bof_create" group_type="wg" %}">Create a new BoF</a></p>
{% endif %}
{% if not groups %}
@ -25,7 +25,7 @@
{% for g in groups %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="acronym">
<a href="{% url "group_charter" acronym=g.acronym %}">{{ g.acronym }}</a>
<a href="{% url "group_charter" group_type=g.type_id acronym=g.acronym %}">{{ g.acronym }}</a>
</td>
<td class="title">
<a {%comment%}href="{% url "doc_view" name=g.charter.name %}"{%endcomment%}>{{ g.name }}</a>

View file

@ -12,7 +12,7 @@
{% for s in charter_states %}{% if not forloop.first %}, {% if forloop.last %}or {% endif %}{% endif %}<i>{{ s.name }}</i>{% endfor %}.</p>
{% if user|has_role:"Area Director,Secretariat" %}
<p><a href="{% url "wg_create" %}">Start chartering new WG</a></p>
<p><a href="{% url "group_create" group_type="wg" %}">Start chartering new WG</a></p>
{% endif %}
{% if not groups %}
@ -28,7 +28,7 @@
{% for g in groups %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="acronym">
<a href="{% url "group_charter" acronym=g.acronym %}">{{ g.acronym }}</a>
<a href="{% url "group_charter" group_type=g.type_id acronym=g.acronym %}">{{ g.acronym }}</a>
</td>
<td class="title">
<a href="{% url "doc_view" name=g.charter.name %}">{{ g.name }}</a>

View file

@ -1,6 +1,6 @@
{% extends "base.html" %}
{% block title %}Request closing of {{ wg.acronym }} {{ wg.type.name }}{% endblock %}
{% block title %}Request closing of {{ group.acronym }} {{ group.type.name }}{% endblock %}
{% block morecss %}
#id_instructions {
@ -14,7 +14,7 @@ form.conclude .actions {
{% endblock %}
{% block content %}
<h1>Request closing of {{ wg.acronym }} {{ wg.type.name }}</h1>
<h1>Request closing of {{ group.acronym }} {{ group.type.name }}</h1>
<p>
Please provide instructions regarding the disposition of each
@ -29,7 +29,7 @@ form.conclude .actions {
{{ form.as_table }}
<tr>
<td colspan="2" class="actions">
<a class="button" href="{% url "group_charter" acronym=wg.acronym %}">Cancel</a>
<a class="button" href="{% url "group_charter" group_type=group.type_id acronym=group.acronym %}">Cancel</a>
<input class="button" type="submit" value="Send request"/>
</td>
</tr>

View file

@ -34,7 +34,7 @@
<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
<a href="{% url "group_charter" group_type=group.type_id acronym=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

View file

@ -1,10 +1,10 @@
{% extends "base.html" %}
{% block title %}
{% if wg %}
Edit WG {{ wg.acronym }}
{% if group %}
Edit {{ group.type.name }} {{ group.acronym }}
{% else %}
Start chartering new WG
Start chartering new group
{% endif %}
{% endblock %}
@ -28,12 +28,12 @@ form.edit #id_urls { height: 4em; }
{% load ietf_filters %}
<h1>
{% if action == "edit" %}
Edit WG {{ wg.acronym }}
Edit {{ group.type.name }} {{ group.acronym }}
{% else %}
{% if action == "charter" %}
Start chartering new WG
Start chartering new group
{% else %}
Create new WG or BoF
Create new group or BoF
{% endif %}
{% endif %}
</h1>
@ -68,7 +68,7 @@ so. New accounts can be <a href="{% url "create_account" %}">created here</a>.</
<td></td>
<td class="actions">
{% if action == "edit" %}
<a class="button" href="{% url "group_charter" acronym=wg.acronym %}">Cancel</a>
<a class="button" href="{% url "group_charter" group_type=group.type_id acronym=group.acronym %}">Cancel</a>
<input class="button" type="submit" value="Save"/>
{% else %}
{% if action == "charter" %}

View file

@ -42,7 +42,7 @@ tr.milestone.add { font-style: italic; }
<noscript>This page depends on Javascript being enabled to work properly.</noscript>
<p>Links:
<a href="{% url "group_charter" acronym=group.acronym %}">{{ group.acronym }} {{ group.type.name }}</a>
<a href="{% url "group_charter" group_type=group.type_id 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>
@ -58,7 +58,7 @@ Director.
{% if can_reset %}
<p>
You can <a href="{% url "wg_reset_charter_milestones" acronym=group.acronym %}">reset
You can <a href="{% url "group_reset_charter_milestones" group_type=group.type_id acronym=group.acronym %}">reset
this list</a> to the milestones currently in use for the {{ group.acronym }} {{ group.type.name }}.
</p>
{% endif %}
@ -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 "group_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" group_type=group.type_id acronym=group.acronym %}{% endif %}">Cancel</a>
<input class="button" type="submit" data-labelsave="Save" data-labelreview="Review changes" value="Save" style="display:none"/>
<input type="hidden" name="action" value="save">
</div>

View file

@ -66,10 +66,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<div class="ietf-navset">
<div>
<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>
| <a href="{% url 'ietf.wginfo.views.dependencies_pdf' acronym=group.acronym %}">Dependency Graph</a>
<a {% if selected == "documents" %}class="selected"{% else %}href="{% url "ietf.wginfo.views.group_documents" group_type=group.type_id acronym=group.acronym %}"{% endif %}>Documents</a> |
<a {% if selected == "charter" %}class="selected"{% else %}href="{% url "ietf.wginfo.views.group_charter" group_type=group.type_id acronym=group.acronym %}"{% endif %}>Charter</a> |
<a {% if selected == "history" %}class="selected"{% else %}href="{% url "ietf.wginfo.views.history" group_type=group.type_id acronym=group.acronym %}"{% endif %}>History</a>
| <a href="{% url 'ietf.wginfo.views.dependencies_pdf' group_type=group.type_id acronym=group.acronym %}">Dependency Graph</a>
{% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %}
| <a href="{{ group.list_archive }}">List Archive &raquo;</a>
{% endif %}

View file

@ -26,7 +26,7 @@ is occasionally incorrect.</span>
<tr><td>Acronym:</td><td>{{ group.acronym }}</td></tr>
{% if group.parent %}
{% if group.parent and group.parent.type_id == "area" %}
<tr><td>{{ group.parent.type.name }}:</td><td>{{ group.parent.name }} ({{ group.parent.acronym }})</td></tr>
{% endif %}
@ -47,7 +47,7 @@ is occasionally incorrect.</span>
{% else %}
none
{% if user|has_role:"Area Director,Secretariat" %}
- <a href="{% url "ietf.wginfo.edit.submit_initial_charter" acronym=group.acronym %}">Submit Charter</a>
- <a href="{% url "ietf.wginfo.edit.submit_initial_charter" group_type=group.type_id acronym=group.acronym %}">Submit Charter</a>
{% endif %}
{% endif %}
</td>
@ -64,6 +64,7 @@ is occasionally incorrect.</span>
</td>
</tr>
{% if group.parent.type_id == "area" %}
<tr><td>Area Director:</td>
<td>
{% if group.areadirector %}
@ -71,6 +72,7 @@ is occasionally incorrect.</span>
{% else %}?{% endif %}
</td>
</tr>
{% endif %}
{% if group.techadvisors %}
<tr>
@ -142,7 +144,7 @@ is occasionally incorrect.</span>
{% 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:
<p>In addition to the charter, there is additional information about this group on the Web at:
{% for url in urls %}
<a href="{{ url.url }}">{{ url.name }}</a>{% if not forloop.last %}, {% endif %}
{% endfor %}
@ -150,7 +152,7 @@ is occasionally incorrect.</span>
{% endif %}
{% endwith %}
<h2>Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} Working Group</h2>
<h2>Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} {{ long_group_type }}</h2>
<p>{{ group.charter_text|escape|format_charter|safe }}</p>

View file

@ -26,7 +26,7 @@
</tr>
<tr class="docs">
<td>Drafts:</td>
<td><input name="{{ form.docs.html_name }}" class="tokenized-field" data-ajax-url="{% url "wg_ajax_search_docs" group.acronym %}" data-pre="{{ form.docs_prepopulate }}"/>
<td><input name="{{ form.docs.html_name }}" class="tokenized-field" data-ajax-url="{% url "group_ajax_search_docs" group_type=group.type_id acronym=group.acronym %}" data-pre="{{ form.docs_prepopulate }}"/>
{{ form.docs.errors }}
</td>
</tr>

View file

@ -29,7 +29,7 @@
{% endfor %}
<div class="actions">
<a href="{% url "wg_edit_charter_milestones" acronym=group.acronym %}">Back</a>
<a href="{% url "group_edit_charter_milestones" group_type=group.type_id acronym=group.acronym %}">Back</a>
<input type="submit" value="Reset charter milestones"/>
</div>
</form>

View file

@ -53,7 +53,7 @@ urlpatterns = patterns('',
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', { 'sitemaps': sitemaps}),
(r'^submit/', include('ietf.submit.urls')),
(r'^sync/', include('ietf.sync.urls')),
(r'^wg/', include('ietf.wginfo.urls')),
(r'^(?P<group_type>(wg|rg))/', include('ietf.wginfo.urls')),
(r'^stream/', include('ietf.group.stream_urls')),
(r'^nomcom/', include('ietf.nomcom.urls')),
(r'^templates/', include('ietf.dbtemplate.urls')),

View file

@ -1,4 +1,4 @@
# edit/create view for WGs
# edit/create view for groups
import re
import os
@ -6,9 +6,8 @@ import datetime
import shutil
from django import forms
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponseForbidden
from django.template import RequestContext
from django.utils.html import mark_safe
from django.http import Http404, HttpResponse
@ -26,7 +25,7 @@ from ietf.wginfo.mails import email_secretariat
MAX_GROUP_DELEGATES = 3
class WGForm(forms.Form):
class GroupForm(forms.Form):
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)
@ -42,7 +41,7 @@ class WGForm(forms.Form):
urls = forms.CharField(widget=forms.Textarea, label="Additional URLs", help_text="Format: http://site/path (Optional description). Separate multiple entries with newline.", required=False)
def __init__(self, *args, **kwargs):
self.wg = kwargs.pop('wg', None)
self.group = kwargs.pop('group', None)
self.confirmed = kwargs.pop('confirmed', False)
super(self.__class__, self).__init__(*args, **kwargs)
@ -55,18 +54,18 @@ class WGForm(forms.Form):
self.confirm_msg = ""
self.autoenable_confirm = False
if self.wg:
if self.group:
self.fields['acronym'].widget.attrs['readonly'] = True
def clean_acronym(self):
self.confirm_msg = ""
self.autoenable_confirm = False
# Changing the acronym of an already existing WG will cause 404s all
# Changing the acronym of an already existing GROUP will cause 404s all
# over the place, loose history, and generally muck up a lot of
# things, so we don't permit it
if self.wg:
return self.wg.acronym # no change permitted
if self.group:
return self.group.acronym # no change permitted
acronym = self.cleaned_data['acronym'].strip().lower()
@ -83,13 +82,13 @@ class WGForm(forms.Form):
return acronym # take over confirmed
if existing.state_id == "bof":
self.confirm_msg = "Turn BoF %s into proposed WG and start chartering it" % existing.acronym
self.confirm_msg = "Turn BoF %s into proposed %s and start chartering it" % (existing.acronym, existing.type.name)
self.autoenable_confirm = True
raise forms.ValidationError("Warning: Acronym used for an existing BoF (%s)." % existing.name)
else:
self.confirm_msg = "Set state of %s WG to proposed and start chartering it" % existing.acronym
self.confirm_msg = "Set state of %s %s to proposed and start chartering it" % (existing.acronym, existing.type.name)
self.autoenable_confirm = False
raise forms.ValidationError("Warning: Acronym used for an existing WG (%s, %s)." % (existing.name, existing.state.name if existing.state else "unknown state"))
raise forms.ValidationError("Warning: Acronym used for an existing %s (%s, %s)." % (existing.type.name, existing.name, existing.state.name if existing.state else "unknown state"))
if existing:
raise forms.ValidationError("Acronym used for an existing group (%s)." % existing.name)
@ -98,7 +97,7 @@ class WGForm(forms.Form):
if old and not self.confirmed:
self.confirm_msg = "Confirm reusing acronym %s" % old[0].acronym
self.autoenable_confirm = False
raise forms.ValidationError("Warning: Acronym used for a historic WG.")
raise forms.ValidationError("Warning: Acronym used for a historic group.")
return acronym
@ -121,16 +120,16 @@ def format_urls(urls, fs="\n"):
res.append(u.url)
return fs.join(res)
def get_or_create_initial_charter(wg):
def get_or_create_initial_charter(group):
try:
charter = Document.objects.get(docalias__name="charter-ietf-%s" % wg.acronym)
charter = Document.objects.get(docalias__name="charter-ietf-%s" % group.acronym)
except Document.DoesNotExist:
charter = Document(
name="charter-ietf-" + wg.acronym,
name="charter-ietf-" + group.acronym,
type_id="charter",
title=wg.name,
group=wg,
abstract=wg.name,
title=group.name,
group=group,
abstract=group.name,
rev="00-00",
)
charter.save()
@ -145,74 +144,74 @@ def get_or_create_initial_charter(wg):
return charter
@role_required('Area Director', 'Secretariat')
def submit_initial_charter(request, acronym=None):
wg = get_object_or_404(Group, acronym=acronym)
if not wg.charter:
wg.charter = get_or_create_initial_charter(wg)
wg.save()
return redirect('charter_submit', name=wg.charter.name, option="initcharter")
def submit_initial_charter(request, group_type, acronym=None):
group = get_object_or_404(Group, acronym=acronym)
if not group.charter:
group.charter = get_or_create_initial_charter(group)
group.save()
return redirect('charter_submit', name=group.charter.name, option="initcharter")
@role_required('Area Director', 'Secretariat')
def edit(request, acronym=None, action="edit"):
"""Edit or create a WG, notifying parties as
def edit(request, group_type, acronym=None, action="edit"):
"""Edit or create a GROUP, notifying parties as
necessary and logging changes as group events."""
if action == "edit":
wg = get_object_or_404(Group, acronym=acronym)
new_wg = False
group = get_object_or_404(Group, acronym=acronym)
new_group = False
elif action in ("create","charter"):
wg = None
new_wg = True
group = None
new_group = True
else:
raise Http404
login = request.user.person
if request.method == 'POST':
form = WGForm(request.POST, wg=wg, confirmed=request.POST.get("confirmed", False))
form = GroupForm(request.POST, group=group, confirmed=request.POST.get("confirmed", False))
if form.is_valid():
clean = form.cleaned_data
if new_wg:
if new_group:
try:
wg = Group.objects.get(acronym=clean["acronym"])
save_group_in_history(wg)
wg.time = datetime.datetime.now()
wg.save()
group = Group.objects.get(acronym=clean["acronym"])
save_group_in_history(group)
group.time = datetime.datetime.now()
group.save()
except Group.DoesNotExist:
wg = Group.objects.create(name=clean["name"],
group = Group.objects.create(name=clean["name"],
acronym=clean["acronym"],
type=GroupTypeName.objects.get(slug="wg"),
type=GroupTypeName.objects.get(slug=group_type),
state=clean["state"]
)
e = ChangeStateGroupEvent(group=wg, type="changed_state")
e.time = wg.time
e = ChangeStateGroupEvent(group=group, type="changed_state")
e.time = group.time
e.by = login
e.state_id = clean["state"].slug
e.desc = "Group created in state %s" % clean["state"].name
e.save()
else:
save_group_in_history(wg)
save_group_in_history(group)
if action=="charter" and not wg.charter: # make sure we have a charter
wg.charter = get_or_create_initial_charter(wg)
if action=="charter" and not group.charter: # make sure we have a charter
group.charter = get_or_create_initial_charter(group)
changes = []
def desc(attr, new, old):
entry = "%(attr)s changed to <b>%(new)s</b> from %(old)s"
if new_wg:
if new_group:
entry = "%(attr)s changed to <b>%(new)s</b>"
return entry % dict(attr=attr, new=new, old=old)
def diff(attr, name):
v = getattr(wg, attr)
v = getattr(group, attr)
if clean[attr] != v:
changes.append(desc(name, clean[attr], v))
setattr(wg, attr, clean[attr])
setattr(group, attr, clean[attr])
prev_acronym = wg.acronym
prev_acronym = group.acronym
# update the attributes, keeping track of what we're doing
diff('name', "Name")
@ -224,85 +223,84 @@ def edit(request, acronym=None, action="edit"):
diff('list_subscribe', "Mailing list subscribe address")
diff('list_archive', "Mailing list archive")
if not new_wg and wg.acronym != prev_acronym and wg.charter:
save_document_in_history(wg.charter)
if not new_group and group.acronym != prev_acronym and group.charter:
save_document_in_history(group.charter)
DocAlias.objects.get_or_create(
name="charter-ietf-%s" % wg.acronym,
document=wg.charter,
name="charter-ietf-%s" % group.acronym,
document=group.charter,
)
old = os.path.join(wg.charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (prev_acronym, wg.charter.rev))
old = os.path.join(group.charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (prev_acronym, group.charter.rev))
if os.path.exists(old):
new = os.path.join(wg.charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (wg.acronym, wg.charter.rev))
new = os.path.join(group.charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (group.acronym, group.charter.rev))
shutil.copy(old, new)
# update roles
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")
old = Email.objects.filter(role__group=group, role__name=slug).select_related("person")
if set(new) != set(old):
changes.append(desc(title,
", ".join(x.get_name() for x in new),
", ".join(x.get_name() for x in old)))
wg.role_set.filter(name=slug).delete()
group.role_set.filter(name=slug).delete()
for e in new:
Role.objects.get_or_create(name_id=slug, email=e, group=wg, person=e.person)
Role.objects.get_or_create(name_id=slug, email=e, group=group, person=e.person)
# update urls
new_urls = clean['urls']
old_urls = format_urls(wg.groupurl_set.order_by('url'), ", ")
old_urls = format_urls(group.groupurl_set.order_by('url'), ", ")
if ", ".join(sorted(new_urls)) != old_urls:
changes.append(desc('Urls', ", ".join(sorted(new_urls)), old_urls))
wg.groupurl_set.all().delete()
group.groupurl_set.all().delete()
# Add new ones
for u in new_urls:
m = re.search('(?P<url>[\w\d:#@%/;$()~_?\+-=\\\.&]+)( \((?P<name>.+)\))?', u)
if m:
if m.group('name'):
url = GroupURL(url=m.group('url'), name=m.group('name'), group=wg)
url = GroupURL(url=m.group('url'), name=m.group('name'), group=group)
else:
url = GroupURL(url=m.group('url'), name='', group=wg)
url = GroupURL(url=m.group('url'), name='', group=group)
url.save()
wg.time = datetime.datetime.now()
group.time = datetime.datetime.now()
if changes and not new_wg:
if changes and not new_group:
for c in changes:
GroupEvent.objects.create(group=wg, by=login, type="info_changed", desc=c)
GroupEvent.objects.create(group=group, by=login, type="info_changed", desc=c)
wg.save()
group.save()
if action=="charter":
return redirect('charter_submit', name=wg.charter.name, option="initcharter")
return redirect('charter_submit', name=group.charter.name, option="initcharter")
return redirect('group_charter', acronym=wg.acronym)
return redirect('group_charter', group_type=group.type_id, acronym=group.acronym)
else: # form.is_valid()
if not new_wg:
init = dict(name=wg.name,
acronym=wg.acronym,
state=wg.state,
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,
list_subscribe=wg.list_subscribe if wg.list_subscribe else None,
list_archive=wg.list_archive if wg.list_archive else None,
urls=format_urls(wg.groupurl_set.all()),
if not new_group:
init = dict(name=group.name,
acronym=group.acronym,
state=group.state,
chairs=Email.objects.filter(role__group=group, role__name="chair"),
secretaries=Email.objects.filter(role__group=group, role__name="secr"),
techadv=Email.objects.filter(role__group=group, role__name="techadv"),
delegates=Email.objects.filter(role__group=group, role__name="delegate"),
ad=group.ad_id if group.ad else None,
parent=group.parent.id if group.parent else None,
list_email=group.list_email if group.list_email else None,
list_subscribe=group.list_subscribe if group.list_subscribe else None,
list_archive=group.list_archive if group.list_archive else None,
urls=format_urls(group.groupurl_set.all()),
)
else:
init = dict(ad=login.id if has_role(request.user, "Area Director") else None,
)
form = WGForm(initial=init, wg=wg)
form = GroupForm(initial=init, group=group)
return render_to_response('wginfo/edit.html',
dict(wg=wg,
form=form,
action=action,
user=request.user,
login=login),
context_instance=RequestContext(request))
return render(request, 'wginfo/edit.html',
dict(group=group,
form=form,
action=action,
user=request.user,
login=login))
@ -310,9 +308,9 @@ class ConcludeForm(forms.Form):
instructions = forms.CharField(widget=forms.Textarea(attrs={'rows': 30}), required=True)
@role_required('Area Director','Secretariat')
def conclude(request, acronym):
"""Request the closing of a WG, prompting for instructions."""
wg = get_object_or_404(Group, acronym=acronym)
def conclude(request, group_type, acronym):
"""Request the closing of group, prompting for instructions."""
group = get_object_or_404(Group, type=group_type, acronym=acronym)
login = request.user.person
@ -321,27 +319,25 @@ def conclude(request, acronym):
if form.is_valid():
instructions = form.cleaned_data['instructions']
email_secretariat(request, wg, "Request closing of group", instructions)
email_secretariat(request, group, "Request closing of group", instructions)
e = GroupEvent(group=wg, by=login)
e = GroupEvent(group=group, by=login)
e.type = "requested_close"
e.desc = "Requested closing group"
e.save()
return redirect('group_charter', acronym=wg.acronym)
return redirect('group_charter', group_type=group.type_id, acronym=group.acronym)
else:
form = ConcludeForm()
return render_to_response('wginfo/conclude.html',
dict(form=form,
wg=wg),
context_instance=RequestContext(request))
return render(request, 'wginfo/conclude.html',
dict(form=form, group=group))
def customize_workflow(request, acronym):
def customize_workflow(request, group_type, acronym):
MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub')
group = get_object_or_404(Group, acronym=acronym, type="wg")
group = get_object_or_404(Group, type=group_type, acronym=acronym)
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")
@ -361,7 +357,7 @@ def customize_workflow(request, acronym):
# redirect so the back button works correctly, otherwise
# repeated POSTs fills up the history
return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym)
return redirect("ietf.wginfo.edit.customize_workflow", group_type=group.type_id, acronym=group.acronym)
if action == "setnextstates":
try:
@ -378,7 +374,7 @@ def customize_workflow(request, acronym):
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)
return redirect("ietf.wginfo.edit.customize_workflow", group_type=group.type_id, acronym=group.acronym)
if action == "settagactive":
active = request.POST.get("active") == "1"
@ -392,7 +388,7 @@ def customize_workflow(request, acronym):
else:
group.unused_tags.add(tag)
return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym)
return redirect("ietf.wginfo.edit.customize_workflow", group_type=group.type_id, acronym=group.acronym)
# put some info for the template on tags and states
@ -417,8 +413,8 @@ def customize_workflow(request, acronym):
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', {
return render(request, 'wginfo/customize_workflow.html', {
'group': group,
'states': states,
'tags': tags,
}, RequestContext(request))
})

View file

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

View file

@ -22,7 +22,7 @@ def email_secretariat(request, group, subject, text):
"wginfo/email_secretariat.txt",
dict(text=text,
group=group,
group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(acronym=group.acronym)),
group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(group_type=group.type_id, acronym=group.acronym)),
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)),
)
)
@ -31,7 +31,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("group_charter", kwargs=dict(acronym=group.acronym)))
text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(group_type=group.type_id, acronym=group.acronym)))
send_mail_text(request, to, None,
u"Milestones changed for %s %s" % (group.acronym, group.type.name),
@ -84,7 +84,7 @@ def email_milestone_review_reminder(group, grace_period=7):
"wginfo/reminder_milestones_need_review.txt",
dict(group=group,
milestones=milestones,
url=settings.IDTRACKER_BASE_URL + urlreverse("wg_edit_milestones", kwargs=dict(acronym=group.acronym)),
url=settings.IDTRACKER_BASE_URL + urlreverse("group_edit_milestones", kwargs=dict(group_type=group.type_id, acronym=group.acronym)),
cc=cc,
)
)
@ -112,7 +112,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("group_charter", kwargs=dict(acronym=group.acronym))
url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(group_type=group.type_id, acronym=group.acronym))
))
def groups_needing_milestones_due_reminder(early_warning_days):
@ -137,7 +137,7 @@ def email_milestones_overdue(group):
"wginfo/reminder_milestones_overdue.txt",
dict(group=group,
milestones=milestones,
url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym))
url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(group_type=group.type_id, acronym=group.acronym))
))
def groups_needing_milestones_overdue_reminder(grace_period=30):

View file

@ -1,4 +1,4 @@
# WG milestone editing views
# group milestone editing views
import datetime
import calendar
@ -110,7 +110,7 @@ class MilestoneForm(forms.Form):
@role_required('WG Chair', 'Area Director', 'Secretariat')
def edit_milestones(request, acronym, milestone_set="current"):
def edit_milestones(request, group_type, acronym, milestone_set="current"):
# milestones_set + needs_review: we have several paths into this view
# AD/Secr. -> all actions on current + add new
# group chair -> limited actions on current + add new for review
@ -120,7 +120,7 @@ def edit_milestones(request, acronym, milestone_set="current"):
login = request.user.person
group = get_object_or_404(Group, acronym=acronym)
group = get_object_or_404(Group, type=group_type, acronym=acronym)
needs_review = False
if not has_role(request.user, ("Area Director", "Secretariat")):
@ -311,7 +311,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('group_charter', acronym=group.acronym)
return redirect('group_charter', group_type=group.type_id, acronym=group.acronym)
else:
for m in milestones:
forms.append(MilestoneForm(instance=m, needs_review=needs_review))
@ -335,11 +335,11 @@ def edit_milestones(request, acronym, milestone_set="current"):
context_instance=RequestContext(request))
@role_required('WG Chair', 'Area Director', 'Secretariat')
def reset_charter_milestones(request, acronym):
def reset_charter_milestones(request, group_type, acronym):
"""Reset charter milestones to the currently in-use milestones."""
login = request.user.person
group = get_object_or_404(Group, acronym=acronym)
group = get_object_or_404(Group, type=group_type, acronym=acronym)
if (not has_role(request.user, ("Area Director", "Secretariat")) and
not group.role_set.filter(name="chair", person=login)):
@ -384,7 +384,7 @@ def reset_charter_milestones(request, acronym):
)
return redirect('wg_edit_charter_milestones', acronym=group.acronym)
return redirect('group_edit_charter_milestones', group_type=group.type_id, acronym=group.acronym)
return render_to_response('wginfo/reset_charter_milestones.html',
dict(group=group,
@ -394,6 +394,6 @@ def reset_charter_milestones(request, acronym):
context_instance=RequestContext(request))
def ajax_search_docs(request, acronym):
def ajax_search_docs(request, group_type, acronym):
docs = Document.objects.filter(name__icontains=request.GET.get('q',''), type="draft").order_by('name').distinct()[:20]
return HttpResponse(json_doc_names(docs), content_type='application/json')

View file

@ -32,11 +32,11 @@ class GroupPagesTests(TestCase):
def tearDown(self):
shutil.rmtree(self.charter_dir)
def test_active_wgs(self):
def test_active_groups(self):
draft = make_test_data()
group = draft.group
url = urlreverse('ietf.wginfo.views.active_wgs')
url = urlreverse('ietf.wginfo.views.active_groups', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(group.parent.name in r.content)
@ -44,6 +44,10 @@ class GroupPagesTests(TestCase):
self.assertTrue(group.name in r.content)
self.assertTrue(group.ad.plain_name() in r.content)
url = urlreverse('ietf.wginfo.views.active_groups', kwargs=dict(group_type="rg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
def test_wg_summaries(self):
draft = make_test_data()
group = draft.group
@ -53,7 +57,7 @@ class GroupPagesTests(TestCase):
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')
url = urlreverse('ietf.wginfo.views.wg_summary_area', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(group.parent.name in r.content)
@ -61,14 +65,14 @@ class GroupPagesTests(TestCase):
self.assertTrue(group.name in r.content)
self.assertTrue(chair.address in r.content)
url = urlreverse('ietf.wginfo.views.wg_summary_acronym')
url = urlreverse('ietf.wginfo.views.wg_summary_acronym', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(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')
url = urlreverse('ietf.wginfo.views.wg_charters', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(group.acronym in r.content)
@ -77,7 +81,7 @@ class GroupPagesTests(TestCase):
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')
url = urlreverse('ietf.wginfo.views.wg_charters_by_acronym', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(group.acronym in r.content)
@ -91,7 +95,7 @@ class GroupPagesTests(TestCase):
group = draft.group
group.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev"))
url = urlreverse('ietf.wginfo.views.chartering_wgs')
url = urlreverse('ietf.wginfo.views.chartering_wgs', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
@ -103,7 +107,7 @@ class GroupPagesTests(TestCase):
group.state_id = "bof"
group.save()
url = urlreverse('ietf.wginfo.views.bofs')
url = urlreverse('ietf.wginfo.views.bofs', kwargs=dict(group_type="wg"))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
@ -137,7 +141,7 @@ class GroupPagesTests(TestCase):
name=draft2.name,
)
url = urlreverse('ietf.wginfo.views.group_documents', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.views.group_documents', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(draft.name in r.content)
@ -147,7 +151,7 @@ class GroupPagesTests(TestCase):
self.assertTrue(draft2.name in r.content)
# test the txt version too while we're at it
url = urlreverse('ietf.wginfo.views.group_documents_txt', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.views.group_documents_txt', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(draft.name in r.content)
@ -167,7 +171,7 @@ class GroupPagesTests(TestCase):
due=datetime.date.today() + datetime.timedelta(days=100))
milestone.docs.add(draft)
url = urlreverse('ietf.wginfo.views.group_charter', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.views.group_charter', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(group.name in r.content)
@ -186,7 +190,7 @@ class GroupPagesTests(TestCase):
type="added_comment",
by=Person.objects.get(name="(System)"))
url = urlreverse('ietf.wginfo.views.history', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.views.history', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
self.assertTrue(e.desc in r.content)
@ -225,7 +229,7 @@ class GroupEditTests(TestCase):
def test_create(self):
make_test_data()
url = urlreverse('wg_create')
url = urlreverse('group_create', kwargs=dict(group_type="wg"))
login_testing_unauthorized(self, "secretary", url)
num_wgs = len(Group.objects.filter(type="wg"))
@ -273,7 +277,7 @@ class GroupEditTests(TestCase):
def test_create_based_on_existing(self):
make_test_data()
url = urlreverse('wg_create')
url = urlreverse('group_create', kwargs=dict(group_type="wg"))
login_testing_unauthorized(self, "secretary", url)
group = Group.objects.get(acronym="mars")
@ -308,7 +312,7 @@ class GroupEditTests(TestCase):
make_test_data()
group = Group.objects.get(acronym="mars")
url = urlreverse('group_edit', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
# normal get
@ -380,7 +384,7 @@ class GroupEditTests(TestCase):
group = Group.objects.get(acronym="mars")
url = urlreverse('wg_conclude', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.edit.conclude', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
# normal get
@ -435,7 +439,7 @@ class MilestoneTests(TestCase):
def test_milestone_sets(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
r = self.client.get(url)
@ -443,7 +447,7 @@ class MilestoneTests(TestCase):
self.assertTrue(m1.desc in r.content)
self.assertTrue(m2.desc not in r.content)
url = urlreverse('wg_edit_charter_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_charter_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
@ -453,7 +457,7 @@ class MilestoneTests(TestCase):
def test_add_milestone(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
# normal get
@ -505,7 +509,7 @@ class MilestoneTests(TestCase):
def test_add_milestone_as_chair(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "marschairman", url)
# normal get
@ -539,7 +543,7 @@ class MilestoneTests(TestCase):
m1.state_id = "review"
m1.save()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "ad", url)
# normal get
@ -569,7 +573,7 @@ class MilestoneTests(TestCase):
def test_delete_milestone(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
milestones_before = GroupMilestone.objects.count()
@ -597,7 +601,7 @@ class MilestoneTests(TestCase):
def test_edit_milestone(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_edit_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_edit_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
milestones_before = GroupMilestone.objects.count()
@ -654,7 +658,7 @@ class MilestoneTests(TestCase):
def test_reset_charter_milestones(self):
m1, m2, group = self.create_test_milestones()
url = urlreverse('wg_reset_charter_milestones', kwargs=dict(acronym=group.acronym))
url = urlreverse('group_reset_charter_milestones', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
# normal get
@ -809,7 +813,7 @@ class MilestoneTests(TestCase):
def test_ajax_search_docs(self):
draft = make_test_data()
r = self.client.get(urlreverse("wg_ajax_search_docs", kwargs=dict(acronym=draft.group.acronym)),
r = self.client.get(urlreverse("group_ajax_search_docs", kwargs=dict(group_type=draft.group.type_id, acronym=draft.group.acronym)),
dict(q=draft.name))
self.assertEqual(r.status_code, 200)
data = json.loads(r.content)
@ -821,7 +825,7 @@ class CustomizeWorkflowTests(TestCase):
group = Group.objects.get(acronym="mars")
url = urlreverse('ietf.wginfo.edit.customize_workflow', kwargs=dict(acronym=group.acronym))
url = urlreverse('ietf.wginfo.edit.customize_workflow', kwargs=dict(group_type=group.type_id, acronym=group.acronym))
login_testing_unauthorized(self, "secretary", url)
state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc")

View file

@ -6,7 +6,7 @@ from django.views.generic import RedirectView
from ietf.wginfo import views, edit, milestones
urlpatterns = patterns('',
(r'^$', views.active_wgs),
(r'^$', views.active_groups),
(r'^summary.txt', RedirectView.as_view(url='/wg/1wg-summary.txt')),
(r'^summary-by-area.txt', RedirectView.as_view(url='/wg/1wg-summary.txt')),
(r'^summary-by-acronym.txt', RedirectView.as_view(url='/wg/1wg-summary-by-acronym.txt')),
@ -16,20 +16,20 @@ urlpatterns = patterns('',
(r'^1wg-charters-by-acronym.txt', views.wg_charters_by_acronym),
(r'^chartering/$', views.chartering_wgs),
(r'^bofs/$', views.bofs),
(r'^chartering/create/$', edit.edit, {'action': "charter"}, "wg_create"),
(r'^chartering/create/$', edit.edit, {'action': "charter"}, "group_create"),
(r'^bofs/create/$', edit.edit, {'action': "create"}, "bof_create"),
(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-]+)/$', views.group_documents, None, "group_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-]+)/init-charter/', edit.submit_initial_charter),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/history/$', views.history),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/deps/dot/$', views.dependencies_dot),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/deps/pdf/$', views.dependencies_pdf),
(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>[a-zA-Z0-9-]+)/conclude/$', edit.conclude),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/$', milestones.edit_milestones, {'milestone_set': "current"}, "group_edit_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "group_edit_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "group_reset_charter_milestones"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "group_ajax_search_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/workflow/$', edit.customize_workflow),
)

View file

@ -36,10 +36,9 @@ import os
import itertools
from tempfile import mkstemp
from django.shortcuts import get_object_or_404, render_to_response
from django.shortcuts import get_object_or_404, render
from django.template.loader import render_to_string
from django.template import RequestContext
from django.http import HttpResponse
from django.http import HttpResponse, Http404
from django.conf import settings
from django.core.urlresolvers import reverse as urlreverse
from django.views.decorators.cache import cache_page
@ -86,7 +85,9 @@ def fill_in_charter_info(group, include_drafts=False):
def extract_last_name(role):
return role.person.name_parts()[3]
def wg_summary_area(request):
def wg_summary_area(request, group_type):
if group_type != "wg":
raise Http404
areas = Group.objects.filter(type="area", state="active").order_by("name")
for area in areas:
area.ads = sorted(roles(area, "ad"), key=extract_last_name)
@ -96,21 +97,25 @@ def wg_summary_area(request):
areas = [a for a in areas if a.groups]
return render_to_response('wginfo/1wg-summary.txt',
{ 'areas': areas },
content_type='text/plain; charset=UTF-8')
return render(request, 'wginfo/1wg-summary.txt',
{ 'areas': areas },
content_type='text/plain; charset=UTF-8')
def wg_summary_acronym(request):
def wg_summary_acronym(request, group_type):
if group_type != "wg":
raise Http404
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 = sorted(roles(group, "chair"), key=extract_last_name)
return render_to_response('wginfo/1wg-summary-by-acronym.txt',
{ 'areas': areas,
'groups': groups },
content_type='text/plain; charset=UTF-8')
return render(request, 'wginfo/1wg-summary-by-acronym.txt',
{ 'areas': areas,
'groups': groups },
content_type='text/plain; charset=UTF-8')
def wg_charters(request):
def wg_charters(request, group_type):
if group_type != "wg":
raise Http404
areas = Group.objects.filter(type="area", state="active").order_by("name")
for area in areas:
area.ads = sorted(roles(area, "ad"), key=extract_last_name)
@ -118,11 +123,13 @@ def wg_charters(request):
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 },
content_type='text/plain; charset=UTF-8')
return render(request, 'wginfo/1wg-charters.txt',
{ 'areas': areas },
content_type='text/plain; charset=UTF-8')
def wg_charters_by_acronym(request):
def wg_charters_by_acronym(request, group_type):
if group_type != "wg":
raise Http404
areas = dict((a.id, a) for a in Group.objects.filter(type="area", state="active").order_by("name"))
for area in areas.itervalues():
@ -132,9 +139,16 @@ def wg_charters_by_acronym(request):
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 },
content_type='text/plain; charset=UTF-8')
return render(request, 'wginfo/1wg-charters-by-acronym.txt',
{ 'groups': groups },
content_type='text/plain; charset=UTF-8')
def active_groups(request, group_type):
if group_type == "wg":
return active_wgs(request)
elif group_type == "rg":
return active_rgs(request)
raise Http404
def active_wgs(request):
areas = Group.objects.filter(type="area", state="active").order_by("name")
@ -148,23 +162,32 @@ def active_wgs(request):
for group in area.groups:
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
return render_to_response('wginfo/active_wgs.html', {'areas':areas}, RequestContext(request))
return render(request, 'wginfo/active_wgs.html', { 'areas':areas })
def bofs(request):
groups = Group.objects.filter(type="wg", state="bof")
return render_to_response('wginfo/bofs.html',dict(groups=groups), RequestContext(request))
def active_rgs(request):
irtf = Group.objects.get(acronym="irtf")
irtf.chair = roles(irtf, "chair").first()
def chartering_wgs(request):
groups = Group.objects.filter(type="rg", state="active").order_by("acronym")
for group in groups:
group.chairs = sorted(roles(group, "chair"), key=extract_last_name)
return render(request, 'wginfo/active_rgs.html', { 'irtf': irtf, 'groups': groups })
def bofs(request, group_type):
groups = Group.objects.filter(type=group_type, state="bof")
return render(request, 'wginfo/bofs.html',dict(groups=groups))
def chartering_wgs(request, group_type):
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")
groups = Group.objects.filter(type=group_type, charter__states__in=charter_states).select_related("state", "charter")
for g in groups:
g.chartering_type = get_chartering_type(g.charter)
return render_to_response('wginfo/chartering_wgs.html',
dict(charter_states=charter_states,
groups=groups),
RequestContext(request))
return render(request, 'wginfo/chartering_wgs.html',
dict(charter_states=charter_states,
groups=groups))
def construct_group_menu_context(request, group, selected, others):
@ -175,16 +198,16 @@ def construct_group_menu_context(request, group, selected, others):
is_ad_or_secretariat = has_role(request.user, ("Area Director", "Secretariat"))
if group.state_id != "proposed" and (is_chair or is_ad_or_secretariat):
actions.append((u"Add or edit milestones", urlreverse("wg_edit_milestones", kwargs=dict(acronym=group.acronym))))
actions.append((u"Add or edit milestones", urlreverse("group_edit_milestones", kwargs=dict(group_type=group.type_id, acronym=group.acronym))))
if group.state_id != "conclude" and is_ad_or_secretariat:
actions.append((u"Edit group", urlreverse("group_edit", kwargs=dict(acronym=group.acronym))))
actions.append((u"Edit group", urlreverse("group_edit", kwargs=dict(group_type=group.type_id, acronym=group.acronym))))
if is_chair or is_ad_or_secretariat:
actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym))))
actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(group_type=group.type_id, acronym=group.acronym))))
if group.state_id in ("active", "dormant") and is_ad_or_secretariat:
actions.append((u"Request closing group", urlreverse("wg_conclude", kwargs=dict(acronym=group.acronym))))
actions.append((u"Request closing group", urlreverse("ietf.wginfo.edit.conclude", kwargs=dict(group_type=group.type_id, acronym=group.acronym))))
d = {
"group": group,
@ -229,22 +252,22 @@ def search_for_group_documents(group):
return docs, meta, docs_related, meta_related
def group_documents(request, acronym):
group = get_object_or_404(Group, type="wg", acronym=acronym)
def group_documents(request, group_type, acronym):
group = get_object_or_404(Group, type=group_type, acronym=acronym)
docs, meta, docs_related, meta_related = search_for_group_documents(group)
return render_to_response('wginfo/group_documents.html',
construct_group_menu_context(request, group, "documents", {
return render(request, '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):
def group_documents_txt(request, group_type, acronym):
"""Return tabulator-separated rows with documents for group."""
group = get_object_or_404(Group, type="wg", acronym=acronym)
group = get_object_or_404(Group, type=group_type, acronym=acronym)
docs, meta, docs_related, meta_related = search_for_group_documents(group)
@ -267,8 +290,8 @@ def group_documents_txt(request, acronym):
return HttpResponse(u"\n".join(rows), content_type='text/plain; charset=UTF-8')
def group_charter(request, acronym):
group = get_object_or_404(Group, type="wg", acronym=acronym)
def group_charter(request, group_type, acronym):
group = get_object_or_404(Group, type=group_type, acronym=acronym)
fill_in_charter_info(group, include_drafts=False)
group.delegates = roles(group, "delegate")
@ -276,22 +299,28 @@ def group_charter(request, acronym):
e = group.latest_event(type__in=("changed_state", "requested_close",))
requested_close = group.state_id != "conclude" and e and e.type == "requested_close"
return render_to_response('wginfo/group_charter.html',
construct_group_menu_context(request, group, "charter", {
"milestones_in_review": group.groupmilestone_set.filter(state="review"),
"requested_close": requested_close,
}), RequestContext(request))
long_group_types = dict(
wg="Working Group",
rg="Research Group",
)
return render(request, 'wginfo/group_charter.html',
construct_group_menu_context(request, group, "charter", {
"milestones_in_review": group.groupmilestone_set.filter(state="review"),
"requested_close": requested_close,
"long_group_type":long_group_types.get(group_type, "Group")
}))
def history(request, acronym):
def history(request, group_type, acronym):
group = get_object_or_404(Group, acronym=acronym)
events = group.groupevent_set.all().select_related('by').order_by('-time', '-id')
return render_to_response('wginfo/history.html',
construct_group_menu_context(request, group, "history", {
return render(request, 'wginfo/history.html',
construct_group_menu_context(request, group, "history", {
"events": events,
}), RequestContext(request))
}))
def nodename(name):
@ -411,7 +440,7 @@ def make_dot(group):
dict( nodes=nodes, edges=edges )
)
def dependencies_dot(request, acronym):
def dependencies_dot(request, group_type, acronym):
group = get_object_or_404(Group, acronym=acronym)
@ -420,7 +449,7 @@ def dependencies_dot(request, acronym):
)
@cache_page ( 60 * 60 )
def dependencies_pdf(request, acronym):
def dependencies_pdf(request, group_type, acronym):
group = get_object_or_404(Group, acronym=acronym)