From ad357e00686408ec0bd5da92aaf4ac6c59b454af Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Sat, 22 Mar 2014 13:11:23 +0000 Subject: [PATCH] Parameterize the in /wg/ 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 --- ietf/community/display.py | 2 +- ietf/doc/views_doc.py | 2 +- ietf/templates/base/left_menu.html | 4 +- ietf/templates/doc/document_charter.html | 4 +- .../iesg/milestones_needing_review.html | 2 +- ietf/templates/wginfo/active_rgs.html | 33 +++ ietf/templates/wginfo/active_wgs.html | 2 +- ietf/templates/wginfo/bofs.html | 4 +- ietf/templates/wginfo/chartering_wgs.html | 4 +- ietf/templates/wginfo/conclude.html | 6 +- ietf/templates/wginfo/customize_workflow.html | 2 +- ietf/templates/wginfo/edit.html | 14 +- ietf/templates/wginfo/edit_milestones.html | 6 +- ietf/templates/wginfo/group_base.html | 8 +- ietf/templates/wginfo/group_charter.html | 10 +- ietf/templates/wginfo/milestone_form.html | 2 +- .../wginfo/reset_charter_milestones.html | 2 +- ietf/urls.py | 2 +- ietf/wginfo/edit.py | 208 +++++++++--------- ietf/wginfo/feeds.py | 4 +- ietf/wginfo/mails.py | 10 +- ietf/wginfo/milestones.py | 16 +- ietf/wginfo/tests.py | 56 ++--- ietf/wginfo/urls.py | 18 +- ietf/wginfo/views.py | 137 +++++++----- 25 files changed, 311 insertions(+), 247 deletions(-) create mode 100644 ietf/templates/wginfo/active_rgs.html diff --git a/ietf/community/display.py b/ietf/community/display.py index b5438d81f..d42769597 100644 --- a/ietf/community/display.py +++ b/ietf/community/display.py @@ -88,7 +88,7 @@ class WGField(DisplayField): if raw: return document.group.acronym else: - return '%s' % (urlreverse('wg_docs', kwargs={'acronym':document.group.acronym}), document.group.acronym) if (document.group and document.group.acronym != 'none') else '' + return '%s' % (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): diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index 8ac502678..7248d22e2 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -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 = "%s" % (urlreverse("wg_docs", kwargs=dict(acronym=doc.group.acronym)), submission) + submission = "%s" % (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 diff --git a/ietf/templates/base/left_menu.html b/ietf/templates/base/left_menu.html index f9b1886b4..6f70f4ec2 100644 --- a/ietf/templates/base/left_menu.html +++ b/ietf/templates/base/left_menu.html @@ -73,8 +73,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  • Active WGs
  • -
  • Chartering WGs
  • -
  • BoFs
  • +
  • Chartering WGs
  • +
  • BoFs
  • Concluded WGs
  • Non-WG Lists
  • diff --git a/ietf/templates/doc/document_charter.html b/ietf/templates/doc/document_charter.html index 351872718..73c272f3e 100644 --- a/ietf/templates/doc/document_charter.html +++ b/ietf/templates/doc/document_charter.html @@ -25,7 +25,7 @@ {% if snapshot %}Snapshot of{% endif %} {% if doc.get_state_slug != "approved" %}Proposed{% endif %} Charter for "{{ group.name }}" - ({{ group.acronym }}) {{ group.type.name }} + ({{ group.acronym }}) {{ group.type.name }} @@ -132,7 +132,7 @@ {% if not snapshot and chartering %}

    Proposed Milestones {% if user|has_role:"Area Director,Secretariat" %} -Edit charter milestones +Edit charter milestones {% endif %}

    diff --git a/ietf/templates/iesg/milestones_needing_review.html b/ietf/templates/iesg/milestones_needing_review.html index 3cca9584b..829fcce99 100644 --- a/ietf/templates/iesg/milestones_needing_review.html +++ b/ietf/templates/iesg/milestones_needing_review.html @@ -15,7 +15,7 @@ div.milestones-for-group { margin: 0.5em 0; } {% for g in ad.groups_needing_review %} -
    {{ g.name }} ({{ g.acronym }}) has new milestones:
    +
    {{ g.name }} ({{ g.acronym }}) has new milestones:
    {% include "wginfo/milestones.html" with milestones=g.milestones_needing_review %} diff --git a/ietf/templates/wginfo/active_rgs.html b/ietf/templates/wginfo/active_rgs.html new file mode 100644 index 000000000..93b6769a0 --- /dev/null +++ b/ietf/templates/wginfo/active_rgs.html @@ -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 %} +

    Active IRTF Research Groups

    + +

    IRTF Chair:

    + +
    + {{ irtf.chair.person.plain_name }} +
    + +

    Active Research Groups:

    + +
    +
    + {% for group in groups %} + + + + + + {% endfor %} +
    {{ group.acronym }}{{ group.name }}{% for chair in group.chairs %}{{ chair.person.plain_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
    + + +{% endblock %} diff --git a/ietf/templates/wginfo/active_wgs.html b/ietf/templates/wginfo/active_wgs.html index 4d88435fa..88a6e694d 100644 --- a/ietf/templates/wginfo/active_wgs.html +++ b/ietf/templates/wginfo/active_wgs.html @@ -80,7 +80,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% for group in area.groups %} - + diff --git a/ietf/templates/wginfo/bofs.html b/ietf/templates/wginfo/bofs.html index 8123cc6bd..04fafa646 100644 --- a/ietf/templates/wginfo/bofs.html +++ b/ietf/templates/wginfo/bofs.html @@ -10,7 +10,7 @@

    Groups in the BoF state

    {% if user|has_role:"Area Director,Secretariat" %} -

    Create a new BoF

    +

    Create a new BoF

    {% endif %} {% if not groups %} @@ -25,7 +25,7 @@ {% for g in groups %} diff --git a/ietf/templates/wginfo/customize_workflow.html b/ietf/templates/wginfo/customize_workflow.html index 069e319a9..e240e53b0 100644 --- a/ietf/templates/wginfo/customize_workflow.html +++ b/ietf/templates/wginfo/customize_workflow.html @@ -34,7 +34,7 @@

    Customize Workflow for {{ group.acronym }} {{ group.type.name }}

    Below you can customize the draft states and tags used in the -{{ group.acronym }} {{ group.type.name }}. Note that some states are +{{ group.acronym }} {{ group.type.name }}. Note that some states are mandatory for group operation and cannot be deactivated.

    You can see the default Working Group I-D State Diagram diff --git a/ietf/templates/wginfo/edit.html b/ietf/templates/wginfo/edit.html index 8e21b090d..a706360dd 100644 --- a/ietf/templates/wginfo/edit.html +++ b/ietf/templates/wginfo/edit.html @@ -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 %}

    {% 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 %}

    @@ -68,7 +68,7 @@ so. New accounts can be created here.
    {{ group.acronym }}{{ group.acronym }} {% for ad in area.ads %}{% if ad.person_id == group.ad_id %}{% endif %}{% endfor %} {{ group.name }} {% for chair in group.chairs %}{{ chair.person.plain_name }}{% if not forloop.last %}, {% endif %}{% endfor %}
    - {{ g.acronym }} + {{ g.acronym }} {{ g.name }} diff --git a/ietf/templates/wginfo/chartering_wgs.html b/ietf/templates/wginfo/chartering_wgs.html index 00daeb90f..8bced2a91 100644 --- a/ietf/templates/wginfo/chartering_wgs.html +++ b/ietf/templates/wginfo/chartering_wgs.html @@ -12,7 +12,7 @@ {% for s in charter_states %}{% if not forloop.first %}, {% if forloop.last %}or {% endif %}{% endif %}{{ s.name }}{% endfor %}.

    {% if user|has_role:"Area Director,Secretariat" %} -

    Start chartering new WG

    +

    Start chartering new WG

    {% endif %} {% if not groups %} @@ -28,7 +28,7 @@ {% for g in groups %}
    - {{ g.acronym }} + {{ g.acronym }} {{ g.name }} diff --git a/ietf/templates/wginfo/conclude.html b/ietf/templates/wginfo/conclude.html index 0812e64d5..705dd4989 100644 --- a/ietf/templates/wginfo/conclude.html +++ b/ietf/templates/wginfo/conclude.html @@ -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 %} -

    Request closing of {{ wg.acronym }} {{ wg.type.name }}

    +

    Request closing of {{ group.acronym }} {{ group.type.name }}

    Please provide instructions regarding the disposition of each @@ -29,7 +29,7 @@ form.conclude .actions { {{ form.as_table }}

    - Cancel + Cancel
    {% if action == "edit" %} - Cancel + Cancel {% else %} {% if action == "charter" %} diff --git a/ietf/templates/wginfo/edit_milestones.html b/ietf/templates/wginfo/edit_milestones.html index 676d47b56..5533e6ff6 100644 --- a/ietf/templates/wginfo/edit_milestones.html +++ b/ietf/templates/wginfo/edit_milestones.html @@ -42,7 +42,7 @@ tr.milestone.add { font-style: italic; }

    Links: - {{ group.acronym }} {{ group.type.name }} + {{ group.acronym }} {{ group.type.name }} - {{ group.charter.canonical_name }}

    @@ -58,7 +58,7 @@ Director. {% if can_reset %}

    -You can reset +You can reset this list to the milestones currently in use for the {{ group.acronym }} {{ group.type.name }}.

    {% endif %} @@ -91,7 +91,7 @@ this list to the milestones currently in use for the {{ group.acronym }} {{
    diff --git a/ietf/templates/wginfo/group_base.html b/ietf/templates/wginfo/group_base.html index d6dfea8bc..ead337bba 100644 --- a/ietf/templates/wginfo/group_base.html +++ b/ietf/templates/wginfo/group_base.html @@ -66,10 +66,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    - Documents | - Charter | - History - | Dependency Graph + Documents | + Charter | + History + | Dependency Graph {% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %} | List Archive » {% endif %} diff --git a/ietf/templates/wginfo/group_charter.html b/ietf/templates/wginfo/group_charter.html index 8aaa27317..585b37d1e 100644 --- a/ietf/templates/wginfo/group_charter.html +++ b/ietf/templates/wginfo/group_charter.html @@ -26,7 +26,7 @@ is occasionally incorrect. Acronym:{{ group.acronym }} - {% if group.parent %} + {% if group.parent and group.parent.type_id == "area" %} {{ group.parent.type.name }}:{{ group.parent.name }} ({{ group.parent.acronym }}) {% endif %} @@ -47,7 +47,7 @@ is occasionally incorrect. {% else %} none {% if user|has_role:"Area Director,Secretariat" %} - - Submit Charter + - Submit Charter {% endif %} {% endif %} @@ -64,6 +64,7 @@ is occasionally incorrect. + {% if group.parent.type_id == "area" %} Area Director: {% if group.areadirector %} @@ -71,6 +72,7 @@ is occasionally incorrect. {% else %}?{% endif %} + {% endif %} {% if group.techadvisors %} @@ -142,7 +144,7 @@ is occasionally incorrect. {% with group.groupurl_set.all as urls %} {% if urls %} -

    In addition to the charter maintained by the IETF Secretariat, there is additional information about this working group on the Web at: +

    In addition to the charter, there is additional information about this group on the Web at: {% for url in urls %} {{ url.name }}{% if not forloop.last %}, {% endif %} {% endfor %} @@ -150,7 +152,7 @@ is occasionally incorrect. {% endif %} {% endwith %} -

    Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} Working Group

    +

    Charter for {% if group.state_id == "proposed" %}Proposed{% endif %} {{ long_group_type }}

    {{ group.charter_text|escape|format_charter|safe }}

    diff --git a/ietf/templates/wginfo/milestone_form.html b/ietf/templates/wginfo/milestone_form.html index c0b261ebf..59d3be29a 100644 --- a/ietf/templates/wginfo/milestone_form.html +++ b/ietf/templates/wginfo/milestone_form.html @@ -26,7 +26,7 @@ Drafts: - + {{ form.docs.errors }} diff --git a/ietf/templates/wginfo/reset_charter_milestones.html b/ietf/templates/wginfo/reset_charter_milestones.html index a905d1047..6ee387399 100644 --- a/ietf/templates/wginfo/reset_charter_milestones.html +++ b/ietf/templates/wginfo/reset_charter_milestones.html @@ -29,7 +29,7 @@ {% endfor %}
    - Back + Back
    diff --git a/ietf/urls.py b/ietf/urls.py index 06427c74c..909245383 100644 --- a/ietf/urls.py +++ b/ietf/urls.py @@ -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(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')), diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 7f9138341..a37d4dd95 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -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 %(new)s from %(old)s" - if new_wg: + if new_group: entry = "%(attr)s changed to %(new)s" 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[\w\d:#@%/;$()~_?\+-=\\\.&]+)( \((?P.+)\))?', 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)) + }) diff --git a/ietf/wginfo/feeds.py b/ietf/wginfo/feeds.py index 8ec8a5fca..8b966c2bd 100644 --- a/ietf/wginfo/feeds.py +++ b/ietf/wginfo/feeds.py @@ -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 diff --git a/ietf/wginfo/mails.py b/ietf/wginfo/mails.py index d4546197e..afda5f7b5 100644 --- a/ietf/wginfo/mails.py +++ b/ietf/wginfo/mails.py @@ -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): diff --git a/ietf/wginfo/milestones.py b/ietf/wginfo/milestones.py index d628a52b4..723c4087c 100644 --- a/ietf/wginfo/milestones.py +++ b/ietf/wginfo/milestones.py @@ -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') diff --git a/ietf/wginfo/tests.py b/ietf/wginfo/tests.py index 018a9068d..8944948f8 100644 --- a/ietf/wginfo/tests.py +++ b/ietf/wginfo/tests.py @@ -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") diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index fb749c460..627144a14 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -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[a-zA-Z0-9-]+)/documents/txt/$', views.group_documents_txt), - (r'^(?P[a-zA-Z0-9-]+)/$', views.group_documents, None, "wg_docs"), + (r'^(?P[a-zA-Z0-9-]+)/$', views.group_documents, None, "group_docs"), (r'^(?P[a-zA-Z0-9-]+)/charter/$', views.group_charter, None, 'group_charter'), - (r'^(?P[a-zA-Z0-9-]+)/init-charter/', edit.submit_initial_charter, None, "wg_init_charter"), + (r'^(?P[a-zA-Z0-9-]+)/init-charter/', edit.submit_initial_charter), (r'^(?P[a-zA-Z0-9-]+)/history/$', views.history), (r'^(?P[a-zA-Z0-9-]+)/deps/dot/$', views.dependencies_dot), (r'^(?P[a-zA-Z0-9-]+)/deps/pdf/$', views.dependencies_pdf), (r'^(?P[a-zA-Z0-9-]+)/edit/$', edit.edit, {'action': "edit"}, "group_edit"), - (r'^(?P[a-zA-Z0-9-]+)/conclude/$', edit.conclude, None, "wg_conclude"), - (r'^(?P[a-zA-Z0-9-]+)/milestones/$', milestones.edit_milestones, {'milestone_set': "current"}, "wg_edit_milestones"), - (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "wg_edit_charter_milestones"), - (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "wg_reset_charter_milestones"), - (r'^(?P[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "wg_ajax_search_docs"), + (r'^(?P[a-zA-Z0-9-]+)/conclude/$', edit.conclude), + (r'^(?P[a-zA-Z0-9-]+)/milestones/$', milestones.edit_milestones, {'milestone_set': "current"}, "group_edit_milestones"), + (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/$', milestones.edit_milestones, {'milestone_set': "charter"}, "group_edit_charter_milestones"), + (r'^(?P[a-zA-Z0-9-]+)/milestones/charter/reset/$', milestones.reset_charter_milestones, None, "group_reset_charter_milestones"), + (r'^(?P[a-zA-Z0-9-]+)/ajax/searchdocs/$', milestones.ajax_search_docs, None, "group_ajax_search_docs"), (r'^(?P[a-zA-Z0-9-]+)/workflow/$', edit.customize_workflow), ) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 678be6d10..0e451cdc6 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -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)