From 6d17ab8015300760370e2ff50bf0a54ba06d03c6 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 3 Sep 2013 16:51:22 +0000 Subject: [PATCH 01/20] Port wginfo/ to new schema, delete some dead code. Missing tests and still a little bit of cruft left from views in other modules. - Legacy-Id: 6084 --- ietf/templates/doc/document_charter.html | 2 +- .../wginfo/1wg-charters-by-acronym.txt | 8 +- ietf/templates/wginfo/1wg-charters.txt | 9 +- .../wginfo/1wg-summary-by-acronym.txt | 12 +- ietf/templates/wginfo/1wg-summary.txt | 19 +- .../{wg-dirREDESIGN.html => active_wgs.html} | 0 ietf/templates/wginfo/bofs.html | 2 +- ietf/templates/wginfo/chartering_wgs.html | 2 +- ietf/templates/wginfo/conclude.html | 2 +- ietf/templates/wginfo/edit.html | 2 +- ietf/templates/wginfo/edit_milestones.html | 4 +- ietf/templates/wginfo/group_base.html | 99 ++++++ ietf/templates/wginfo/group_charter.html | 171 +++++++++++ ietf/templates/wginfo/group_documents.html | 18 ++ ietf/templates/wginfo/group_entry.txt | 4 + .../wginfo/group_entry_with_charter.txt | 48 +++ ietf/templates/wginfo/history.html | 9 +- ietf/templates/wginfo/wg-charter.txt | 47 --- ietf/templates/wginfo/wg-charterREDESIGN.txt | 47 --- ietf/templates/wginfo/wg-dir.html | 99 ------ ietf/templates/wginfo/wg_base.html | 4 +- ietf/templates/wginfo/wg_charter.html | 182 ----------- ietf/templates/wginfo/wg_documents.html | 50 ---- ietf/templates/wginfo/wg_documents.txt | 2 - ietf/templates/wginfo/wg_documents_entry.txt | 1 - ietf/templates/wginfo/wg_summary.txt | 5 - ietf/wgcharter/feeds.py | 4 +- ietf/wgcharter/mails.py | 2 +- ietf/wginfo/edit.py | 4 +- ietf/wginfo/mails.py | 6 +- ietf/wginfo/milestones.py | 2 +- ietf/wginfo/tests.py | 2 +- ietf/wginfo/urls.py | 10 +- ietf/wginfo/views.py | 283 +++++++++++------- 34 files changed, 563 insertions(+), 598 deletions(-) rename ietf/templates/wginfo/{wg-dirREDESIGN.html => active_wgs.html} (100%) create mode 100644 ietf/templates/wginfo/group_base.html create mode 100644 ietf/templates/wginfo/group_charter.html create mode 100644 ietf/templates/wginfo/group_documents.html create mode 100644 ietf/templates/wginfo/group_entry.txt create mode 100644 ietf/templates/wginfo/group_entry_with_charter.txt delete mode 100644 ietf/templates/wginfo/wg-charter.txt delete mode 100644 ietf/templates/wginfo/wg-charterREDESIGN.txt delete mode 100644 ietf/templates/wginfo/wg-dir.html delete mode 100644 ietf/templates/wginfo/wg_charter.html delete mode 100644 ietf/templates/wginfo/wg_documents.html delete mode 100644 ietf/templates/wginfo/wg_documents.txt delete mode 100644 ietf/templates/wginfo/wg_documents_entry.txt delete mode 100644 ietf/templates/wginfo/wg_summary.txt diff --git a/ietf/templates/doc/document_charter.html b/ietf/templates/doc/document_charter.html index fb23abb2c..885d8a4a4 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 }} diff --git a/ietf/templates/wginfo/1wg-charters-by-acronym.txt b/ietf/templates/wginfo/1wg-charters-by-acronym.txt index 247e1466c..bad8939cd 100644 --- a/ietf/templates/wginfo/1wg-charters-by-acronym.txt +++ b/ietf/templates/wginfo/1wg-charters-by-acronym.txt @@ -1,4 +1,4 @@ -{% load ietf_filters %}{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{{ wg }} -{% endif %}{% endif %}{% endfor %} -{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{% include "wginfo/wg-charter.txt" %} -{% endif %}{% endif %}{% endfor %} +{% autoescape off %}{% load ietf_filters %}{% for group in groups %}{{ group.acronym }} +{% endfor %} + +{% for group in groups %}{% include "wginfo/group_entry_with_charter.txt" %}{% endfor %}{% endautoescape %} diff --git a/ietf/templates/wginfo/1wg-charters.txt b/ietf/templates/wginfo/1wg-charters.txt index 4e5e70941..767dd1bb0 100644 --- a/ietf/templates/wginfo/1wg-charters.txt +++ b/ietf/templates/wginfo/1wg-charters.txt @@ -1,7 +1,6 @@ -{% load ietf_filters %}{% regroup wg_list|dictsort:"area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.name" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %}{{ wg }} -{% endif %}{% endif %}{% endfor %}{% endfor %} +{% autoescape off %}{% load ietf_filters %}{% for area in areas %}{% for group in area.groups %}{{ group.acronym }} +{% endfor %}{% endfor %} + +{% for area in areas %}{% for group in area.groups %}{% include "wginfo/group_entry_with_charter.txt" %}{% endfor %}{% endfor %}{% endautoescape %} -{% regroup wg_list|dictsort:"area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.name" %}{% if wg.area.area.status_id == 1 and wg.area.area.acronym != "iesg" %}{% if wg.start_date %} -{% include "wginfo/wg-charter.txt" %} -{% endif %}{% endif %}{% endfor %}{% endfor %} diff --git a/ietf/templates/wginfo/1wg-summary-by-acronym.txt b/ietf/templates/wginfo/1wg-summary-by-acronym.txt index d1a0f46be..028d5fd0e 100644 --- a/ietf/templates/wginfo/1wg-summary-by-acronym.txt +++ b/ietf/templates/wginfo/1wg-summary-by-acronym.txt @@ -1,10 +1,10 @@ -{% load ietf_filters %} +{% autoescape off %}{% load ietf_filters %} IETF Working Group Summary (By Acronym) The following Area Abbreviations are used in this document -{% for area in area_list %} -{{ area|upper }} - {{ area.area_acronym.name }}{% endfor %} -{% for wg in wg_list|dictsort:"group_acronym.acronym" %}{% if wg.start_date %} -{{ wg.group_acronym.name|safe }} ({{ wg }}) -- {{ wg.area.area|upper }} -{% include "wginfo/wg_summary.txt" %}{% endif %}{% endfor %} +{% for area in areas %} +{{ area.acronym|upper }} - {{ area.name }}{% endfor %} +{% for group in groups %} +{{ group.name }} ({{ group.acronym }}) -- {{ group.parent.acronym|upper }} +{% include "wginfo/group_entry.txt" %}{% endfor %}{% endautoescape %} diff --git a/ietf/templates/wginfo/1wg-summary.txt b/ietf/templates/wginfo/1wg-summary.txt index 55d76d1e2..8073c03c7 100644 --- a/ietf/templates/wginfo/1wg-summary.txt +++ b/ietf/templates/wginfo/1wg-summary.txt @@ -1,8 +1,11 @@ -{% load ietf_filters %} IETF Working Group Summary (By Area) -{% regroup wg_list|dictsort:"area.area.area_acronym.acronym" by area.area as wga_list %}{% for area in wga_list %}{% for wg in area.list|dictsort:"group_acronym.acronym" %}{% ifequal wg.area.area.status_id 1 %}{% if forloop.first %} -{{ wg.area_acronym.name }} ({{ wg.area_acronym }}) -{{ wg.area_acronym.name|dashify }}------{% for ad in wg.area_directors %} - {{ ad.person }} <{{ ad.person.email.1 }}>{% endfor %} -{% endif %}{% if wg.start_date %} -{{ wg.group_acronym.name|safe }} ({{ wg }}) -{% include "wginfo/wg_summary.txt" %}{% endif %}{% endifequal %}{% endfor %}{% endfor %} +{% autoescape off %}{% load ietf_filters %} + IETF Working Group Summary (By Area) + + +{% for area in areas %}{{ area.name }} ({{ area.acronym }}) +{{ area.name|dashify }}------{% for ad in area.ads %} + {{ ad.person }} <{{ ad.address }}>{% endfor %} + +{% for group in area.groups %}{{ group.name }} ({{ group.acronym }}) +{% include "wginfo/group_entry.txt" %} +{% endfor %}{% endfor %}{% endautoescape %} diff --git a/ietf/templates/wginfo/wg-dirREDESIGN.html b/ietf/templates/wginfo/active_wgs.html similarity index 100% rename from ietf/templates/wginfo/wg-dirREDESIGN.html rename to ietf/templates/wginfo/active_wgs.html diff --git a/ietf/templates/wginfo/bofs.html b/ietf/templates/wginfo/bofs.html index 60df23342..3d2d5134a 100644 --- a/ietf/templates/wginfo/bofs.html +++ b/ietf/templates/wginfo/bofs.html @@ -25,7 +25,7 @@ {% for g in groups %} diff --git a/ietf/templates/wginfo/edit.html b/ietf/templates/wginfo/edit.html index ad77789a9..2ca32f710 100644 --- a/ietf/templates/wginfo/edit.html +++ b/ietf/templates/wginfo/edit.html @@ -66,7 +66,7 @@ Create new WG or BoF
- {{ g.acronym }} + {{ g.acronym }} {{ g.name }} diff --git a/ietf/templates/wginfo/chartering_wgs.html b/ietf/templates/wginfo/chartering_wgs.html index 291daa6a5..67255ca0b 100644 --- a/ietf/templates/wginfo/chartering_wgs.html +++ b/ietf/templates/wginfo/chartering_wgs.html @@ -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 d233057c1..76391dcef 100644 --- a/ietf/templates/wginfo/conclude.html +++ b/ietf/templates/wginfo/conclude.html @@ -28,7 +28,7 @@ form.conclude .actions { {{ form.as_table }}
- Back + Back
{% ifequal action "edit" %} - Back + Back {% else %} {% ifequal action "charter" %} diff --git a/ietf/templates/wginfo/edit_milestones.html b/ietf/templates/wginfo/edit_milestones.html index ccbf0b3dd..e3a3a8a12 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 }}

@@ -91,7 +91,7 @@ this list to the milestones currently in use for the {{ group.acronym }} {{
- Cancel + Cancel
diff --git a/ietf/templates/wginfo/group_base.html b/ietf/templates/wginfo/group_base.html new file mode 100644 index 000000000..bd5f47138 --- /dev/null +++ b/ietf/templates/wginfo/group_base.html @@ -0,0 +1,99 @@ +{% extends "base.html" %} +{% comment %} +Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +All rights reserved. Contact: Pasi Eronen + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * Neither the name of the Nokia Corporation and/or its + subsidiary(-ies) nor the names of its contributors may be used + to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +{% endcomment %} +{% load ietf_filters wgchairs_tags %} +{% block title %}{{ group.name }} ({{ group.acronym }}) - {% block group_subtitle %}{% endblock %}{% endblock %} + +{% block morecss %} +.ietf-navset { + background:#214197 url(/images/yui/sprite.png) repeat-x left -1400px; + color:white; + border:1px solid black; + padding:4px; +} +.ietf-navset .selected { font-weight:bold; padding: 0 3px; } +.ietf-navset a, .ietf-navset a:visited { color: white; padding:0 3px; } + +.ietf-group-details { float:right; padding: 4px;margin-top:16px; margin-left: 16px; } +.ietf-group-details tr { vertical-align: top; } +.ietf-concluded-bg {background-color: #F8F8D0; } +.ietf-concluded-warning { background:red;color:white;padding:2px 2px;} +.ietf-proposed-bg { } +.ietf-proposed-warning { background:green;color:white;padding:2px 2px;} +.ietf-box th { + font-weight: bold; + padding-top: 1em; + text-align: left; +} +.ietf-box tr:first-child th { + padding-top: 0; +} +{% endblock morecss %} + +{% block content %} +
+ +

{{ group.name}} ({{ group.acronym }}) + {% if group.state_id == "dormant" or group.state_id == "conclude" %}
(concluded {{ group.type.name }}){% endif %} + {% if group.state_id == "proposed" %}
(proposed {{ group.type.name }}){% endif %} +

+ +
+ Documents | + Charter | + + {% if can_manage_workflow %} + Manage workflow | + {% endif %} + + {% if can_manage_delegates %} + Manage delegations | + {% endif %} + + {% if can_manage_shepherds %} + Manage shepherds | + {% endif %} + + History | + {% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %} + List Archive » | + {% endif %} + Tools WG Page » +
+ +{% block group_content %} +{% endblock group_content %} + +
+{% endblock content %} diff --git a/ietf/templates/wginfo/group_charter.html b/ietf/templates/wginfo/group_charter.html new file mode 100644 index 000000000..fb4d448b1 --- /dev/null +++ b/ietf/templates/wginfo/group_charter.html @@ -0,0 +1,171 @@ +{% extends "wginfo/group_base.html" %} + +{% load ietf_filters %} +{% block group_subtitle %}Charter{% endblock %} + +{% block morecss %} +{{ block.super }} +h2 a.button { margin-left: 0.5em; font-size: 13px; } +{% endblock %} + +{% block group_content %} +
+ +{% if group.state_id == "conclude" %} +Note: The data for concluded WGs +is occasionally incorrect. +{% endif %} + + + + + + + + + + + + {% if group.parent %} + + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + {% if group.techadvisors %} + + + + + {% endif %} + + {% if group.editors %} + + + + + {% endif %} + + {% if group.secretaries %} + + + + + {% endif %} + + + + + + + + {% if group.state_id != "conclude" %} + + + + + + + + + + + + {% endif %} + +
Group
Name:{{ group.name }}
Acronym:{{ group.acronym }}
{{ group.parent.type.name }}:{{ group.parent.name }} ({{ group.parent.acronym }})
State:{{ group.state.name }} + {% if requested_close %} + (but in the process of being closed) + {% endif %} +
Charter: + {% if group.charter %} + {{ group.charter.name }}-{{ group.charter.rev }} ({{ group.charter.get_state.name }}) + {% else %} + none + {% if user|has_role:"Area Director,Secretariat" %} + - Submit Charter + {% endif %} + {% endif %} +
Personnel
Chair{{ group.chairs|pluralize }}: + {% for chair in group.chairs %} + {{ chair.person.plain_name }} <{{ chair.address }}>
+ {% endfor %} +
Area Director: + {% if group.areadirector %} + {{ group.areadirector.person.plain_name }} <{{ group.areadirector.address }}> + {% else %}?{% endif %} +
Tech Advisor{{ group.techadvisors|pluralize }}: + {% for techadvisor in group.techadvisors %} + {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
+ {% endfor %} +
Editor{{ group.editors|pluralize }}: + {% for editor in group.editors %} + {{ editor.person.plain_name }} <{{ editor.address }}>
+ {% endfor %} +
Secretar{{ group.secretaries|pluralize:"y,ies" }}: + {% for secretary in group.secretaries %} + {{ secretary.person.plain_name }} <{{ secretary.address }}>
+ {% endfor %} +
Mailing List
Address:{{ group.list_email|urlize }}
To Subscribe:{{ group.list_subscribe|urlize }}
Archive:{{ group.list_archive|urlize }}
Jabber Chat
Room Address:xmpp:{{ group.acronym }}@jabber.ietf.org
Logs:http://jabber.ietf.org/logs/{{ group.acronym }}/
+ +{% if user|has_role:"Area Director,Secretariat" %} +
+ {% for name, url in actions %} + {{ name }} + {% endfor %} +
+{% endif %} +
+ +{% 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: +{% for url in urls %} +{{ url.name }}{% if not forloop.last %}, {% endif %} +{% endfor %} +

+{% endif %} +{% endwith %} + +

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

+ +

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

+ +

{% if group.state_id == "proposed" %}Proposed{% endif %} Milestones + +{% if group.state_id != "proposed" %} +{% if user|has_role:"Area Director,Secretariat" or is_chair %} +Add or edit milestones +{% endif %} +{% endif %} +

+ +{% with group.milestones as milestones %} +{% include "wginfo/milestones.html" %} +{% endwith %} + +{% if milestones_in_review %} +

+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }} +currently in Area Director review.

+{% endif %} + +{% endblock %} diff --git a/ietf/templates/wginfo/group_documents.html b/ietf/templates/wginfo/group_documents.html new file mode 100644 index 000000000..a1adc68ef --- /dev/null +++ b/ietf/templates/wginfo/group_documents.html @@ -0,0 +1,18 @@ +{% extends "wginfo/group_base.html" %} + +{% block group_subtitle %}Documents{% endblock %} + +{% block group_content %} +
+ +{% include "doc/search/search_results.html" %} + +{% with docs_related as docs %}{% with meta_related as meta %}{% include "doc/search/search_results.html" %}{% endwith %}{% endwith %} + +
+{% endblock group_content %} + +{% block js %} + + +{% endblock %} diff --git a/ietf/templates/wginfo/group_entry.txt b/ietf/templates/wginfo/group_entry.txt new file mode 100644 index 000000000..c58fca075 --- /dev/null +++ b/ietf/templates/wginfo/group_entry.txt @@ -0,0 +1,4 @@ +{% for chair in group.chairs %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person.plain_name }} <{{ chair.address }}> +{% endfor %} WG Mail: {{ group.list_email }} + To Join: {{ group.list_subscribe }} + Archive: {{ group.list_archive }} diff --git a/ietf/templates/wginfo/group_entry_with_charter.txt b/ietf/templates/wginfo/group_entry_with_charter.txt new file mode 100644 index 000000000..fb904032a --- /dev/null +++ b/ietf/templates/wginfo/group_entry_with_charter.txt @@ -0,0 +1,48 @@ +{% autoescape off %}{% load ietf_filters %}{{ group.name }} ({{group.acronym}}) +{{ group.name|dashify }}{{ group.acronym|dashify }}--- + + Charter + Last Modified: {{ group.time.date|date }} + + Current Status: {{ group.state.name }} + + Chair{{ group.chairs|pluralize }}: +{% for chair in group.chairs %} {{ chair.person.name }} <{{chair.address}}> +{% endfor %} + {{ group.area.name}} Directors: +{% for ad in group.area.ads %} {{ ad.person.plain_name }} <{{ ad }}> +{% endfor %} +{% if group.areadirector %} {{ group.area.name }} Advisor: + {{ group.areadirector.person.plain_name }} <{{ group.areadirector.address }}> +{% endif %}{% if group.techadvisors %} + Tech Advisor{{ group.techadvisors|pluralize }}: +{% for techadvisor in group.techadvisors %} {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}> +{% endfor %}{% endif %}{% if group.editors %} + Editor{{ group.editors|pluralize }}: +{% for editor in group.editors %} {{ editor.person.plain_name }} <{{ editor.address}}> +{% endfor %}{% endif %}{% if group.secretaries %} + Secretar{{ group.secretaries|pluralize:"y,ies" }}: +{% for secretary in group.secretaries %} {{ secretary.person.plain_name }} <{{ secretary.address }}> +{% endfor %}{% endif %} + Mailing Lists: + General Discussion: {{ group.list_email }} + To Subscribe: {{ group.list_subscribe }} + Archive: {{ group.list_archive }} + +Description of Working Group: + + {{ group.charter_text|indent }} + +Goals and Milestones: +{% for milestone in group.milestones %} {% if milestone.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc }} +{% endfor %} +Internet-Drafts: +{% for alias in group.drafts %} - {{ alias.document.title }} [{{ alias.name }}-{{ alias.document.rev }}] ({{ alias.document.pages }} pages) +{% endfor %} +{% if group.rfcs %}Requests for Comments: +{% for alias in group.rfcs %} {{ alias.name.upper }}: {{ alias.document.title}} ({{ alias.document.pages }} pages){% for r in alias.rel %} + * {{ r.action }} {{ r.target.name|upper }}{% endfor %}{% for r in alias.invrel %} + * {% if r.relationsship == "obs" %}{{ r.inverse_action|upper }}{% else %}{{ r.action }}{% endif %} {{ r.source.canonical_name|upper }}{% endfor %} +{% endfor %} +{% else %}No Requests for Comments{% endif %} +{% endautoescape %} diff --git a/ietf/templates/wginfo/history.html b/ietf/templates/wginfo/history.html index ed86d4324..bc1926609 100644 --- a/ietf/templates/wginfo/history.html +++ b/ietf/templates/wginfo/history.html @@ -1,15 +1,16 @@ -{% extends "wginfo/wg_base.html" %} +{% extends "wginfo/group_base.html" %} {% load ietf_filters %} -{% block wg_titledetail %}History{% endblock %} +{% block group_subtitle %}History{% endblock %} -{% block wg_content %} +{% block group_content %} {% load ietf_filters %} -

WG History

+

Group History

+ {% for e in events %} diff --git a/ietf/templates/wginfo/wg-charter.txt b/ietf/templates/wginfo/wg-charter.txt deleted file mode 100644 index c0d8af0d4..000000000 --- a/ietf/templates/wginfo/wg-charter.txt +++ /dev/null @@ -1,47 +0,0 @@ -{% if USE_DB_REDESIGN_PROXY_CLASSES %}{% include "wginfo/wg-charterREDESIGN.txt" %}{% else %}{% load ietf_filters %}{{wg.group_acronym.name|safe}} ({{wg}}) -{{ wg.group_acronym.name|dashify }}{{ wg.group_acronym.acronym|dashify }}--- - - Charter - Last Modified: {{ wg.last_modified_date }} - - Current Status: {{ wg.status }} - - Chair{{ wg.chairs.count|pluralize:",s" }}: -{% for chair in wg.chairs %} {{ chair.person|safe }} <{{chair.person.email.1}}> -{% endfor %} - {{wg.area.area.area_acronym.name}} Directors: -{% for ad in wg.area_directors %} {{ ad.person|safe }} <{{ad.person.email.1}}> -{% endfor %} - {{wg.area.area.area_acronym.name}} Advisor: - {{ wg.area_director.person|safe }} <{{wg.area_director.person.email.1}}> -{% if wg.wgtechadvisor_set.count %} - Tech Advisor{{ wg.wgtechadvisor_set.count|pluralize:",s" }}: -{% for techadvisor in wg.wgtechadvisor_set.all %} {{ techadvisor.person|safe }} <{{techadvisor.person.email.1}}> -{% endfor %}{% endif %}{% if wg.wgeditor_set.count %} - Editor{{ wg.wgeditor_set.count|pluralize:",s" }}: -{% for editor in wg.wgeditor_set.all %} {{ editor.person|safe }} <{{editor.person.email.1}}> -{% endfor %}{% endif %}{% if wg.secretaries %} - Secretar{{ wg.secretaries.count|pluralize:"y,ies" }}: -{% for secretary in wg.secretaries %} {{ secretary.person|safe }} <{{secretary.person.email.1}}> -{% endfor %}{% endif %} - Mailing Lists: - General Discussion: {{ wg.email_address }} - To Subscribe: {{ wg.email_subscribe }} - Archive: {{ wg.email_archive }} - -Description of Working Group: - - {{ wg.charter_text|indent|safe }} - -Goals and Milestones: -{% for milestone in wg.milestones %} {% ifequal milestone.done 'Done' %}Done {% else %}{%ifequal milestone.expected_due_date.month 1 %}Jan{% endifequal %}{%ifequal milestone.expected_due_date.month 2 %}Feb{% endifequal %}{%ifequal milestone.expected_due_date.month 3 %}Mar{% endifequal %}{%ifequal milestone.expected_due_date.month 4 %}Apr{% endifequal %}{%ifequal milestone.expected_due_date.month 5 %}May{% endifequal %}{%ifequal milestone.expected_due_date.month 6 %}Jun{% endifequal %}{%ifequal milestone.expected_due_date.month 7 %}Jul{% endifequal %}{%ifequal milestone.expected_due_date.month 8 %}Aug{% endifequal %}{%ifequal milestone.expected_due_date.month 9 %}Sep{% endifequal %}{%ifequal milestone.expected_due_date.month 10 %}Oct{% endifequal %}{%ifequal milestone.expected_due_date.month 11 %}Nov{% endifequal %}{%ifequal milestone.expected_due_date.month 12 %}Dec{% endifequal %} {{ milestone.expected_due_date.year }}{% endifequal %} - {{ milestone.description|safe }} -{% endfor %} -Internet-Drafts: -{% for draft in wg.drafts %} - {{draft.title|safe}} [{{draft.filename}}-{{draft.revision}}] ({{ draft.txt_page_count }} pages) -{% endfor %} -{% if wg.rfcs %}Requests for Comments: -{% for rfc in wg.rfcs %} {{rfc}}: {{rfc.title|safe}} ({{ rfc.txt_page_count }} pages){% for obs in rfc.obsoletes%} - * {{obs.action}} RFC{{obs.rfc_acted_on_id}}{% endfor %}{% for obs in rfc.obsoleted_by%} - * {%ifequal obs.action 'Obsoletes'%}OBSOLETED BY{%else%}Updated by{%endifequal%} RFC{{obs.rfc_id}}{% endfor %} -{%endfor%} -{%else%}No Requests for Comments{% endif %}{% endif %} diff --git a/ietf/templates/wginfo/wg-charterREDESIGN.txt b/ietf/templates/wginfo/wg-charterREDESIGN.txt deleted file mode 100644 index a46bb0b08..000000000 --- a/ietf/templates/wginfo/wg-charterREDESIGN.txt +++ /dev/null @@ -1,47 +0,0 @@ -{% load ietf_filters %}{{wg.name|safe}} ({{wg.acronym}}) -{{ wg.name|dashify }}{{ wg.acronym|dashify }}--- - - Charter - Last Modified: {{ wg.time.date }} - - Current Status: {{ wg.state.name }} - - Chair{{ wg.chairs|pluralize }}: -{% for chair in wg.chairs %} {{ chair.person.name|safe }} <{{chair.address}}> -{% endfor %} - {{wg.area.area.area_acronym.name}} Directors: -{% for ad in wg.area_directors %} {{ ad.person|safe }} <{{ad.person.email.1}}> -{% endfor %} - {{wg.area.area.area_acronym.name}} Advisor: - {{ wg.areadirector.person.name|safe }} <{{wg.areadirector.address}}> -{% if wg.techadvisors %} - Tech Advisor{{ wg.techadvisors|pluralize }}: -{% for techadvisor in wg.techadvisors %} {{ techadvisor.person.plain_name|safe }} <{{techadvisor.address}}> -{% endfor %}{% endif %}{% if wg.editors %} - Editor{{ wg.editors|pluralize }}: -{% for editor in wg.editors %} {{ editor.person.plain_name|safe }} <{{editor.person.address}}> -{% endfor %}{% endif %}{% if wg.secretaries %} - Secretar{{ wg.secretaries|pluralize:"y,ies" }}: -{% for secretary in wg.secretaries %} {{ secretary.person.plain_name|safe }} <{{secretary.person.address}}> -{% endfor %}{% endif %} - Mailing Lists: - General Discussion: {{ wg.email_address }} - To Subscribe: {{ wg.email_subscribe }} - Archive: {{ wg.email_archive }} - -Description of Working Group: - - {{ wg.charter_text|indent|safe }} - -Goals and Milestones: -{% for milestone in wg.milestones %} {% if milestone.resolved %}{{ milestone.resolved }} {% else %}{{ milestone.due|date:"M Y" }}{% endif %} - {{ milestone.desc|safe }} -{% endfor %} -Internet-Drafts: -{% for alias in wg.drafts %} - {{alias.document.title|safe}} [{{alias.name}}-{{alias.document.rev}}] ({{ alias.document.pages }} pages) -{% endfor %} -{% if wg.rfcs %}Requests for Comments: -{% for alias in wg.rfcs %} {{ alias.name.upper }}: {{ alias.document.title|safe}} ({{ alias.document.pages }} pages){% for r in alias.rel %} - * {{ r.action }} {{ r.target.name|upper }}{% endfor %}{% for r in alias.invrel %} - * {% ifequal r.relationsship "obs" %}{{ r.inverse_action|upper }}{% else %}{{ r.action }}{% endifequal %} {{ r.source.canonical_name|upper }}{% endfor %} -{%endfor%} -{%else%}No Requests for Comments{% endif %} diff --git a/ietf/templates/wginfo/wg-dir.html b/ietf/templates/wginfo/wg-dir.html deleted file mode 100644 index b9cfb208b..000000000 --- a/ietf/templates/wginfo/wg-dir.html +++ /dev/null @@ -1,99 +0,0 @@ -{% extends "base.html" %} -{# Copyright The IETF Trust 2009, All Rights Reserved #} -{% comment %} -Portion Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the Nokia Corporation and/or its - subsidiary(-ies) nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% endcomment %} - -{% block title %}Active IETF Working Groups{% endblock %} - -{% block morecss %} -.ietf-wg-table { width: 100%; max-width:50em; } -.ietf-wg-table tr { vertical-align:top; } -{% endblock morecss %} - -{% block content %} -

Active IETF Working Groups

- -

See also: - Concluded Working Groups (www.ietf.org), - Concluded Working Groups (tools.ietf.org), - Historic Charters. -

- - {% for area in areas|dictsort:"area_acronym.name" %} -

{{ area.area_acronym.name }}

- - {% for ad in area.areadirector_set.all|dictsort:"person.last_name" %} - {% if forloop.first %} -

Area Director{{ forloop.revcounter|pluralize }}:

-
DateByText
{{ e.time|date:"Y-m-d"}}
- {% endif %} - - {% if forloop.last %} -
  {{ ad.person }} <{{ ad.person.email.1 }}>
- {% endif %} - {% endfor %} - - {% for url in area.additional_urls %} - {% if forloop.first %} -

Area Specific Web Page{{ forloop.revcounter|pluralize}}:

-

- {% endif %} - {{ url.description }}{% if not forloop.last %}
{% endif %} - {% if forloop.last %} -

- {% endif %} - {% endfor %} - - {% for wg in area.active_wgs %} - {% if forloop.first %} -

Active Working Groups:

-
- - {% endif %} - - - - - - - {% if forloop.last %} -
{{ wg }}{% for ad in area.areadirector_set.all|dictsort:"person.last_name" %}{% ifequal ad wg.area_director %}{% endifequal %}{% endfor %}{{ wg.group_acronym.name }}{% for chair in wg.chairs %}{{chair.person}}{% if not forloop.last %}, {% endif %}{% endfor %}
-
- {% endif %} - {% empty %} -

No Active Working Groups

- {% endfor %}{# wg #} - - {% endfor %}{# area #} -{% endblock %} diff --git a/ietf/templates/wginfo/wg_base.html b/ietf/templates/wginfo/wg_base.html index e4a14be8e..4f73e3fe4 100644 --- a/ietf/templates/wginfo/wg_base.html +++ b/ietf/templates/wginfo/wg_base.html @@ -66,8 +66,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}){% if concluded %}
(concluded WG){% endif %}{% if proposed %}
(proposed WG){% endif %}

-{% ifequal selected "documents" %}Documents{% else %}Documents{% endifequal %} | -{% ifequal selected "charter" %}Charter{% else %}Charter{% endifequal %} | +{% ifequal selected "documents" %}Documents{% else %}Documents{% endifequal %} | +{% ifequal selected "charter" %}Charter{% else %}Charter{% endifequal %} | {% wgchairs_admin_options wg %} History | {% if wg.clean_email_archive|startswith:"http:" or wg.clean_email_archive|startswith:"https:" or wg.clean_email_archive|startswith:"ftp:" %} diff --git a/ietf/templates/wginfo/wg_charter.html b/ietf/templates/wginfo/wg_charter.html deleted file mode 100644 index e4797950b..000000000 --- a/ietf/templates/wginfo/wg_charter.html +++ /dev/null @@ -1,182 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% comment %} -Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the Nokia Corporation and/or its - subsidiary(-ies) nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% endcomment %} -{% load ietf_filters %} -{% block wg_titledetail %}Charter{% endblock %} - -{% block morecss %} -{{ block.super }} -h2 a.button { margin-left: 0.5em; font-size: 13px; } -{% endblock %} - -{% block wg_content %} -
-{% if concluded %} -Note: The data for concluded WGs -is occasionally incorrect. -{% endif %} - - - - - - - - - - - {% if wg.parent %} - - {% endif %} - - - - - - - - - - - - - - - - - - - - - - {% if wg.techadvisors %} - - - - - {% endif %} - {% if wg.editors %} - - - {% endif %} - {% if wg.secretaries %} - - - - - {% endif %} - - - - - - - - {% if not concluded %} - - - - - {% endif %} - -
Group
Name:{{ wg.name }}
Acronym:{{ wg.acronym }}
Area:{{ wg.parent.name }} ({{ wg.parent.acronym }})
State:{{ wg.state.name }} - {% if requested_close %} - (but in the process of being closed) - {% endif %} -
Charter: - {% if wg.charter %} - {{ wg.charter.name }}-{{ wg.charter.rev }} ({{ wg.charter.get_state.name }}) - {% else %} - none - {% if user|has_role:"Area Director,Secretariat" %} - - Submit Charter - {% endif %} - {% endif %} -
Personnel
Chair{{ wg.chairs|pluralize }}: - {% for chair in wg.chairs %} - {{ chair.person.plain_name }} <{{ chair.address }}>
- {% endfor %} -
Area Director: - {% if not wg.ad %}?{% else %} - {{ wg.ad.plain_name }} <{{ wg.areadirector.address }}>{% endif %} -
Tech Advisor{{ wg.techadvisors|pluralize }}: - {% for techadvisor in wg.techadvisors %} - {{ techadvisor.person.plain_name }} <{{ techadvisor.address }}>
- {% endfor %} -
Editor{{ wg.editors|pluralize }}: - {% for editor in wg.editors %} - {{ editor.person.plain_name }} <{{ editor.address }}>
- {% endfor %} -
Secretar{{ wg.secretaries|pluralize:"y,ies" }}: - {% for secretary in wg.secretaries %} - {{ secretary.person.plain_name }} <{{ secretary.address }}>
- {% endfor %} -
Mailing List
Address:{{ wg.email_address|urlize }}
To Subscribe:{{ wg.email_subscribe|urlize }}
Archive:{{ wg.clean_email_archive|urlize }}
Jabber Chat
Room Address:xmpp:{{ wg.acronym }}@jabber.ietf.org
Logs:http://jabber.ietf.org/logs/{{ wg.acronym }}/
- -{% if user|has_role:"Area Director,Secretariat" %} -
- {% for name, url in actions %} - {{ name }} - {% if not forloop.last %}|{% endif %} - {% endfor %} -
-{% endif %} -
- -{% if wg.additional_urls %} -

In addition to the charter maintained by the IETF Secretariat, there is additional information about this working group on the Web at: -{% for url in wg.additional_urls %} -{{ url.name }}{% if not forloop.last %}, {% endif %} -{% endfor %} -

-{% endif %} - -

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

-

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

- -

{% if wg.state_id == "proposed" %}Proposed{% endif %} Milestones -{% if wg.state_id != "proposed" %} -{% if user|has_role:"Area Director,Secretariat" or is_chair %} -Add or edit milestones -{% endif %} -{% endif %} -

- -{% with wg.milestones as milestones %}{% include "wginfo/milestones.html" %}{% endwith %} - -{% if milestones_in_review %} -

+ {{ milestones_in_review|length }} new milestone{{ milestones_in_review|pluralize }} -currently in Area Director review.

-{% endif %} -{% endblock wg_content %} diff --git a/ietf/templates/wginfo/wg_documents.html b/ietf/templates/wginfo/wg_documents.html deleted file mode 100644 index f0fb4529b..000000000 --- a/ietf/templates/wginfo/wg_documents.html +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% comment %} -Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the Nokia Corporation and/or its - subsidiary(-ies) nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% endcomment %} -{% block wg_titledetail %}Documents{% endblock %} - -{% block wg_content %} -
- -{% include "doc/search/search_results.html" %} - -{% with docs_related as docs %}{% include "doc/search/search_results.html" %}{% endwith %} - -
-{% endblock wg_content %} - -{% block js %} - - -{% endblock %} diff --git a/ietf/templates/wginfo/wg_documents.txt b/ietf/templates/wginfo/wg_documents.txt deleted file mode 100644 index 3b46a8249..000000000 --- a/ietf/templates/wginfo/wg_documents.txt +++ /dev/null @@ -1,2 +0,0 @@ -{% load ietf_filters %}{% regroup docs by view_sort_group as grouped_docs %}{% for doc_group in grouped_docs %}{% for doc in doc_group.list %}{% include "wginfo/wg_documents_entry.txt" %}{% endfor %}{% endfor %}{% regroup docs_related by view_sort_group as grouped_docs_related %}{% for doc_group in grouped_docs_related %}{% for doc in doc_group.list %}Related {% include "wginfo/wg_documents_entry.txt" %}{% endfor %}{% endfor %} - diff --git a/ietf/templates/wginfo/wg_documents_entry.txt b/ietf/templates/wginfo/wg_documents_entry.txt deleted file mode 100644 index 19f456c33..000000000 --- a/ietf/templates/wginfo/wg_documents_entry.txt +++ /dev/null @@ -1 +0,0 @@ -{% load ietf_filters %}{{doc_group.grouper}} {% if doc.rfc %}{{doc.rfc.rfc_number}} {{doc.rfc.title|clean_whitespace}}{% else %}{{doc.id.draft_name_and_revision}} {{doc.id.title|clean_whitespace}}{% endif %} diff --git a/ietf/templates/wginfo/wg_summary.txt b/ietf/templates/wginfo/wg_summary.txt deleted file mode 100644 index 603d9e2f8..000000000 --- a/ietf/templates/wginfo/wg_summary.txt +++ /dev/null @@ -1,5 +0,0 @@ -{% for chair in wg.wgchair_set.all %}{% if forloop.first %} Chair{{ forloop.revcounter|pluralize:": ,s:" }} {% else %} {% endif %}{{ chair.person|safe }} <{{ chair.person.email.1 }}> -{% endfor %} WG Mail: {{ wg.email_address }} - To Join: {{ wg.email_subscribe }}{%if wg.email_keyword %} - In Body: {{ wg.email_keyword|safe }}{% endif %} - Archive: {{ wg.email_archive }} diff --git a/ietf/wgcharter/feeds.py b/ietf/wgcharter/feeds.py index 5abf7708c..1dd8bbfff 100644 --- a/ietf/wgcharter/feeds.py +++ b/ietf/wgcharter/feeds.py @@ -26,7 +26,7 @@ class GroupChanges(Feed): def link(self, obj): if not obj: raise FeedDoesNotExist - return urlreverse('wg_charter', kwargs={'acronym': obj.acronym}) + return urlreverse('group_charter', kwargs={'acronym': obj.acronym}) def description(self, obj): return self.title(obj) @@ -44,7 +44,7 @@ class GroupChanges(Feed): if isinstance(obj, DocEvent): return urlreverse("doc_view", kwargs={'name': obj.doc_id }) elif isinstance(obj, GroupEvent): - return urlreverse('wg_charter', kwargs={'acronym': obj.group.acronym }) + return urlreverse('group_charter', kwargs={'acronym': obj.group.acronym }) def item_pubdate(self, obj): return obj.time diff --git a/ietf/wgcharter/mails.py b/ietf/wgcharter/mails.py index 29c603b4e..0f983a017 100644 --- a/ietf/wgcharter/mails.py +++ b/ietf/wgcharter/mails.py @@ -33,7 +33,7 @@ def email_secretariat(request, group, type, text): "wgcharter/email_secretariat.txt", dict(text=text, group=group, - group_url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=group.acronym)), + group_url=settings.IDTRACKER_BASE_URL + urlreverse('group_charter', kwargs=dict(acronym=group.acronym)), charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=group.charter.name)), ) ) diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 945129ff7..670d876c5 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -258,7 +258,7 @@ def edit(request, acronym=None, action="edit"): if action=="charter": return redirect('charter_submit', name=wg.charter.name, option="initcharter") - return redirect('wg_charter', acronym=wg.acronym) + return redirect('group_charter', acronym=wg.acronym) else: # form.is_valid() if not new_wg: from ietf.person.forms import json_emails @@ -312,7 +312,7 @@ def conclude(request, acronym): e.desc = "Requested closing group" e.save() - return redirect('wg_charter', acronym=wg.acronym) + return redirect('group_charter', acronym=wg.acronym) else: form = ConcludeForm() diff --git a/ietf/wginfo/mails.py b/ietf/wginfo/mails.py index 96b8bb6e8..02606d30e 100644 --- a/ietf/wginfo/mails.py +++ b/ietf/wginfo/mails.py @@ -16,7 +16,7 @@ def email_milestones_changed(request, group, changes): def wrap_up_email(to, text): text = wrap(strip_tags(text), 70) text += "\n\n" - text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym))) + text += u"URL: %s" % (settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym))) send_mail_text(request, to, None, u"Milestones changed for %s %s" % (group.acronym, group.type.name), @@ -95,7 +95,7 @@ def email_milestones_due(group, early_warning_days): milestones=milestones, today=today, early_warning_days=early_warning_days, - url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym)) + url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym)) )) def groups_needing_milestones_due_reminder(early_warning_days): @@ -120,7 +120,7 @@ def email_milestones_overdue(group): "wginfo/reminder_milestones_overdue.txt", dict(group=group, milestones=milestones, - url=settings.IDTRACKER_BASE_URL + urlreverse("wg_charter", kwargs=dict(acronym=group.acronym)) + url=settings.IDTRACKER_BASE_URL + urlreverse("group_charter", kwargs=dict(acronym=group.acronym)) )) def groups_needing_milestones_overdue_reminder(grace_period=30): diff --git a/ietf/wginfo/milestones.py b/ietf/wginfo/milestones.py index 3e7b3df64..dee1765cc 100644 --- a/ietf/wginfo/milestones.py +++ b/ietf/wginfo/milestones.py @@ -313,7 +313,7 @@ def edit_milestones(request, acronym, milestone_set="current"): if milestone_set == "charter": return redirect('doc_view', name=group.charter.canonical_name()) else: - return redirect('wg_charter', acronym=group.acronym) + return redirect('group_charter', acronym=group.acronym) else: for m in milestones: forms.append(MilestoneForm(instance=m, needs_review=needs_review)) diff --git a/ietf/wginfo/tests.py b/ietf/wginfo/tests.py index 75e8db055..f50d14885 100644 --- a/ietf/wginfo/tests.py +++ b/ietf/wginfo/tests.py @@ -178,7 +178,7 @@ class WgEditTestCase(django.test.TestCase): make_test_data() group = Group.objects.get(acronym="mars") - url = urlreverse('wg_edit', kwargs=dict(acronym=group.acronym)) + url = urlreverse('group_edit', kwargs=dict(acronym=group.acronym)) login_testing_unauthorized(self, "secretary", url) # normal get diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index 80651befd..956ee2de6 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -6,7 +6,7 @@ from django.views.generic.simple import redirect_to urlpatterns = patterns('', - (r'^$', views.wg_dir), + (r'^$', views.active_wgs), (r'^summary.txt', redirect_to, { 'url':'/wg/1wg-summary.txt' }), (r'^summary-by-area.txt', redirect_to, { 'url':'/wg/1wg-summary.txt' }), (r'^summary-by-acronym.txt', redirect_to, { 'url':'/wg/1wg-summary-by-acronym.txt' }), @@ -18,12 +18,12 @@ urlpatterns = patterns('', (r'^bofs/$', views.bofs), (r'^chartering/create/$', edit.edit, {'action': "charter"}, "wg_create"), (r'^bofs/create/$', edit.edit, {'action': "create"}, "bof_create"), - (r'^(?P[a-zA-Z0-9-]+)/documents/txt/$', views.wg_documents_txt), - (r'^(?P[a-zA-Z0-9-]+)/$', views.wg_documents_html, None, "wg_docs"), - (r'^(?P[a-zA-Z0-9-]+)/charter/$', views.wg_charter, None, 'wg_charter'), + (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-]+)/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-]+)/history/$', views.history), - (r'^(?P[a-zA-Z0-9-]+)/edit/$', edit.edit, {'action': "edit"}, "wg_edit"), + (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"), diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 7af56f075..dd2070200 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -32,77 +32,111 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import itertools + from django.shortcuts import get_object_or_404, render_to_response -from django.template import RequestContext, loader +from django.template import RequestContext from django.http import HttpResponse from django.conf import settings from django.core.urlresolvers import reverse as urlreverse -from ietf.idtracker.models import Area, IETFWG + from ietf.doc.views_search import SearchForm, retrieve_search_results -from ietf.idrfc.idrfc_wrapper import IdRfcWrapper from ietf.ipr.models import IprDetail -from ietf.group.models import Group -from ietf.doc.models import State +from ietf.group.models import Group, GroupURL +from ietf.doc.models import State, DocAlias, RelatedDocument from ietf.doc.utils import get_chartering_type +from ietf.person.models import Email +from ietf.group.utils import get_charter_text +from ietf.doc.templatetags.ietf_filters import clean_whitespace + +from ietf.wgchairs.accounts import (can_manage_workflow_in_group, + can_manage_delegates_in_group, + can_manage_shepherds_in_group) -def fill_in_charter_info(wg, include_drafts=False): - from ietf.person.models import Email - from ietf.doc.models import DocAlias, RelatedDocument +def fill_in_charter_info(group, include_drafts=False): + group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None + group.chairs = Email.objects.filter(role__group=group, role__name="chair") + group.techadvisors = Email.objects.filter(role__group=group, role__name="techadv") + group.editors = Email.objects.filter(role__group=group, role__name="editor") + group.secretaries = Email.objects.filter(role__group=group, role__name="secr") + milestone_state = "charter" if group.state_id == "proposed" else "active" + group.milestones = group.groupmilestone_set.filter(state=milestone_state).order_by('due') - wg.areadirector = wg.ad.role_email("ad", wg.parent) if wg.ad else None - wg.chairs = Email.objects.filter(role__group=wg, role__name="chair") - wg.techadvisors = Email.objects.filter(role__group=wg, role__name="techadv") - wg.editors = Email.objects.filter(role__group=wg, role__name="editor") - wg.secretaries = Email.objects.filter(role__group=wg, role__name="secr") - milestone_state = "charter" if wg.state_id == "proposed" else "active" - wg.milestones = wg.groupmilestone_set.filter(state=milestone_state).order_by('due') + group.charter_text = get_charter_text(group) if include_drafts: - aliases = DocAlias.objects.filter(document__type="draft", document__group=wg).select_related('document').order_by("name") - wg.drafts = [] - wg.rfcs = [] + aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name") + group.drafts = [] + group.rfcs = [] for a in aliases: if a.name.startswith("draft"): - wg.drafts.append(a) + group.drafts.append(a) else: - wg.rfcs.append(a) + group.rfcs.append(a) a.rel = RelatedDocument.objects.filter(source=a.document).distinct() a.invrel = RelatedDocument.objects.filter(target=a).distinct() -def wg_summary_acronym(request): - areas = Area.active_areas() - wgs = IETFWG.objects.filter(status=IETFWG.ACTIVE) - return HttpResponse(loader.render_to_string('wginfo/1wg-summary-by-acronym.txt', {'area_list': areas, 'wg_list': wgs}),mimetype='text/plain; charset=UTF-8') +def extract_last_name(email): + return email.person.name_parts()[3] + +def extract_group_chairs(group): + return sorted(Email.objects.filter(role__group=group, role__name="chair").select_related("person"), key=extract_last_name) def wg_summary_area(request): - wgs = IETFWG.objects.filter(status='1',group_type='1',start_date__isnull=False).exclude(parent=None) - return HttpResponse(loader.render_to_string('wginfo/1wg-summary.txt', {'wg_list': wgs}),mimetype='text/plain; charset=UTF-8') - -def wg_charters(request): - wgs = IETFWG.objects.filter(status='1',group_type='1',start_date__isnull=False).exclude(parent=None) - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - for wg in wgs: - fill_in_charter_info(wg, include_drafts=True) - return HttpResponse(loader.render_to_string('wginfo/1wg-charters.txt', {'wg_list': wgs, 'USE_DB_REDESIGN_PROXY_CLASSES': settings.USE_DB_REDESIGN_PROXY_CLASSES}),mimetype='text/plain; charset=UTF-8') - -def wg_charters_by_acronym(request): - wgs = IETFWG.objects.filter(status='1',group_type='1',start_date__isnull=False) - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - for wg in wgs: - fill_in_charter_info(wg, include_drafts=True) - return HttpResponse(loader.render_to_string('wginfo/1wg-charters-by-acronym.txt', {'wg_list': wgs, 'USE_DB_REDESIGN_PROXY_CLASSES': settings.USE_DB_REDESIGN_PROXY_CLASSES}),mimetype='text/plain; charset=UTF-8') - -def wg_dir(request): - areas = Area.active_areas() - return render_to_response('wginfo/wg-dir.html', {'areas':areas}, RequestContext(request)) - -def wg_dirREDESIGN(request): - from ietf.group.models import Group, GroupURL - from ietf.person.models import Email - areas = Group.objects.filter(type="area", state="active").order_by("name") for area in areas: + area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=extract_last_name) + area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym") + for group in area.groups: + group.chairs = extract_group_chairs(group) + + areas = [a for a in areas if a.groups] + + return render_to_response('wginfo/1wg-summary.txt', + { 'areas': areas }, + mimetype='text/plain; charset=UTF-8') + +def wg_summary_acronym(request): + areas = Group.objects.filter(type="area", state="active").order_by("name") + groups = Group.objects.filter(type="wg", state="active").order_by("acronym").select_related("parent") + for group in groups: + group.chairs = extract_group_chairs(group) + return render_to_response('wginfo/1wg-summary-by-acronym.txt', + { 'areas': areas, + 'groups': groups }, + mimetype='text/plain; charset=UTF-8') + +def wg_charters(request): + areas = Group.objects.filter(type="area", state="active").order_by("name") + for area in areas: + area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=extract_last_name) + area.groups = Group.objects.filter(parent=area, type="wg", state="active").order_by("name") + for group in area.groups: + fill_in_charter_info(group, include_drafts=True) + group.area = area + return render_to_response('wginfo/1wg-charters.txt', + { 'areas': areas }, + mimetype='text/plain; charset=UTF-8') + +def wg_charters_by_acronym(request): + areas = dict((a.id, a) for a in Group.objects.filter(type="area", state="active").order_by("name")) + + for area in areas.itervalues(): + area.ads = sorted(Email.objects.filter(role__group=area, role__name="ad").select_related("person"), key=extract_last_name) + + groups = Group.objects.filter(type="wg", state="active").exclude(parent=None).order_by("acronym") + for group in groups: + fill_in_charter_info(group, include_drafts=True) + group.area = areas.get(group.parent_id) + return render_to_response('wginfo/1wg-charters-by-acronym.txt', + { 'groups': groups }, + mimetype='text/plain; charset=UTF-8') + +def active_wgs(request): + areas = Group.objects.filter(type="area", state="active").order_by("name") + for area in areas: + # dig out information for template area.ads = [] for e in Email.objects.filter(role__group=area, role__name="ad").select_related("person"): e.incoming = False @@ -112,26 +146,22 @@ def wg_dirREDESIGN(request): e.incoming = True area.ads.append(e) - area.ads.sort(key=lambda e: (e.incoming, e.person.name_parts()[3])) + area.ads.sort(key=lambda e: (e.incoming, extract_last_name(e))) area.wgs = Group.objects.filter(parent=area, type="wg", state="active").order_by("acronym") area.urls = area.groupurl_set.all().order_by("name") for wg in area.wgs: - wg.chairs = sorted(Email.objects.filter(role__group=wg, role__name="chair").select_related("person"), key=lambda e: e.person.name_parts()[3]) - - return render_to_response('wginfo/wg-dirREDESIGN.html', {'areas':areas}, RequestContext(request)) + wg.chairs = extract_group_chairs(wg) -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - wg_dir = wg_dirREDESIGN + return render_to_response('wginfo/active_wgs.html', {'areas':areas}, RequestContext(request)) def bofs(request): groups = Group.objects.filter(type="wg", state="bof") - return render_to_response('wginfo/bofs.html',dict(groups=groups),RequestContext(request)) + return render_to_response('wginfo/bofs.html',dict(groups=groups), RequestContext(request)) def chartering_wgs(request): charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev")) groups = Group.objects.filter(type="wg", charter__states__in=charter_states).select_related("state", "charter") - for g in groups: g.chartering_type = get_chartering_type(g.charter) @@ -141,31 +171,40 @@ def chartering_wgs(request): RequestContext(request)) -def wg_documents(request, acronym): - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - concluded = wg.status_id in [ 2, 3, ] - proposed = (wg.status_id == 4) - form = SearchForm({'by':'group', 'group':str(wg.group_acronym.acronym), - 'rfcs':'on', 'activedrafts':'on'}) +def construct_group_menu_context(request, group, selected, others): + """Return context with info for the group menu filled in.""" + d = { + "group": group, + "selected": selected, + "can_manage_delegates": can_manage_delegates_in_group(request.user, group), + "can_manage_workflow": can_manage_workflow_in_group(request.user, group), + "can_manage_shepherds": can_manage_shepherds_in_group(request.user, group), + } + + d.update(others) + + return d + +def search_for_group_documents(group): + form = SearchForm({ 'by':'group', 'group': group.acronym or "", 'rfcs':'on', 'activedrafts': 'on' }) docs, meta = retrieve_search_results(form) # get the related docs - form_related = SearchForm({'by':'group', 'name':'-'+str(wg.group_acronym.acronym)+'-', 'activedrafts':'on'}) - docs_related, meta_related = retrieve_search_results(form_related) - docs_related_pruned = [] - for d in docs_related: + form_related = SearchForm({ 'by':'group', 'name': u'-%s-' % group.acronym, 'activedrafts': 'on' }) + raw_docs_related, meta_related = retrieve_search_results(form_related) + + docs_related = [] + for d in raw_docs_related: parts = d.name.split("-", 2); # canonical form draft--wg-etc - if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(wg.group_acronym.acronym + "-"): - docs_related_pruned.append(d) - - docs_related = docs_related_pruned + if len(parts) >= 3 and parts[1] != "ietf" and parts[2].startswith(group.acronym + "-"): + docs_related.append(d) # move call for WG adoption to related cleaned_docs = [] docs_related_names = set(d.name for d in docs_related) for d in docs: - if d.stream_id == "ietf" and d.get_state_slug("draft-stream-ietf") == "c-adopt": + if d.stream_id and d.get_state_slug("draft-stream-%s" % d.stream_id) == "c-adopt": if d.name not in docs_related_names: docs_related.append(d) else: @@ -175,59 +214,75 @@ def wg_documents(request, acronym): docs_related.sort(key=lambda d: d.name) - return wg, concluded, proposed, docs, meta, docs_related, meta_related + return docs, meta, docs_related, meta_related -def wg_documents_txt(request, acronym): - wg, concluded, proposed, docs, meta, docs_related, meta_related = wg_documents(request, acronym) - return HttpResponse(loader.render_to_string('wginfo/wg_documents.txt', {'wg': wg, 'concluded':concluded, 'proposed':proposed, 'selected':'documents', 'docs':docs, 'meta':meta, 'docs_related':docs_related, 'meta_related':meta_related}),mimetype='text/plain; charset=UTF-8') +def group_documents(request, acronym): + group = get_object_or_404(Group, type="wg", acronym=acronym) -def wg_documents_html(request, acronym): - wg, concluded, proposed, docs, meta, docs_related, meta_related = wg_documents(request, acronym) - return render_to_response('wginfo/wg_documents.html', {'wg': wg, 'concluded':concluded, 'proposed':proposed, 'selected':'documents', 'docs':docs, 'meta':meta, 'docs_related':docs_related, 'meta_related':meta_related}, RequestContext(request)) + docs, meta, docs_related, meta_related = search_for_group_documents(group) -def wg_charter(request, acronym): - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - concluded = wg.status_id in [ 2, 3, ] - proposed = (wg.status_id == 4) + return render_to_response('wginfo/group_documents.html', + construct_group_menu_context(request, group, "documents", { + 'docs': docs, + 'meta': meta, + 'docs_related': docs_related, + 'meta_related': meta_related + }), RequestContext(request)) + +def group_documents_txt(request, acronym): + """Return tabulator-separated rows with documents for group.""" + group = get_object_or_404(Group, type="wg", acronym=acronym) + + docs, meta, docs_related, meta_related = search_for_group_documents(group) + + for d in docs_related: + d.search_heading = u"Related %s" % d.search_heading + + rows = [] + for d in itertools.chain(docs, docs_related): + rfc_number = d.rfc_number() + if rfc_number != None: + name = rfc_number + else: + name = "%s-%s" % (d.name, d.rev) + + rows.append(u"\t".join((d.search_heading.replace("Internet-Draft", ""), name, clean_whitespace(d.title)))) + + return HttpResponse(u"\n".join(rows), mimetype='text/plain; charset=UTF-8') + + +def group_charter(request, acronym): + group = get_object_or_404(Group, type="wg", acronym=acronym) + + fill_in_charter_info(group, include_drafts=False) - fill_in_charter_info(wg) actions = [] - if wg.state_id != "conclude": - actions.append(("Edit WG", urlreverse("wg_edit", kwargs=dict(acronym=wg.acronym)))) + if group.state_id != "conclude": + actions.append((u"Edit %s" % group.type.name, urlreverse("group_edit", kwargs=dict(acronym=group.acronym)))) - e = wg.latest_event(type__in=("changed_state", "requested_close",)) - requested_close = wg.state_id != "conclude" and e and e.type == "requested_close" + e = group.latest_event(type__in=("changed_state", "requested_close",)) + requested_close = group.state_id != "conclude" and e and e.type == "requested_close" - if wg.state_id in ("active", "dormant"): - actions.append(("Request closing WG", urlreverse("wg_conclude", kwargs=dict(acronym=wg.acronym)))) + if group.state_id in ("active", "dormant"): + actions.append((u"Request closing %s" % group.type.name, urlreverse("wg_conclude", kwargs=dict(acronym=group.acronym)))) - context = get_wg_menu_context(wg, "charter") - context.update(dict( - actions=actions, - is_chair=request.user.is_authenticated() and wg.role_set.filter(name="chair", person__user=request.user), - milestones_in_review=wg.groupmilestone_set.filter(state="review"), - requested_close=requested_close, - )) + is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user), - return render_to_response('wginfo/wg_charter.html', - context, - RequestContext(request)) + return render_to_response('wginfo/group_charter.html', + construct_group_menu_context(request, group, "charter", { + "actions": actions, + "is_chair": is_chair, + "milestones_in_review": group.groupmilestone_set.filter(state="review"), + "requested_close": requested_close, + }), RequestContext(request)) -def get_wg_menu_context(wg, selected): - # it would probably be better to refactor wginfo into rendering - # the menu separately instead of each view having to include the information - - return dict(wg=wg, concluded=wg.state_id == "conclude", proposed=wg.state_id == "proposed", selected=selected) def history(request, acronym): - wg = get_object_or_404(Group, acronym=acronym) + group = get_object_or_404(Group, acronym=acronym) - events = wg.groupevent_set.all().select_related('by').order_by('-time', '-id') + events = group.groupevent_set.all().select_related('by').order_by('-time', '-id') - context = get_wg_menu_context(wg, "history") - context.update(dict(events=events, - )) - - wg.group_acronym = wg # hack for compatibility with old templates - - return render_to_response('wginfo/history.html', context, RequestContext(request)) + return render_to_response('wginfo/history.html', + construct_group_menu_context(request, group, "history", { + "events": events, + }), RequestContext(request)) From 459bbf39e0a7a6d3a3cf53ccb096061c5a5d2c51 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 4 Sep 2013 08:44:50 +0000 Subject: [PATCH 02/20] Fix spelling mistake - Legacy-Id: 6087 --- ietf/templates/wginfo/group_base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/templates/wginfo/group_base.html b/ietf/templates/wginfo/group_base.html index bd5f47138..ef5000cd0 100644 --- a/ietf/templates/wginfo/group_base.html +++ b/ietf/templates/wginfo/group_base.html @@ -78,7 +78,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endif %} {% if can_manage_delegates %} - Manage delegations | + Manage delegations | {% endif %} {% if can_manage_shepherds %} From b4feab127a4ebf3a537ed8d7d6deddbba12ee9bc Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 5 Sep 2013 22:08:11 +0000 Subject: [PATCH 03/20] Add basic tests for the information pages in wginfo - Legacy-Id: 6089 --- ietf/wginfo/tests.py | 174 ++++++++++++++++++++++++++++++++++----- ietf/wginfo/testurl.list | 19 ----- 2 files changed, 153 insertions(+), 40 deletions(-) delete mode 100644 ietf/wginfo/testurl.list diff --git a/ietf/wginfo/tests.py b/ietf/wginfo/tests.py index f50d14885..ea5dbb45e 100644 --- a/ietf/wginfo/tests.py +++ b/ietf/wginfo/tests.py @@ -50,36 +50,168 @@ from ietf.name.models import * from ietf.person.models import * from ietf.wginfo.mails import * - -class WgInfoUrlTestCase(SimpleUrlTestCase): - def testUrls(self): - self.doTestUrls(__file__) - -class WgFileTestCase(unittest.TestCase): - def testFileExistence(self): - fpath = os.path.join(settings.IETFWG_DESCRIPTIONS_PATH, "tls.desc.txt") - if not os.path.exists(fpath): - print "\nERROR: charter files not found in "+settings.IETFWG_DESCRIPTIONS_PATH - print "They are needed for testing WG charter pages." - print "Download them to a local directory with:" - print "wget -nd -nc -np -r http://www.ietf.org/wg-descriptions/" - print "And set IETFWG_DESCRIPTIONS_PATH in settings_local.py\n" - -class WgOverviewTestCase(django.test.TestCase): +class GroupPagesTests(django.test.TestCase): fixtures = ["names"] - def test_overview(self): - make_test_data() + def setUp(self): + self.charter_dir = os.path.abspath("tmp-charter-dir") + os.mkdir(self.charter_dir) + settings.CHARTER_PATH = self.charter_dir - wg = Group.objects.get(acronym="mars") - wg.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev")) + def tearDown(self): + shutil.rmtree(self.charter_dir) + + def test_active_wgs(self): + draft = make_test_data() + group = draft.group + + url = urlreverse('ietf.wginfo.views.active_wgs') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.parent.name in r.content) + self.assertTrue(group.acronym in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(group.ad.plain_name() in r.content) + + def test_wg_summaries(self): + draft = make_test_data() + group = draft.group + + chair = Email.objects.filter(role__group=group, role__name="chair")[0] + + with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f: + f.write("This is a charter.") + + url = urlreverse('ietf.wginfo.views.wg_summary_area') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.parent.name in r.content) + self.assertTrue(group.acronym in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(chair.address in r.content) + + url = urlreverse('ietf.wginfo.views.wg_summary_acronym') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.acronym in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(chair.address in r.content) + + url = urlreverse('ietf.wginfo.views.wg_charters') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.acronym in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(group.ad.plain_name() in r.content) + self.assertTrue(chair.address in r.content) + self.assertTrue("This is a charter." in r.content) + + url = urlreverse('ietf.wginfo.views.wg_charters_by_acronym') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.acronym in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(group.ad.plain_name() in r.content) + self.assertTrue(chair.address in r.content) + self.assertTrue("This is a charter." in r.content) + + def test_chartering_wgs(self): + draft = make_test_data() + group = draft.group + group.charter.set_state(State.objects.get(used=True, type="charter", slug="intrev")) url = urlreverse('ietf.wginfo.views.chartering_wgs') r = self.client.get(url) self.assertEquals(r.status_code, 200) q = PyQuery(r.content) - self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("mars")')), 1) + self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1) + def test_bofs(self): + draft = make_test_data() + group = draft.group + group.state_id = "bof" + group.save() + + url = urlreverse('ietf.wginfo.views.bofs') + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + q = PyQuery(r.content) + self.assertEquals(len(q('table.ietf-doctable td.acronym a:contains("%s")' % group.acronym)), 1) + + def test_group_documents(self): + draft = make_test_data() + group = draft.group + + draft2 = Document.objects.create( + name="draft-somebody-mars-test", + time=datetime.datetime.now(), + type_id="draft", + title="Test By Somebody", + stream_id="ietf", + group=Group.objects.get(type="individ"), + abstract="Abstract.", + rev="01", + pages=2, + intended_std_level_id="ps", + shepherd=None, + ad=None, + expires=datetime.datetime.now() + datetime.timedelta(days=10), + notify="", + note="", + ) + + draft2.set_state(State.objects.get(used=True, type="draft", slug="active")) + DocAlias.objects.create( + document=draft2, + name=draft2.name, + ) + + url = urlreverse('ietf.wginfo.views.group_documents', kwargs=dict(acronym=group.acronym)) + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(draft.name in r.content) + self.assertTrue(group.name in r.content) + self.assertTrue(group.acronym in r.content) + + self.assertTrue(draft2.name in r.content) + + def test_group_charter(self): + draft = make_test_data() + group = draft.group + + with open(os.path.join(self.charter_dir, "%s-%s.txt" % (group.charter.canonical_name(), group.charter.rev)), "w") as f: + f.write("This is a charter.") + + milestone = GroupMilestone.objects.create( + group=group, + state_id="active", + desc="Get Work Done", + due=datetime.date.today() + datetime.timedelta(days=100)) + milestone.docs.add(draft) + + url = urlreverse('ietf.wginfo.views.group_charter', kwargs=dict(acronym=group.acronym)) + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(group.name in r.content) + self.assertTrue(group.acronym in r.content) + self.assertTrue("This is a charter." in r.content) + self.assertTrue(milestone.desc in r.content) + self.assertTrue(milestone.docs.all()[0].name in r.content) + + def test_history(self): + draft = make_test_data() + group = draft.group + + e = GroupEvent.objects.create( + group=group, + desc="Something happened.", + type="added_comment", + by=Person.objects.get(name="(System)")) + + url = urlreverse('ietf.wginfo.views.history', kwargs=dict(acronym=group.acronym)) + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + self.assertTrue(e.desc in r.content) class WgEditTestCase(django.test.TestCase): fixtures = ["names"] diff --git a/ietf/wginfo/testurl.list b/ietf/wginfo/testurl.list deleted file mode 100644 index 2cf38b30a..000000000 --- a/ietf/wginfo/testurl.list +++ /dev/null @@ -1,19 +0,0 @@ -200 /wg/ -404 /wg/nosuchgroup/ -200 /wg/tls/ -200 /wg/tls/charter/ -200 /wg/mobike/ # concluded -200 /wg/mobike/charter/ -200 /wg/catnip/ # concluded very long time ago -200 /wg/catnip/charter/ # concluded very long time ago -404 /wg/saag/ # not a WG -404 /wg/saag/charter/ # not a WG - -200 /wg/1wg-summary.txt -200 /wg/1wg-summary-by-acronym.txt -301 /wg/summary.txt -301 /wg/summary-by-area.txt -301 /wg/summary-by-acronym.txt -200,heavy /wg/1wg-charters.txt -200,heavy /wg/1wg-charters-by-acronym.txt - From 3f9327eefe72b76fc3fd6cb53f550785a8f7cb18 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Fri, 6 Sep 2013 22:38:57 +0000 Subject: [PATCH 04/20] Fix crash bug in /wg//charter/ page for BOFs - Legacy-Id: 6092 --- ietf/wginfo/views.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index dd2070200..362beab76 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -63,7 +63,10 @@ def fill_in_charter_info(group, include_drafts=False): milestone_state = "charter" if group.state_id == "proposed" else "active" group.milestones = group.groupmilestone_set.filter(state=milestone_state).order_by('due') - group.charter_text = get_charter_text(group) + if group.charter: + group.charter_text = get_charter_text(group) + else: + group.charter_text = u"Not chartered yet." if include_drafts: aliases = DocAlias.objects.filter(document__type="draft", document__group=group).select_related('document').order_by("name") From 5a3cccce7c1b40a346339bb9ae59125365311312 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Mon, 9 Sep 2013 16:46:34 +0000 Subject: [PATCH 05/20] Fix subtle is_chair bug and construct group_documents_txt state names directly from state instead of using search headings - Legacy-Id: 6113 --- ietf/wginfo/views.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 362beab76..446c1ba59 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -238,8 +238,11 @@ def group_documents_txt(request, acronym): docs, meta, docs_related, meta_related = search_for_group_documents(group) + for d in docs: + d.prefix = d.get_state().name + for d in docs_related: - d.search_heading = u"Related %s" % d.search_heading + d.prefix = u"Related %s" % d.get_state().name rows = [] for d in itertools.chain(docs, docs_related): @@ -249,7 +252,7 @@ def group_documents_txt(request, acronym): else: name = "%s-%s" % (d.name, d.rev) - rows.append(u"\t".join((d.search_heading.replace("Internet-Draft", ""), name, clean_whitespace(d.title)))) + rows.append(u"\t".join((d.prefix, name, clean_whitespace(d.title)))) return HttpResponse(u"\n".join(rows), mimetype='text/plain; charset=UTF-8') @@ -269,7 +272,7 @@ def group_charter(request, acronym): if group.state_id in ("active", "dormant"): actions.append((u"Request closing %s" % group.type.name, urlreverse("wg_conclude", kwargs=dict(acronym=group.acronym)))) - is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user), + is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user) return render_to_response('wginfo/group_charter.html', construct_group_menu_context(request, group, "charter", { From 026ed3f8df422cdfd241168774d0087e4814b3ef Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:13:59 +0000 Subject: [PATCH 06/20] Add statehelp template filter for outputting a little help icon for a state with a tooltip and link to the description - Legacy-Id: 6133 --- ietf/doc/templatetags/ietf_filters.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index 21f9e4b80..2e7dc8cf6 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -9,6 +9,7 @@ from django.template.defaultfilters import linebreaksbr, wordwrap, stringfilter, from django.template import resolve_variable from django.utils.safestring import mark_safe, SafeData from django.utils import simplejson +from django.utils.html import strip_tags try: from email import utils as emailutils except ImportError: @@ -475,6 +476,14 @@ def state(doc, slug): slug = "%s-stream-%s" % (doc.type_id, doc.stream_id) return doc.get_state(slug) +@register.filter +def statehelp(state): + "Output help icon with tooltip for state." + from django.core.urlresolvers import reverse as urlreverse + tooltip = escape(strip_tags(state.desc)) + url = urlreverse("state_help", kwargs=dict(type=state.type_id)) + "#" + state.slug + return mark_safe('?' % (url, tooltip)) + def _test(): import doctest doctest.testmod() @@ -483,11 +492,10 @@ if __name__ == "__main__": _test() @register.filter -def plural(text, list, arg=u's'): +def plural(text, seq, arg=u's'): "Similar to pluralize, but looks at the text, too" from django.template.defaultfilters import pluralize if text.endswith('s'): return text else: - return text + pluralize(len(list), arg) - \ No newline at end of file + return text + pluralize(len(seq), arg) From 95fdfb5d8a9e59d3bf930d6adf5b556eb46e9168 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:15:18 +0000 Subject: [PATCH 07/20] Add tags for streams to state help - Legacy-Id: 6134 --- ietf/doc/views_help.py | 8 ++++++-- ietf/templates/doc/state_help.html | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ietf/doc/views_help.py b/ietf/doc/views_help.py index 68104d624..936c27bf1 100644 --- a/ietf/doc/views_help.py +++ b/ietf/doc/views_help.py @@ -3,12 +3,14 @@ from django.shortcuts import render_to_response, get_object_or_404 from django.template import RequestContext from ietf.doc.models import * +from ietf.doc.utils import get_tags_for_stream_id def state_help(request, type): slug, title = { "draft-iesg": ("draft-iesg", "IESG States For Internet-Drafts"), "draft-rfceditor": ("draft-rfceditor", "RFC Editor States For Internet-Drafts"), "draft-iana-action": ("draft-iana-action", "IANA Action States For Internet-Drafts"), + "draft-stream-ietf": ("draft-stream-ietf", "IETF Stream States For Internet-Drafts"), "charter": ("charter", "Charter States"), "conflict-review": ("conflrev", "Conflict Review States"), "status-change": ("statchg", "RFC Status Change States"), @@ -35,6 +37,9 @@ def state_help(request, type): states.insert(0, fake_state) tags = DocTagName.objects.filter(slug__in=IESG_SUBSTATE_TAGS) + elif state_type.slug.startswith("draft-stream-"): + possible = get_tags_for_stream_id(state_type.slug.replace("draft-stream-", "")) + tags = DocTagName.objects.filter(slug__in=possible) return render_to_response("doc/state_help.html", { "title": title, @@ -42,5 +47,4 @@ def state_help(request, type): "states": states, "has_next_states": has_next_states, "tags": tags, - }, - context_instance=RequestContext(request)) + }, context_instance=RequestContext(request)) diff --git a/ietf/templates/doc/state_help.html b/ietf/templates/doc/state_help.html index e0c1e3131..a328d6c87 100644 --- a/ietf/templates/doc/state_help.html +++ b/ietf/templates/doc/state_help.html @@ -24,7 +24,7 @@ {% for state in states %} {{ state.name }} - {{ state.desc|linebreaksbr }} + {{ state.desc|safe|linebreaksbr }} {% if has_next_states %} {% for s in state.next_states.all %} From 3c8f5d352197edb23a44fca2b0ade5058955e968 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:16:11 +0000 Subject: [PATCH 08/20] CSS styling for state help icon - Legacy-Id: 6135 --- static/css/base2.css | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/static/css/base2.css b/static/css/base2.css index f51504aae..20149dbfc 100644 --- a/static/css/base2.css +++ b/static/css/base2.css @@ -363,6 +363,24 @@ span.fieldRequired { color: red; } +.state-help-icon { + display: inline-block; + margin-left: 0.2em; + padding: 0 0.2em; + font-weight: bold; + font-style: normal; + font-size: 90%; + color: #999; + background-color: #ddd; + text-decoration: none; +} + +.state-help-icon:hover { + color: #eee; + background-color: #bbb; + transition-duration: 0.2s; +} + /* js styles */ .js-info { background-color: #FFDD88; From 947345ecf239d19c3d113fce4d4a276ba90dcbd2 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:18:14 +0000 Subject: [PATCH 09/20] Remove link to now obsolete shepherd pages, move manage workflow to wginfo, fix a couple of oddities on the workflow page - Legacy-Id: 6136 --- .../customize_workflow.html} | 40 +++--- ietf/templates/wginfo/group_base.html | 14 +- ietf/templates/wginfo/group_charter.html | 2 +- ietf/wgchairs/urls.py | 2 - ietf/wgchairs/views.py | 127 ------------------ ietf/wginfo/edit.py | 80 ++++++++++- ietf/wginfo/urls.py | 2 +- ietf/wginfo/views.py | 11 +- 8 files changed, 105 insertions(+), 173 deletions(-) rename ietf/templates/{wgchairs/manage_workflowREDESIGN.html => wginfo/customize_workflow.html} (80%) diff --git a/ietf/templates/wgchairs/manage_workflowREDESIGN.html b/ietf/templates/wginfo/customize_workflow.html similarity index 80% rename from ietf/templates/wgchairs/manage_workflowREDESIGN.html rename to ietf/templates/wginfo/customize_workflow.html index 4a385afaf..d1c939e64 100644 --- a/ietf/templates/wgchairs/manage_workflowREDESIGN.html +++ b/ietf/templates/wginfo/customize_workflow.html @@ -1,13 +1,6 @@ -{% extends "wginfo/wg_base.html" %} +{% extends "base.html" %} -{% block wg_titledetail %}Manage Workflow{% endblock %} - -{% block pagehead %} -{{ block.super }} - - - -{% endblock pagehead %} +{% block title %}Customize Workflow for {{ group.acronym }} {{ group.type.name }}{% endblock %} {% block morecss %} {{ block.super }} @@ -53,13 +46,20 @@ } {% endblock %} -{% block wg_content %} -
-

Edit workflow

+{% block content %} +{% load ietf_filters %} -

Below you can customize the draft states and tags used in the {{ wg.acronym }} WG. Note that some states are mandatory for WG operation and cannot be deactivated.

+
+ +

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 +mandatory for group operation and cannot be deactivated.

+ +

You can see the default Working Group I-D State Diagram +in Section 4.1 of RFC6174.

-

You can see the default Working Group I-D State Diagram in Section 4.1 of RFC6174.

States

@@ -90,11 +90,7 @@ {% endif %} -
- {{ state.name }} {% if not state.used %} (not used in {{ wg.acronym }}){% endif %} - + -
-
{{ state.desc|safe|linebreaks }}
+ {{ state.name }} {% if not state.used %} (not used in {{ group.acronym }}){% endif %} {{ state|statehelp }}
@@ -142,11 +138,14 @@ - {{ tag.name }} {% if not tag.used %} (not used in {{ wg.acronym }}){% endif %} + {{ tag.name }} {% if not tag.used %} (not used in {{ group.acronym }}){% endif %} {% endfor %} +{% endblock content %} + +{% block js %} - {% endblock %} diff --git a/ietf/templates/wginfo/group_base.html b/ietf/templates/wginfo/group_base.html index ef5000cd0..1496a7e57 100644 --- a/ietf/templates/wginfo/group_base.html +++ b/ietf/templates/wginfo/group_base.html @@ -32,7 +32,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. {% endcomment %} -{% load ietf_filters wgchairs_tags %} +{% load ietf_filters %} {% block title %}{{ group.name }} ({{ group.acronym }}) - {% block group_subtitle %}{% endblock %}{% endblock %} {% block morecss %} @@ -73,18 +73,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Documents | Charter | - {% if can_manage_workflow %} - Manage workflow | - {% endif %} - - {% if can_manage_delegates %} - Manage delegations | - {% endif %} - - {% if can_manage_shepherds %} - Manage shepherds | - {% endif %} - History | {% if group.list_archive|startswith:"http:" or group.list_archive|startswith:"https:" or group.list_archive|startswith:"ftp:" %} List Archive » | diff --git a/ietf/templates/wginfo/group_charter.html b/ietf/templates/wginfo/group_charter.html index fb4d448b1..7175748a3 100644 --- a/ietf/templates/wginfo/group_charter.html +++ b/ietf/templates/wginfo/group_charter.html @@ -130,7 +130,7 @@ is occasionally incorrect. {% if user|has_role:"Area Director,Secretariat" %}
{% for name, url in actions %} - {{ name }} + {{ name }} {% if not forloop.last %} | {% endif %} {% endfor %}
{% endif %} diff --git a/ietf/wgchairs/urls.py b/ietf/wgchairs/urls.py index d8cadb8ee..b9b32c240 100644 --- a/ietf/wgchairs/urls.py +++ b/ietf/wgchairs/urls.py @@ -3,7 +3,5 @@ from django.conf.urls.defaults import patterns, url urlpatterns = patterns('ietf.wgchairs.views', - url(r'^workflows/$', 'manage_workflow', name='manage_workflow'), url(r'^delegates/$', 'manage_delegates', name='manage_delegates'), - url(r'^shepherds/$', 'wg_shepherd_documents', name='manage_shepherds'), ) diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py index 3bcd6e026..1f9552e3d 100644 --- a/ietf/wgchairs/views.py +++ b/ietf/wgchairs/views.py @@ -51,133 +51,6 @@ def manage_delegates(request, acronym): }, RequestContext(request)) -def manage_workflow(request, acronym): - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - user = request.user - if not can_manage_workflow_in_group(user, wg): - return HttpResponseForbidden("You don't have permission to access this view") - workflow = get_workflow_for_wg(wg) - default_workflow = get_default_workflow_for_wg() - formset = None - if request.method == 'POST': - form = workflow_form_factory(request, wg=wg, user=user) - if form.is_valid(): - form.save() - elif isinstance(form, TransitionFormSet): - formset = form - tags = workflow.selected_tags.all() - default_tags = default_workflow.annotation_tags.all() - states = workflow.selected_states.all().order_by('statedescription__order') - default_states = default_workflow.states.all().order_by('statedescription__order') - for i in default_states: - if states.filter(name=i.name).count() == 1: - i.used = True - if i.name in REQUIRED_STATES: - i.freeze = True - for i in default_tags: - if tags.filter(name=i.name).count() == 1: - i.used = True - if not formset: - formset = TransitionFormSet(queryset=workflow.transitions.all(), user=user, wg=wg) - - return render_to_response('wgchairs/manage_workflow.html', - {'wg': wg, - 'workflow': workflow, - 'default_workflow': default_workflow, - 'states': states, - 'tags': tags, - 'default_states': default_states, - 'default_tags': default_tags, - 'formset': formset, - 'selected': 'manage_workflow', - }, RequestContext(request)) - -def manage_workflowREDESIGN(request, acronym): - from ietf.doc.models import State - from ietf.group.models import GroupStateTransitions - - MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub') - - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - user = request.user - if not can_manage_workflow_in_group(user, wg): - return HttpResponseForbidden("You don't have permission to access this view") - - if request.method == 'POST': - action = request.POST.get("action") - if action == "setstateactive": - active = request.POST.get("active") == "1" - try: - state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state")) - except State.DoesNotExist: - return HttpResponse("Invalid state %s" % request.POST.get("state")) - - if active: - wg.unused_states.remove(state) - else: - wg.unused_states.add(state) - - if action == "setnextstates": - try: - state = State.objects.get(pk=request.POST.get("state")) - except State.DoesNotExist: - return HttpResponse("Invalid state %s" % request.POST.get("state")) - - next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states")) - unused = wg.unused_states.all() - if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)): - # just use the default - wg.groupstatetransitions_set.filter(state=state).delete() - else: - transitions, _ = GroupStateTransitions.objects.get_or_create(group=wg, state=state) - transitions.next_states = next_states - - if action == "settagactive": - active = request.POST.get("active") == "1" - try: - tag = DocTagName.objects.get(pk=request.POST.get("tag")) - except DocTagName.DoesNotExist: - return HttpResponse("Invalid tag %s" % request.POST.get("tag")) - - if active: - wg.unused_tags.remove(tag) - else: - wg.unused_tags.add(tag) - - - # put some info for the template on tags and states - unused_tags = wg.unused_tags.all().values_list('slug', flat=True) - tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf")) - for t in tags: - t.used = t.slug not in unused_tags - - unused_states = wg.unused_states.all().values_list('slug', flat=True) - states = State.objects.filter(used=True, type="draft-stream-ietf") - transitions = dict((o.state, o) for o in wg.groupstatetransitions_set.all()) - for s in states: - s.used = s.slug not in unused_states - s.mandatory = s.slug in MANDATORY_STATES - - default_n = s.next_states.all() - if s in transitions: - n = transitions[s].next_states.all() - else: - n = default_n - - s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states] - s.used_next_states = [x for x in n if x.slug not in unused_states] - - return render_to_response('wgchairs/manage_workflowREDESIGN.html', - {'wg': wg, - 'states': states, - 'tags': tags, - 'selected': 'manage_workflow', - }, RequestContext(request)) - - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - manage_workflow = manage_workflowREDESIGN - def wg_shepherd_documents(request, acronym): wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) user = request.user diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 670d876c5..eb73783c0 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -20,7 +20,7 @@ from ietf.group.models import * from ietf.group.utils import save_group_in_history from ietf.wgcharter.mails import email_secretariat from ietf.person.forms import EmailsField - +from ietf.doc.utils import get_tags_for_stream_id class WGForm(forms.Form): name = forms.CharField(max_length=255, label="WG Name", required=True) @@ -320,3 +320,81 @@ def conclude(request, acronym): dict(form=form, wg=wg), context_instance=RequestContext(request)) + + +def customize_workflow(request, acronym): + MANDATORY_STATES = ('c-adopt', 'wg-doc', 'sub-pub') + + group = get_object_or_404(Group, acronym=acronym, type="wg") + if not request.user.is_authenticated() or not (has_role(request.user, "Secretariat") or group.role_set.filter(name="chair", person__user=request.user)): + return HttpResponseForbidden("You don't have permission to access this view") + + if request.method == 'POST': + action = request.POST.get("action") + if action == "setstateactive": + active = request.POST.get("active") == "1" + try: + state = State.objects.exclude(slug__in=MANDATORY_STATES).get(pk=request.POST.get("state")) + except State.DoesNotExist: + return HttpResponse("Invalid state %s" % request.POST.get("state")) + + if active: + group.unused_states.remove(state) + else: + group.unused_states.add(state) + + if action == "setnextstates": + try: + state = State.objects.get(pk=request.POST.get("state")) + except State.DoesNotExist: + return HttpResponse("Invalid state %s" % request.POST.get("state")) + + next_states = State.objects.filter(used=True, type='draft-stream-ietf', pk__in=request.POST.getlist("next_states")) + unused = group.unused_states.all() + if set(next_states.exclude(pk__in=unused)) == set(state.next_states.exclude(pk__in=unused)): + # just use the default + group.groupstatetransitions_set.filter(state=state).delete() + else: + transitions, _ = GroupStateTransitions.objects.get_or_create(group=group, state=state) + transitions.next_states = next_states + + if action == "settagactive": + active = request.POST.get("active") == "1" + try: + tag = DocTagName.objects.get(pk=request.POST.get("tag")) + except DocTagName.DoesNotExist: + return HttpResponse("Invalid tag %s" % request.POST.get("tag")) + + if active: + group.unused_tags.remove(tag) + else: + group.unused_tags.add(tag) + + + # put some info for the template on tags and states + unused_tags = group.unused_tags.all().values_list('slug', flat=True) + tags = DocTagName.objects.filter(slug__in=get_tags_for_stream_id("ietf")) + for t in tags: + t.used = t.slug not in unused_tags + + unused_states = group.unused_states.all().values_list('slug', flat=True) + states = State.objects.filter(used=True, type="draft-stream-ietf") + transitions = dict((o.state, o) for o in group.groupstatetransitions_set.all()) + for s in states: + s.used = s.slug not in unused_states + s.mandatory = s.slug in MANDATORY_STATES + + default_n = s.next_states.all() + if s in transitions: + n = transitions[s].next_states.all() + else: + n = default_n + + s.next_states_checkboxes = [(x in n, x in default_n, x) for x in states] + s.used_next_states = [x for x in n if x.slug not in unused_states] + + return render_to_response('wginfo/customize_workflow.html', { + 'group': group, + 'states': states, + 'tags': tags, + }, RequestContext(request)) diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index 956ee2de6..bad932b21 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -29,6 +29,6 @@ urlpatterns = patterns('', (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-]+)/workflow/$', edit.customize_workflow), (r'^(?P[^/]+)/management/', include('ietf.wgchairs.urls')), - ) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 446c1ba59..b45310929 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -49,10 +49,6 @@ from ietf.person.models import Email from ietf.group.utils import get_charter_text from ietf.doc.templatetags.ietf_filters import clean_whitespace -from ietf.wgchairs.accounts import (can_manage_workflow_in_group, - can_manage_delegates_in_group, - can_manage_shepherds_in_group) - def fill_in_charter_info(group, include_drafts=False): group.areadirector = group.ad.role_email("ad", group.parent) if group.ad else None @@ -179,9 +175,6 @@ def construct_group_menu_context(request, group, selected, others): d = { "group": group, "selected": selected, - "can_manage_delegates": can_manage_delegates_in_group(request.user, group), - "can_manage_workflow": can_manage_workflow_in_group(request.user, group), - "can_manage_shepherds": can_manage_shepherds_in_group(request.user, group), } d.update(others) @@ -274,6 +267,10 @@ def group_charter(request, acronym): is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user) + if is_chair or has_role(request.user, "Secretariat"): + actions.append((u"Manage delegates", urlreverse("manage_delegates", kwargs=dict(acronym=group.acronym)))) + actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym)))) + return render_to_response('wginfo/group_charter.html', construct_group_menu_context(request, group, "charter", { "actions": actions, From 9409814ada5892b7043968265aff6613790f1f51 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:22:11 +0000 Subject: [PATCH 10/20] Fix missing import - Legacy-Id: 6137 --- ietf/wginfo/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index b45310929..87f4d8caf 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -48,6 +48,7 @@ from ietf.doc.utils import get_chartering_type from ietf.person.models import Email from ietf.group.utils import get_charter_text from ietf.doc.templatetags.ietf_filters import clean_whitespace +from ietf.ietfauth.utils import has_role def fill_in_charter_info(group, include_drafts=False): From 8657e4fd08a4a7a510e3c17f2cd089fedcf2b917 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Tue, 10 Sep 2013 16:23:22 +0000 Subject: [PATCH 11/20] Redirect when POSTing on workflow customization page to prevent the history from filling up with spam entries - Legacy-Id: 6138 --- ietf/wginfo/edit.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index eb73783c0..09814d3a0 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -343,6 +343,10 @@ def customize_workflow(request, acronym): else: group.unused_states.add(state) + # redirect so the back button works correctly, otherwise + # repeated POSTs fills up the history + return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym) + if action == "setnextstates": try: state = State.objects.get(pk=request.POST.get("state")) @@ -358,6 +362,8 @@ 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) + if action == "settagactive": active = request.POST.get("active") == "1" try: @@ -370,6 +376,8 @@ def customize_workflow(request, acronym): else: group.unused_tags.add(tag) + return redirect("ietf.wginfo.edit.customize_workflow", acronym=group.acronym) + # put some info for the template on tags and states unused_tags = group.unused_tags.all().values_list('slug', flat=True) From 36d4710393b0967dcd44c0bc05baa79a4390eddb Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Wed, 11 Sep 2013 17:28:33 +0000 Subject: [PATCH 12/20] Fix styling of next states in workflow customization, replace "+" with "+ customize" - Legacy-Id: 6142 --- ietf/templates/wginfo/customize_workflow.html | 58 ++++++------------- 1 file changed, 19 insertions(+), 39 deletions(-) diff --git a/ietf/templates/wginfo/customize_workflow.html b/ietf/templates/wginfo/customize_workflow.html index d1c939e64..082ecfe3d 100644 --- a/ietf/templates/wginfo/customize_workflow.html +++ b/ietf/templates/wginfo/customize_workflow.html @@ -5,45 +5,25 @@ {% block morecss %} {{ block.super }} .state-table .inactive, -.tag-table .inactive { - font-style: italic; +.tag-table .inactive { font-style: italic; color: #666; } +.state-table .state { margin-bottom: 0.1em; } +.state-table .set-next-states label { display: block; cursor: pointer; } +.state-table .set-next-states label input { vertical-align: middle; } +.state-table .set-state input, .set-tag input { width: 6em; } +.state-table .toggled { display: none; } +.state-table .toggler { color: #666; -} -.state-table .state { - padding-right: 0.6em; -} -.set-next-states { - margin-top: 1em; -} -.set-next-states label { - display: block; - cursor: pointer; -} -.set-next-states label input { - vertical-align: middle; -} -.set-state input, .set-tag input { - width: 6em; -} -.toggled { - display: none; -} -.toggler { - color: #000; + background: #ddd; + font-weight: bold; text-decoration: none; - padding: 0px 3px; + padding: 1px 3px; display: inline-block; margin-left: 0.5em; - font-size: 15px; - font-weight: bold; -} -.inactive .toggler { - color: #666; -} -.toggler:hover { - background-color: #999; - color: #fff; + margin-top: 0.5em; + margin-bottom: 0.5em; } +.state-table .inactive .toggler { color: #aaa; background: #eee; } +.state-table .toggler:hover { background-color: #999; color: #fff; } {% endblock %} {% block content %} @@ -95,11 +75,11 @@ in Section 4.1 of RFC61
Select the next states: @@ -153,11 +133,11 @@ jQuery('.state-table .toggler').click(function(e) { var toggler = jQuery(this), toggled = toggler.parent().siblings(".toggled"); if (toggled.is(":hidden")) { - toggler.html("–"); + toggler.html("– customize"); toggled.slideDown(300); } else { - toggler.html("+"); + toggler.html("+ customize"); toggled.slideUp(300); } }); From 5493f3c61346fbb89c6ba8ef15acc13a49e8a7d3 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 12 Sep 2013 16:36:10 +0000 Subject: [PATCH 13/20] Fix missing import statement in for customize_workflow - Legacy-Id: 6146 --- ietf/wginfo/edit.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 09814d3a0..068a62b10 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -1,8 +1,9 @@ # edit/create view for WGs -import re, os, string, datetime, shutil +import re, os, datetime, shutil from django.shortcuts import render_to_response, get_object_or_404, redirect +from django.http import HttpResponseForbidden from django.core.urlresolvers import reverse from django.template import RequestContext from django import forms From 570b7577477979c2fdf3e1bfa9a6d8857fa72f03 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 12 Sep 2013 16:36:27 +0000 Subject: [PATCH 14/20] Move group workflow tests to wginfo - Legacy-Id: 6147 --- ietf/wginfo/tests.py | 72 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/ietf/wginfo/tests.py b/ietf/wginfo/tests.py index ea5dbb45e..7615e23bc 100644 --- a/ietf/wginfo/tests.py +++ b/ietf/wginfo/tests.py @@ -817,3 +817,75 @@ class MilestoneTestCase(django.test.TestCase): self.assertTrue(group.acronym in outbox[-1]["Subject"]) self.assertTrue(m1.desc in unicode(outbox[-1])) self.assertTrue(m2.desc in unicode(outbox[-1])) + +class CustomizeWorkflowTestCase(django.test.TestCase): + fixtures = ['names'] + + def test_customize_workflow(self): + make_test_data() + + group = Group.objects.get(acronym="mars") + + url = urlreverse('ietf.wginfo.edit.customize_workflow', kwargs=dict(acronym=group.acronym)) + login_testing_unauthorized(self, "secretary", url) + + state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc") + self.assertTrue(state not in group.unused_states.all()) + + # get + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + q = PyQuery(r.content) + self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='0']")), 1) + + # deactivate state + r = self.client.post(url, + dict(action="setstateactive", + state=state.pk, + active="0")) + self.assertEquals(r.status_code, 302) + r = self.client.get(url) + q = PyQuery(r.content) + self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='1']")), 1) + group = Group.objects.get(acronym=group.acronym) + self.assertTrue(state in group.unused_states.all()) + + # change next states + state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-doc") + next_states = State.objects.filter(used=True, type=b"draft-stream-ietf", slug__in=["parked", "dead", "wait-wgw", 'sub-pub']).values_list('pk', flat=True) + r = self.client.post(url, + dict(action="setnextstates", + state=state.pk, + next_states=next_states)) + self.assertEquals(r.status_code, 302) + r = self.client.get(url) + q = PyQuery(r.content) + self.assertEquals(len(q("form.set-next-states").find("input[name=state][value='%s']" % state.pk).parents('form').find("input[name=next_states][checked=checked]")), len(next_states)) + transitions = GroupStateTransitions.objects.filter(group=group, state=state) + self.assertEquals(len(transitions), 1) + self.assertEquals(set(transitions[0].next_states.values_list("pk", flat=True)), set(next_states)) + + # change them back to default + next_states = state.next_states.values_list("pk", flat=True) + r = self.client.post(url, + dict(action="setnextstates", + state=state.pk, + next_states=next_states)) + self.assertEquals(r.status_code, 302) + r = self.client.get(url) + q = PyQuery(r.content) + transitions = GroupStateTransitions.objects.filter(group=group, state=state) + self.assertEquals(len(transitions), 0) + + # deactivate tag + tag = DocTagName.objects.get(slug="w-expert") + r = self.client.post(url, + dict(action="settagactive", + tag=tag.pk, + active="0")) + self.assertEquals(r.status_code, 302) + r = self.client.get(url) + q = PyQuery(r.content) + self.assertEquals(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1) + group = Group.objects.get(acronym=group.acronym) + self.assertTrue(tag in group.unused_tags.all()) From f4761ba7c13649eef5ae28e15047466eed330ce8 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 11:01:32 +0000 Subject: [PATCH 15/20] Get rid of unused wgchairs references - Legacy-Id: 6193 --- ietf/ietfworkflows/templatetags/ietf_streams.py | 2 -- ietf/ietfworkflows/templatetags/ietf_streams_redesign.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/ietf/ietfworkflows/templatetags/ietf_streams.py b/ietf/ietfworkflows/templatetags/ietf_streams.py index f9e69803f..5d8b5ca51 100644 --- a/ietf/ietfworkflows/templatetags/ietf_streams.py +++ b/ietf/ietfworkflows/templatetags/ietf_streams.py @@ -5,8 +5,6 @@ from django.core.urlresolvers import reverse as urlreverse from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_state_for_draft) -from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document, - can_manage_writeup_of_a_document) from ietf.ietfworkflows.streams import get_stream_from_wrapper from ietf.ietfworkflows.models import Stream from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream, diff --git a/ietf/ietfworkflows/templatetags/ietf_streams_redesign.py b/ietf/ietfworkflows/templatetags/ietf_streams_redesign.py index 978e99e74..852911126 100644 --- a/ietf/ietfworkflows/templatetags/ietf_streams_redesign.py +++ b/ietf/ietfworkflows/templatetags/ietf_streams_redesign.py @@ -5,8 +5,6 @@ from django.core.urlresolvers import reverse as urlreverse from ietf.idrfc.idrfc_wrapper import IdRfcWrapper, IdWrapper from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_state_for_draft) -from ietf.wgchairs.accounts import (can_manage_shepherd_of_a_document, - can_manage_writeup_of_a_document) from ietf.ietfworkflows.streams import get_stream_from_wrapper from ietf.ietfworkflows.models import Stream from ietf.ietfworkflows.accounts import (can_edit_state, can_edit_stream, From 3562c5ef0664055fc8f4a9d65ebff79288b938b3 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 11:02:24 +0000 Subject: [PATCH 16/20] Rewrite slightly to avoid using wgchairs.accounts.get_person_for_user - Legacy-Id: 6194 --- ietf/ietfworkflows/forms.py | 6 ++++-- ietf/secr/announcement/forms.py | 3 +-- ietf/secr/announcement/views.py | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ietf/ietfworkflows/forms.py b/ietf/ietfworkflows/forms.py index 7f9dd1fdf..c5cef4f57 100644 --- a/ietf/ietfworkflows/forms.py +++ b/ietf/ietfworkflows/forms.py @@ -7,7 +7,6 @@ from workflows.models import State from workflows.utils import set_workflow_for_object from ietf.idtracker.models import PersonOrOrgInfo, IETFWG, InternetDraft -from ietf.wgchairs.accounts import get_person_for_user from ietf.ietfworkflows.models import Stream, StreamDelegate from ietf.ietfworkflows.utils import (get_workflow_for_draft, get_workflow_for_wg, get_state_for_draft, get_state_by_name, @@ -33,7 +32,10 @@ class StreamDraftForm(forms.Form): def __init__(self, *args, **kwargs): self.draft = kwargs.pop('draft', None) self.user = kwargs.pop('user', None) - self.person = get_person_for_user(self.user) + try: + self.person = self.user.get_profile() + except: + self.person = None self.workflow = get_workflow_for_draft(self.draft) self.message = {} super(StreamDraftForm, self).__init__(*args, **kwargs) diff --git a/ietf/secr/announcement/forms.py b/ietf/secr/announcement/forms.py index 64293c324..e74498d57 100644 --- a/ietf/secr/announcement/forms.py +++ b/ietf/secr/announcement/forms.py @@ -7,7 +7,6 @@ from ietf.secr.utils.group import current_nomcom from ietf.message.models import Message from ietf.ietfauth.decorators import has_role -from ietf.wgchairs.accounts import get_person_for_user # --------------------------------------------- # Globals @@ -158,7 +157,7 @@ class AnnounceForm(forms.ModelForm): def save(self, *args, **kwargs): user = kwargs.pop('user') message = super(AnnounceForm, self).save(commit=False) - message.by = get_person_for_user(user) + message.by = user.get_profile() if self.cleaned_data['to'] == 'Other...': message.to = self.cleaned_data['to_custom'] if kwargs['commit']: diff --git a/ietf/secr/announcement/views.py b/ietf/secr/announcement/views.py index 8d6ba084c..c10ac692b 100644 --- a/ietf/secr/announcement/views.py +++ b/ietf/secr/announcement/views.py @@ -6,7 +6,6 @@ from django.template import RequestContext from ietf.ietfauth.decorators import has_role from ietf.utils.mail import send_mail_text -from ietf.wgchairs.accounts import get_person_for_user from ietf.group.models import Group from ietf.secr.utils.group import current_nomcom from ietf.secr.utils.decorators import check_for_cancel @@ -104,4 +103,4 @@ def confirm(request): 'message': data, 'to': to}, RequestContext(request, {}), - ) \ No newline at end of file + ) From 81ba5ef9593db0de79f55583b366f07f79229f8c Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 11:04:31 +0000 Subject: [PATCH 17/20] Move delegate handling to group edit page (like other group personnel), show group delegates in the charter page with the other personnel - Legacy-Id: 6195 --- ietf/templates/wginfo/group_charter.html | 11 +++++++++++ ietf/wginfo/edit.py | 25 +++++++++++++++++------- ietf/wginfo/tests.py | 2 ++ ietf/wginfo/urls.py | 1 - ietf/wginfo/views.py | 2 +- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/ietf/templates/wginfo/group_charter.html b/ietf/templates/wginfo/group_charter.html index 7175748a3..b29f6a918 100644 --- a/ietf/templates/wginfo/group_charter.html +++ b/ietf/templates/wginfo/group_charter.html @@ -105,6 +105,17 @@ is occasionally incorrect. {% endif %} + {% if group.delegates %} + + Delegate{{ group.delegates|pluralize }}: + + {% for delegate in group.delegates %} + {{ delegate.person.plain_name }} <{{ delegate.address }}>
+ {% endfor %} + + + {% endif %} + Mailing List Address:{{ group.list_email|urlize }} diff --git a/ietf/wginfo/edit.py b/ietf/wginfo/edit.py index 068a62b10..92009b0b0 100644 --- a/ietf/wginfo/edit.py +++ b/ietf/wginfo/edit.py @@ -23,13 +23,16 @@ from ietf.wgcharter.mails import email_secretariat from ietf.person.forms import EmailsField from ietf.doc.utils import get_tags_for_stream_id +MAX_GROUP_DELEGATES = 3 + class WGForm(forms.Form): - name = forms.CharField(max_length=255, label="WG Name", required=True) - acronym = forms.CharField(max_length=10, label="WG Acronym", required=True) - state = forms.ModelChoiceField(GroupStateName.objects.all(), label="WG State", required=True) - chairs = EmailsField(label="WG Chairs", required=False) - secretaries = EmailsField(label="WG Secretaries", required=False) - techadv = EmailsField(label="WG Technical Advisors", required=False) + name = forms.CharField(max_length=255, label="Name", required=True) + acronym = forms.CharField(max_length=10, label="Acronym", required=True) + state = forms.ModelChoiceField(GroupStateName.objects.all(), label="State", required=True) + chairs = EmailsField(label="Chairs", required=False) + secretaries = EmailsField(label="Secretaries", required=False) + techadv = EmailsField(label="Technical Advisors", required=False) + delegates = EmailsField(label="Delegates", required=False, help_text=mark_safe("Type in name to search for person
Chairs can delegate the authority to update the state of group documents - max %s persons at a given time" % MAX_GROUP_DELEGATES)) ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'), label="Shepherding AD", empty_label="(None)", required=False) parent = forms.ModelChoiceField(Group.objects.filter(type="area", state="active").order_by('name'), label="IETF Area", empty_label="(None)", required=False) list_email = forms.CharField(max_length=64, required=False) @@ -97,6 +100,13 @@ class WGForm(forms.Form): def clean_urls(self): return [x.strip() for x in self.cleaned_data["urls"].splitlines() if x.strip()] + def clean_delegates(self): + if len(self.cleaned_data["delegates"]) > MAX_GROUP_DELEGATES: + raise forms.ValidationError("At most %s delegates can be appointed at the same time, please remove %s delegates." % ( + MAX_GROUP_DELEGATES, len(self.cleaned_data["delegates"]) - MAX_GROUP_DELEGATES)) + return self.cleaned_data["delegates"] + + def format_urls(urls, fs="\n"): res = [] for u in urls: @@ -221,7 +231,7 @@ def edit(request, acronym=None, action="edit"): shutil.copy(old, new) # update roles - for attr, slug, title in [('chairs', 'chair', "Chairs"), ('secretaries', 'secr', "Secretaries"), ('techadv', 'techadv', "Tech Advisors")]: + for attr, slug, title in [('chairs', 'chair', "Chairs"), ('secretaries', 'secr', "Secretaries"), ('techadv', 'techadv', "Tech Advisors"), ('delegates', 'delegate', "Delegates")]: new = clean[attr] old = Email.objects.filter(role__group=wg, role__name=slug).select_related("person") if set(new) != set(old): @@ -269,6 +279,7 @@ def edit(request, acronym=None, action="edit"): chairs=Email.objects.filter(role__group=wg, role__name="chair"), secretaries=Email.objects.filter(role__group=wg, role__name="secr"), techadv=Email.objects.filter(role__group=wg, role__name="techadv"), + delegates=Email.objects.filter(role__group=wg, role__name="delegate"), ad=wg.ad_id if wg.ad else None, parent=wg.parent.id if wg.parent else None, list_email=wg.list_email if wg.list_email else None, diff --git a/ietf/wginfo/tests.py b/ietf/wginfo/tests.py index 7615e23bc..33134b233 100644 --- a/ietf/wginfo/tests.py +++ b/ietf/wginfo/tests.py @@ -355,6 +355,7 @@ class WgEditTestCase(django.test.TestCase): chairs="aread@ietf.org, ad1@ietf.org", secretaries="aread@ietf.org, ad1@ietf.org, ad2@ietf.org", techadv="aread@ietf.org", + delegates="ad2@ietf.org", list_email="mars@mail", list_subscribe="subscribe.mars", list_archive="archive.mars", @@ -375,6 +376,7 @@ class WgEditTestCase(django.test.TestCase): self.assertEquals(group.ad, ad) for k in ("chair", "secr", "techadv"): self.assertTrue(group.role_set.filter(name=k, email__address="aread@ietf.org")) + self.assertTrue(group.role_set.filter(name="delegate", email__address="ad2@ietf.org")) self.assertEquals(group.list_email, "mars@mail") self.assertEquals(group.list_subscribe, "subscribe.mars") self.assertEquals(group.list_archive, "archive.mars") diff --git a/ietf/wginfo/urls.py b/ietf/wginfo/urls.py index bad932b21..b0106f144 100644 --- a/ietf/wginfo/urls.py +++ b/ietf/wginfo/urls.py @@ -30,5 +30,4 @@ urlpatterns = patterns('', (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-]+)/workflow/$', edit.customize_workflow), - (r'^(?P[^/]+)/management/', include('ietf.wgchairs.urls')), ) diff --git a/ietf/wginfo/views.py b/ietf/wginfo/views.py index 87f4d8caf..27871eb8b 100644 --- a/ietf/wginfo/views.py +++ b/ietf/wginfo/views.py @@ -255,6 +255,7 @@ def group_charter(request, acronym): group = get_object_or_404(Group, type="wg", acronym=acronym) fill_in_charter_info(group, include_drafts=False) + group.delegates = Email.objects.filter(role__group=group, role__name="delegate") actions = [] if group.state_id != "conclude": @@ -269,7 +270,6 @@ def group_charter(request, acronym): is_chair = request.user.is_authenticated() and group.role_set.filter(name="chair", person__user=request.user) if is_chair or has_role(request.user, "Secretariat"): - actions.append((u"Manage delegates", urlreverse("manage_delegates", kwargs=dict(acronym=group.acronym)))) actions.append((u"Customize workflow", urlreverse("ietf.wginfo.edit.customize_workflow", kwargs=dict(acronym=group.acronym)))) return render_to_response('wginfo/group_charter.html', From 8ffecd80158dd25a33f21bc705f7efff884d7090 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 11:05:21 +0000 Subject: [PATCH 18/20] Clean up a couple of old-school tags in group edit template, add link to account creation for personnel - Legacy-Id: 6196 --- ietf/templates/wginfo/edit.html | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/ietf/templates/wginfo/edit.html b/ietf/templates/wginfo/edit.html index 2ca32f710..8af9917b8 100644 --- a/ietf/templates/wginfo/edit.html +++ b/ietf/templates/wginfo/edit.html @@ -9,6 +9,7 @@ Start chartering new WG {% endblock %} {% block morecss %} +form.edit td { padding-bottom: .5em; } form.edit #id_name, form.edit #id_list_email, form.edit #id_list_subscribe, @@ -16,8 +17,7 @@ form.edit #id_list_archive, form.edit #id_urls, form.edit #id_comments { width: 400px; } form.edit input[type=checkbox] { vertical-align: middle; } -ul.errorlist { border-width: 0px; padding: 0px; margin: 0px;} -ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; } +form.edit #id_urls { height: 4em; } {% endblock %} {% block pagehead %} @@ -27,28 +27,30 @@ ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; } {% block content %} {% load ietf_filters %}

-{% ifequal action "edit" %} +{% if action == "edit" %} Edit WG {{ wg.acronym }} {% else %} - {% ifequal action "charter" %} + {% if action == "charter" %} Start chartering new WG {% else %} Create new WG or BoF - {% endifequal %} -{% endifequal %} + {% endif %} +{% endif %}

+

Note that persons with authorization to manage information, e.g. +chairs and delegates, need a Datatracker account to actually do +so. New accounts can be created here.

+ {% for field in form.visible_fields %} @@ -65,16 +67,16 @@ Create new WG or BoF
{{ field.label_tag }}: {% if field.field.required %}*{% endif %} {{ field }} - {% ifequal field.name "ad" %} - {% if user|has_role:"Area Director" %} + {% if field.name == "ad" and user|has_role:"Area Director" %} {% endif %} - {% endifequal %} {% if field.help_text %}
{{ field.help_text }}
{% endif %} {{ field.errors }}
- {% ifequal action "edit" %} - Back - + {% if action == "edit" %} + Cancel + {% else %} - {% ifequal action "charter" %} + {% if action == "charter" %} {% else %} - {% endifequal %} - {% endifequal %} + {% endif %} + {% endif %}
From 19fc7c14bcd86e29f34d21ba4778f6881f24ef20 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 15:19:12 +0000 Subject: [PATCH 19/20] Increase contrast a bit for the customize buttons - Legacy-Id: 6197 --- ietf/templates/wginfo/customize_workflow.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ietf/templates/wginfo/customize_workflow.html b/ietf/templates/wginfo/customize_workflow.html index 082ecfe3d..147267aaf 100644 --- a/ietf/templates/wginfo/customize_workflow.html +++ b/ietf/templates/wginfo/customize_workflow.html @@ -12,7 +12,7 @@ .state-table .set-state input, .set-tag input { width: 6em; } .state-table .toggled { display: none; } .state-table .toggler { - color: #666; + color: #444; background: #ddd; font-weight: bold; text-decoration: none; @@ -23,7 +23,7 @@ margin-bottom: 0.5em; } .state-table .inactive .toggler { color: #aaa; background: #eee; } -.state-table .toggler:hover { background-color: #999; color: #fff; } +.state-table .toggler:hover { color: #fff; background-color: #999; } {% endblock %} {% block content %} From a871d6e19e647a072a20201bac812ac07860e1b5 Mon Sep 17 00:00:00 2001 From: Ole Laursen Date: Thu, 19 Sep 2013 15:22:59 +0000 Subject: [PATCH 20/20] Remove wgchairs app, all of its functionality is now superceded by wginfo/ and other recent developments in doc/ - Legacy-Id: 6198 --- bin/mkdiagram | 2 +- ietf/doc/proxy.py | 5 - ietf/group/proxy.py | 16 +- ietf/settings.py | 1 - .../wgchairs/confirm_management_writeup.html | 55 -- ietf/templates/wgchairs/draft_state.html | 1 - .../wgchairs/edit_management_shepherd.html | 41 -- .../wgchairs/edit_management_writeup.html | 67 --- ietf/templates/wgchairs/manage_delegates.html | 60 --- ietf/templates/wgchairs/manage_workflow.html | 165 ------ ietf/templates/wgchairs/notexistdelegate.html | 28 - .../notexistsdelegate_delegate_email.txt | 10 - .../notexistsdelegate_secretariat_email.txt | 15 - .../notexistsdelegate_wgchairs_email.txt | 12 - .../wgchairs/shepherd_document_row.html | 17 - .../wgchairs/wg_shepherd_documents.html | 122 ----- .../wgchairs/wgchairs_admin_options.html | 23 - ietf/templates/wginfo/wg_base.html | 83 --- ietf/wgchairs/.gitignore | 1 - ietf/wgchairs/__init__.py | 18 - ietf/wgchairs/accounts.py | 108 ---- ietf/wgchairs/forms.py | 478 ------------------ ietf/wgchairs/migrations/.gitignore | 1 - ietf/wgchairs/migrations/0001_initial.py | 110 ---- ietf/wgchairs/migrations/0002_add_writeup.py | 163 ------ ietf/wgchairs/migrations/__init__.py | 0 ietf/wgchairs/models.py | 87 ---- ietf/wgchairs/templatetags/.gitignore | 1 - ietf/wgchairs/templatetags/__init__.py | 0 ietf/wgchairs/templatetags/wgchairs_tags.py | 47 -- ietf/wgchairs/tests.py | 214 -------- ietf/wgchairs/urls.py | 7 - ietf/wgchairs/views.py | 73 --- 33 files changed, 15 insertions(+), 2016 deletions(-) delete mode 100644 ietf/templates/wgchairs/confirm_management_writeup.html delete mode 100644 ietf/templates/wgchairs/draft_state.html delete mode 100644 ietf/templates/wgchairs/edit_management_shepherd.html delete mode 100644 ietf/templates/wgchairs/edit_management_writeup.html delete mode 100644 ietf/templates/wgchairs/manage_delegates.html delete mode 100644 ietf/templates/wgchairs/manage_workflow.html delete mode 100644 ietf/templates/wgchairs/notexistdelegate.html delete mode 100644 ietf/templates/wgchairs/notexistsdelegate_delegate_email.txt delete mode 100644 ietf/templates/wgchairs/notexistsdelegate_secretariat_email.txt delete mode 100644 ietf/templates/wgchairs/notexistsdelegate_wgchairs_email.txt delete mode 100644 ietf/templates/wgchairs/shepherd_document_row.html delete mode 100644 ietf/templates/wgchairs/wg_shepherd_documents.html delete mode 100644 ietf/templates/wgchairs/wgchairs_admin_options.html delete mode 100644 ietf/templates/wginfo/wg_base.html delete mode 100644 ietf/wgchairs/.gitignore delete mode 100644 ietf/wgchairs/__init__.py delete mode 100644 ietf/wgchairs/accounts.py delete mode 100644 ietf/wgchairs/forms.py delete mode 100644 ietf/wgchairs/migrations/.gitignore delete mode 100644 ietf/wgchairs/migrations/0001_initial.py delete mode 100644 ietf/wgchairs/migrations/0002_add_writeup.py delete mode 100644 ietf/wgchairs/migrations/__init__.py delete mode 100644 ietf/wgchairs/models.py delete mode 100644 ietf/wgchairs/templatetags/.gitignore delete mode 100644 ietf/wgchairs/templatetags/__init__.py delete mode 100644 ietf/wgchairs/templatetags/wgchairs_tags.py delete mode 100644 ietf/wgchairs/tests.py delete mode 100644 ietf/wgchairs/urls.py delete mode 100644 ietf/wgchairs/views.py diff --git a/bin/mkdiagram b/bin/mkdiagram index 765a7ba52..5eca0efc1 100755 --- a/bin/mkdiagram +++ b/bin/mkdiagram @@ -9,7 +9,7 @@ trap 'echo "$program($LINENO): Command failed with error code $? ($0 $*)"; exit if [ "$*" ]; then apps="$@"; graph="${1%.*}"; else apps=$(ls */models.py | sed 's!/models.py!!'); graph="models"; fi newapps="doc group meeting message person name" -legacyapps="announcements idindex idrfc idtracker iesg ietfauth ietfworkflows ipr liaisons mailinglists proceedings redirects submit wgchairs wgcharter wginfo" +legacyapps="announcements idindex idrfc idtracker iesg ietfauth ietfworkflows ipr liaisons mailinglists proceedings redirects submit wgcharter wginfo" proxy="$(grep ^class */proxy.py | tr '()' ' ' | awk '{printf $2 ","}')" names="$(grep ^class name/models.py | tr '()' ' ' | awk '{printf $2 ","}')" diff --git a/ietf/doc/proxy.py b/ietf/doc/proxy.py index 21993174c..6b2fbe15c 100644 --- a/ietf/doc/proxy.py +++ b/ietf/doc/proxy.py @@ -194,11 +194,6 @@ class InternetDraft(Document): def authors(self): return IDAuthor.objects.filter(document=self) - @property - def protowriteup_set(self): - from ietf.wgchairs.models import ProtoWriteUpProxy - return ProtoWriteUpProxy.objects.filter(doc=self, type="changed_protocol_writeup") - # methods from InternetDraft def displayname(self): return self.name diff --git a/ietf/group/proxy.py b/ietf/group/proxy.py index 2ab006760..5245eb0cc 100644 --- a/ietf/group/proxy.py +++ b/ietf/group/proxy.py @@ -94,6 +94,19 @@ def proxied_role_emails(emails): proxy_role_email(e) return emails +class WGDelegateProxy(Role): + #person = models.ForeignKey(PersonOrOrgInfo) # same name + #wg = models.ForeignKey(IETFWG) + @property + def wg(self): + return self.group + + def __unicode__(self): + return u"%s" % self.person + + class Meta: + proxy = True + class IETFWG(Group): objects = TranslatingManager(dict(group_acronym="id", group_acronym__acronym="acronym", @@ -211,8 +224,7 @@ class IETFWG(Group): return d @property def wgdelegate_set(self): - from ietf.wgchairs.models import WGDelegate - return WGDelegate.objects.filter(group=self, name="delegate") + return WGDelegateProxy.objects.filter(group=self, name="delegate") class Meta: proxy = True diff --git a/ietf/settings.py b/ietf/settings.py index d3b7367cc..ad5f1069b 100644 --- a/ietf/settings.py +++ b/ietf/settings.py @@ -175,7 +175,6 @@ INSTALLED_APPS = ( 'ietf.wginfo', 'ietf.submit', 'ietf.ietfworkflows', - 'ietf.wgchairs', 'ietf.wgcharter', 'ietf.sync', 'ietf.community', diff --git a/ietf/templates/wgchairs/confirm_management_writeup.html b/ietf/templates/wgchairs/confirm_management_writeup.html deleted file mode 100644 index 3bc5ceab9..000000000 --- a/ietf/templates/wgchairs/confirm_management_writeup.html +++ /dev/null @@ -1,55 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% load ietf_filters wgchairs_tags %} - -{% block title %}Change shepherd write-up for {{ doc }}{% endblock %} - -{% block wg_content %} - -

-Return to shepherd list -

- -

Updating write-up for {{ doc }}

- -

-Before you modify the shepherd write-up please revise the 'Doc Shepherd Follow-up Underway' annotation tag and set or reset it if appropriate. -

-

-Remember that you must provide a comment if you change the annotation tag state. -

- - -
- - -{% if form.message %} - -{% endif %} - - -
Doc Shepherd Follow-up Underway
- {{ form.message.value }} -
- - - - -
-{{ form.comment }} -
-

- Change write-up and ...
- -
- Cancel, I don't want to do any change! -

- -
- - - -
New shepherd write-up
{{ form.get_writeup|linebreaksbr }}
- -
- -{% endblock %} diff --git a/ietf/templates/wgchairs/draft_state.html b/ietf/templates/wgchairs/draft_state.html deleted file mode 100644 index 956ebd44f..000000000 --- a/ietf/templates/wgchairs/draft_state.html +++ /dev/null @@ -1 +0,0 @@ -{{ state.name }} diff --git a/ietf/templates/wgchairs/edit_management_shepherd.html b/ietf/templates/wgchairs/edit_management_shepherd.html deleted file mode 100644 index b9a9e616a..000000000 --- a/ietf/templates/wgchairs/edit_management_shepherd.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% load ietf_filters %} - -{% block title %}Change shepherd for {{ doc }}{% endblock %} - -{% block wg_content %} - -

-Return to shepherd list -Return to {{ doc }} -

- -

Change shepherd for {{ doc }}

- -
-
- - - -
Actual shepherd
{% if doc.shepherd %}{{ doc.shepherd }}{% else %}No shepherd assigned{% endif %}
- - - -
-
-
- - -{% if form.message %} - -{% endif %} - - -
Change shepherd
- {{ form.message.value }} -
{{ form.as_p }}
- - {% if form.can_cancel %}No! I don't want to continue{% endif %} -
-
-{% endblock %} diff --git a/ietf/templates/wgchairs/edit_management_writeup.html b/ietf/templates/wgchairs/edit_management_writeup.html deleted file mode 100644 index 7a61437c0..000000000 --- a/ietf/templates/wgchairs/edit_management_writeup.html +++ /dev/null @@ -1,67 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% load ietf_filters wgchairs_tags %} - -{% block title %} {% if can_edit %} Change {% else %} View {% endif %} shepherd write-up for {{ doc }}{% endblock %} - -{% block wg_content %} - -

-Return to shepherd list -

- -

{% if can_edit %} Change {% else %} View {% endif %} shepherd write-up for {{ doc }}

- - - - -
Draft stateActual shepherd write-upLast updated
{% show_state doc %}{{ writeup.writeup|linebreaksbr }}{% if writeup %}{{ writeup.date }} by {{ writeup.person }}{% endif %}
- -

-Please, note that the 'Doc Shepherd Follow-up Underway' annotation tag is {% if not followup %}NOT{% endif %} set for {{ doc }}. -

- -{% if can_edit %} -
-
- - -{% if form.message %} - -{% endif %} - - -
Edit shepherd write-up
- {{ form.message.value }} -
-
- -
- -
- -
- - - -
Upload a new shepherd write-up
-

Replace the current write-up with the contents of a plain ascii file:

-
- -
-
-{% else %} -{% if authorized_user %} - - - -
Edit shepherd write-up
-

- You can not edit or upload the shepherd write-up for {{ doc }} because the draft is not on "WG Consensus: Waiting for Write-Up" state. -

-

- Please contact with the {{ wg }} Working Group chair. -

-
-{% endif %} -{% endif %} -{% endblock %} diff --git a/ietf/templates/wgchairs/manage_delegates.html b/ietf/templates/wgchairs/manage_delegates.html deleted file mode 100644 index f1f2eaf58..000000000 --- a/ietf/templates/wgchairs/manage_delegates.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "wginfo/wg_base.html" %} - - -{% block wg_titledetail %}Delegates{% endblock %} - -{% block wg_content %} -
- -

Manage delegates

-

-Sometimes, a WG has one (or more) WG Secretaries, in addition to the WG Chairs. -This page lets the WG Chairs delegate the authority to do updates to the WG state of WG documents in the datatracker. -

- -

-You may at most delegate the datatracker update rights to {{ max_delegates }} persons at any given time. -

- - - - -
-{% if delegates %} -
- - - {% for delegate in delegates %} - - {% endfor %} -
RemoveDelegate name
{{ delegate.person }}
- -
-{% else %} -No delegates -{% endif %} -
- - -{% if add_form.message %} - -{% endif %} - -
Add new delegate
- {{ add_form.message.value }} -
-{% if can_add %} -
- {{ add_form.as_p }} -

- - {% if add_form.can_cancel %}No! I don't want to continue{% endif %} -

-
-{% else %} -You can only assign {{ max_delegates }} delegates. Please remove delegates to add a new one. -{% endif %} -
-
-
-{% endblock %} diff --git a/ietf/templates/wgchairs/manage_workflow.html b/ietf/templates/wgchairs/manage_workflow.html deleted file mode 100644 index bc5a4fbd7..000000000 --- a/ietf/templates/wgchairs/manage_workflow.html +++ /dev/null @@ -1,165 +0,0 @@ -{% extends "wginfo/wg_base.html" %} - -{% block wg_titledetail %}Manage Workflow{% endblock %} - -{% block pagehead %} -{{ block.super }} - - - -{% endblock pagehead %} - -{% block wg_content %} -
-

Edit workflow

-
- - -
-
-
- - - - - {% for state in states %} - - - -{% endfor %} -
States used in {{ wg }} Working Group
{{ state.name }}

- - - - - {% for tag in tags %} - - - -{% endfor %} -
Annotation tags used in {{ wg }} Working Group
{{ tag.name }}
-
- - - - - {% for transition in workflow.transitions.all %} - - - - - - {% endfor %} - {% if not workflow.transitions.all.count %} - - {% endif %} -
Transition nameInitial statesDestination state
- {{ transition.name }} - - {% for state in transition.states.all %} - {{state.name }}{% if not forloop.last %}
{% endif %} - {% endfor %} -
- {{ transition.destination.name }} -
There are no transitions defined so any state change is allowed
-
-
- -
-

-Please note that the states you can not uncheck are needed in all IETF WGs. -

-

-You can see the default Working Group I-D State Diagram in Section 4.1 of RFC6174 -

-
- - - - - {% for state in default_states %} - - - - - -{% endfor %} -
Used in {{ wg }}Available statesDefinition
-
-
[+] {{ state.statedescription_set.all.0.definition|safe }}
-
-
- -
-
- -
-

-You can see the default Working Group I-D State Diagram in Section 4.1 of RFC6174 -

-
- - - - -{{ formset.as_table }} -
DeleteTransition nameInitial statesDestination state
- -
-
- -
-
- - - - - {% for tag in default_tags %} - - - - -{% endfor %} -
Used in {{ wg }}Available annotation tags
- -
-
-
-
- - - -{% endblock %} diff --git a/ietf/templates/wgchairs/notexistdelegate.html b/ietf/templates/wgchairs/notexistdelegate.html deleted file mode 100644 index 706907022..000000000 --- a/ietf/templates/wgchairs/notexistdelegate.html +++ /dev/null @@ -1,28 +0,0 @@ -{% if shepherd %} -

-The shepherd you are trying to designate does not have a personal user-id and password to log-on to the Datatracker. -

-

-An email will be sent to the following addresses to inform that -the person you have designated to be one of your document shepherds -currently does not have login credentials for the Datatracker -and should contact the Secretariat to obtain their own user-id and -password for the Datatracker. -

-{% else %} -

-The delegate you are trying to designate does not have a personal user-id and password to log-on to the Datatracker. -

-

-An email will be sent to the following addresses to inform that -the person you have designated to be one of your delegates -currently does not have login credentials for the Datatracker -and should contact the Secretariat to obtain their own user-id and -password for the Datatracker. -

-{% endif %} -
    -{% for email in email_list %} -
  • {{ email }}
  • -{% endfor %} -
diff --git a/ietf/templates/wgchairs/notexistsdelegate_delegate_email.txt b/ietf/templates/wgchairs/notexistsdelegate_delegate_email.txt deleted file mode 100644 index de2318a93..000000000 --- a/ietf/templates/wgchairs/notexistsdelegate_delegate_email.txt +++ /dev/null @@ -1,10 +0,0 @@ -{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add you as a {{ wg }} {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}. - -You don't have an user/password to log into the datatracker so you must contact -the Secretariat at iesg-secretary@ietf.org in order to get your credentials. - -When you get your credentials, please inform {{ chair }} at -{{ chair.email.1 }} so he/she can finish the designate process. - -Thank you. -{% endautoescape %} diff --git a/ietf/templates/wgchairs/notexistsdelegate_secretariat_email.txt b/ietf/templates/wgchairs/notexistsdelegate_secretariat_email.txt deleted file mode 100644 index 27edacc11..000000000 --- a/ietf/templates/wgchairs/notexistsdelegate_secretariat_email.txt +++ /dev/null @@ -1,15 +0,0 @@ -{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email -{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}. - -This person don't have an user/password to log into the datatracker so -an email has been seent to {{ delegate_email }} in order to he/she contacs the -Secretariat to request his/her credentials. - -{% if delegate_persons %} -Please, note that the following persons with {{ delegate_email }} email address -already exists in the system but they can not log in. -{% for person in delegate_persons %} -{{ person.pk }} - {{ person }} -{% endfor %} -{% endif %} -{% endautoescape %} \ No newline at end of file diff --git a/ietf/templates/wgchairs/notexistsdelegate_wgchairs_email.txt b/ietf/templates/wgchairs/notexistsdelegate_wgchairs_email.txt deleted file mode 100644 index 477111dcf..000000000 --- a/ietf/templates/wgchairs/notexistsdelegate_wgchairs_email.txt +++ /dev/null @@ -1,12 +0,0 @@ -{% autoescape off %}{{ chair }} as a WG Chair of {{ wg }} wants to add a person with email -{{ delegate_email }} as a {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}. - -This person don't have an user/password to log into the datatracker so -an email has been seent to {{ delegate_email }} in order to he/she contacs the -Secretariat to request his/her credentials. - -When he/she gets her credentials then he/she will send an email to -{{ chair }} at {{ chair.email.1 }}. - -{{ chair }} could then assign this person as {% if shepherd %}shepherd of document {{ shepherd }}{% else %}WG Delegate{% endif %}. -{% endautoescape%} \ No newline at end of file diff --git a/ietf/templates/wgchairs/shepherd_document_row.html b/ietf/templates/wgchairs/shepherd_document_row.html deleted file mode 100644 index a58e1eac5..000000000 --- a/ietf/templates/wgchairs/shepherd_document_row.html +++ /dev/null @@ -1,17 +0,0 @@ -{% load wgchairs_tags %} - - - - {{ doc.title }} - - - Change shepherd - - - {% writeup doc %} - [Edit] - - - {% writeupdate doc %} - - diff --git a/ietf/templates/wgchairs/wg_shepherd_documents.html b/ietf/templates/wgchairs/wg_shepherd_documents.html deleted file mode 100644 index 2afcd9bac..000000000 --- a/ietf/templates/wgchairs/wg_shepherd_documents.html +++ /dev/null @@ -1,122 +0,0 @@ -{% extends "wginfo/wg_base.html" %} -{% comment %} -Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the Nokia Corporation and/or its - subsidiary(-ies) nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% endcomment %} -{% block wg_titledetail %}Documents{% endblock %} - -{% block pagehead %} -{{ block.super }} - - - -{% endblock pagehead %} - -{% block wg_content %} - -

Documents by its shepherd

-
- - -
-
- - - - - - - - - {% for doc in no_shepherd %} - {% include "wgchairs/shepherd_document_row.html" %} - {% endfor %} - -
DocumentChange shepherdShepherd write-upShepherd write-up last update
-
- -
- - - - - - - - - {% for doc in my_documents %} - {% include "wgchairs/shepherd_document_row.html" %} - {% endfor %} - -
DocumentStatusShepherd write-upShepherd write-up last update
-
- -
-{% regroup other_shepherds by shepherd as regrouped %} -{% for documents in regrouped %} -

{{ documents.grouper }}

- - - - - - - - {% for doc in documents.list %} - {% include "wgchairs/shepherd_document_row.html" %} - {% endfor %} -
DocumentStatusShepherd write-upShepherd write-up last update
-{% endfor %} -
- - -{% endblock wg_content %} - diff --git a/ietf/templates/wgchairs/wgchairs_admin_options.html b/ietf/templates/wgchairs/wgchairs_admin_options.html deleted file mode 100644 index b8c45a00f..000000000 --- a/ietf/templates/wgchairs/wgchairs_admin_options.html +++ /dev/null @@ -1,23 +0,0 @@ -{% if can_manage_workflow %} - {% ifequal selected "manage_workflow" %} - Manage workflow - {% else %} - Manage workflow - {% endifequal %} | -{% endif %} - -{% if can_manage_delegates %} - {% ifequal selected "manage_delegates" %} - Manage delegations - {% else %} - Manage delegations - {% endifequal %} | -{% endif %} - -{% if can_manage_shepherds %} - {% ifequal selected "manage_shepherds" %} - Manage shepherds - {% else %} - Manage shepherds - {% endifequal %} | -{% endif %} diff --git a/ietf/templates/wginfo/wg_base.html b/ietf/templates/wginfo/wg_base.html deleted file mode 100644 index 4f73e3fe4..000000000 --- a/ietf/templates/wginfo/wg_base.html +++ /dev/null @@ -1,83 +0,0 @@ -{% extends "base.html" %} -{% comment %} -Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -All rights reserved. Contact: Pasi Eronen - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * Neither the name of the Nokia Corporation and/or its - subsidiary(-ies) nor the names of its contributors may be used - to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -{% endcomment %} -{% load ietf_filters wgchairs_tags %} -{% block title %}{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}) - {% block wg_titledetail %}{% endblock %}{% endblock %} - -{% block morecss %} -.ietf-navset { - background:#214197 url(/images/yui/sprite.png) repeat-x left -1400px; - color:white; - border:1px solid black; - padding:4px; -} -.ietf-navset .selected { font-weight:bold; padding: 0 3px; } -.ietf-navset a, .ietf-navset a:visited { color: white; padding:0 3px; } - -.ietf-wg-details { float:right; padding: 4px;margin-top:16px; margin-left: 16px; } -.ietf-wg-details tr { vertical-align: top; } -.ietf-concluded-bg {background-color: #F8F8D0; } -.ietf-concluded-warning { background:red;color:white;padding:2px 2px;} -.ietf-proposed-bg { } -.ietf-proposed-warning { background:green;color:white;padding:2px 2px;} -.ietf-box th { - font-weight: bold; - padding-top: 1em; - text-align: left; -} -.ietf-box tr:first-child th { - padding-top: 0; -} -{% endblock morecss %} - -{% block content %} -
-

{{wg.group_acronym.name}} ({{wg.group_acronym.acronym}}){% if concluded %}
(concluded WG){% endif %}{% if proposed %}
(proposed WG){% endif %}

- -
-{% ifequal selected "documents" %}Documents{% else %}Documents{% endifequal %} | -{% ifequal selected "charter" %}Charter{% else %}Charter{% endifequal %} | -{% wgchairs_admin_options wg %} -History | -{% if wg.clean_email_archive|startswith:"http:" or wg.clean_email_archive|startswith:"https:" or wg.clean_email_archive|startswith:"ftp:" %} -List Archive » | -{% endif %} -Tools WG Page » -
- -{% block wg_content %} -{% endblock wg_content %} - -
-{% endblock content %} diff --git a/ietf/wgchairs/.gitignore b/ietf/wgchairs/.gitignore deleted file mode 100644 index a74b07aee..000000000 --- a/ietf/wgchairs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.pyc diff --git a/ietf/wgchairs/__init__.py b/ietf/wgchairs/__init__.py deleted file mode 100644 index e8d53c9a3..000000000 --- a/ietf/wgchairs/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# coding: latin-1 - -from types import ModuleType -import urls, models, views, forms, accounts - -# These people will be sent a stack trace if there's an uncaught exception in -# code any of the modules imported above: -DEBUG_EMAILS = [ - ('Emilio A. Sánchez', 'esanchez@yaco.es'), -] - -for k in locals().keys(): - m = locals()[k] - if isinstance(m, ModuleType): - if hasattr(m, "DEBUG_EMAILS"): - DEBUG_EMAILS += list(getattr(m, "DEBUG_EMAILS")) - setattr(m, "DEBUG_EMAILS", DEBUG_EMAILS) - diff --git a/ietf/wgchairs/accounts.py b/ietf/wgchairs/accounts.py deleted file mode 100644 index c6b5b7645..000000000 --- a/ietf/wgchairs/accounts.py +++ /dev/null @@ -1,108 +0,0 @@ -from django.conf import settings -from ietf.group.models import Role - -def is_secretariat(user): - if not user or not user.is_authenticated(): - return False - return bool(user.groups.filter(name='Secretariat')) - - -def is_area_director_for_group(person, group): - return bool(group.area.area.areadirector_set.filter(person=person).count()) - -def is_area_director_for_groupREDESIGN(person, group): - return bool(Role.objects.filter(group=group.parent, person=person, name__in=("ad", "pre-ad"))) - - -def is_group_chair(person, group): - if group.chairs().filter(person=person): - return True - return False - -def is_group_chairREDESIGN(person, group): - return bool(Role.objects.filter(group=group, person=person, name="chair")) - - -def is_group_delegate(person, group): - return bool(group.wgdelegate_set.filter(person=person).count()) - -def is_group_delegateREDESIGN(person, group): - return bool(Role.objects.filter(group=group, person=person, name="delegate")) - - -def get_person_for_user(user): - try: - return user.get_profile().person() - except: - return None - - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.liaisons.accounts import is_secretariat, get_person_for_user - is_area_director_for_group = is_area_director_for_groupREDESIGN - is_group_chair = is_group_chairREDESIGN - is_group_delegate = is_group_delegateREDESIGN - - -def can_do_wg_workflow_in_group(user, group): - person = get_person_for_user(user) - if not person: - return False - return (is_secretariat(user) or is_group_chair(person, group)) - - -def can_do_wg_workflow_in_document(user, document): - person = get_person_for_user(user) - if not person or not document.group: - return False - return (is_secretariat(user) or can_do_wg_workflow_in_group(document.group.ietfwg)) - - -def can_manage_workflow_in_group(user, group): - person = get_person_for_user(user) - if not person: - return False - return (is_secretariat(user) or is_group_chair(person, group)) - - -def can_manage_delegates_in_group(user, group): - person = get_person_for_user(user) - if not person: - return False - return (is_secretariat(user) or is_group_chair(person, group)) - - -def can_manage_shepherds_in_group(user, group): - person = get_person_for_user(user) - if not person: - return False - return (is_secretariat(user) or is_group_chair(person, group)) - - -def can_manage_shepherd_of_a_document(user, document): - person = get_person_for_user(user) - if not person or not document.group: - return False - return can_manage_shepherds_in_group(user, document.group.ietfwg) - - -def can_manage_writeup_of_a_document_no_state(user, document): - person = get_person_for_user(user) - if not person or not document.group: - return False - group = document.group.ietfwg - return (is_secretariat(user) or - is_group_chair(person, group) or - is_area_director_for_group(person, group) or - is_group_delegate(person, group)) - - -def can_manage_writeup_of_a_document(user, document): - person = get_person_for_user(user) - if not person or not document.group: - return False - return (can_manage_writeup_of_a_document_no_state(user, document) or - person == document.shepherd) - - - diff --git a/ietf/wgchairs/forms.py b/ietf/wgchairs/forms.py deleted file mode 100644 index 001acec7c..000000000 --- a/ietf/wgchairs/forms.py +++ /dev/null @@ -1,478 +0,0 @@ -import datetime - -from django import forms -from django.conf import settings -from django.db.models import Q -from django.forms.models import BaseModelFormSet -from django.template.loader import render_to_string -from django.utils.safestring import mark_safe - -from ietf.wgchairs.models import WGDelegate, ProtoWriteUp -from ietf.wgchairs.accounts import get_person_for_user -from ietf.ietfworkflows.constants import REQUIRED_STATES -from ietf.ietfworkflows.utils import (get_default_workflow_for_wg, get_workflow_for_wg, - update_tags, FOLLOWUP_TAG, get_state_by_name) -from ietf.ietfworkflows.models import AnnotationTag, State -from ietf.idtracker.models import PersonOrOrgInfo -from ietf.utils.mail import send_mail_text - -from workflows.models import Transition - -from ietf.doc.models import WriteupDocEvent -from ietf.person.models import Person, Email -from ietf.group.models import Group, Role, RoleName -from ietf.group.utils import save_group_in_history -from ietf.name.models import DocTagName - - -class RelatedWGForm(forms.Form): - - can_cancel = False - - def __init__(self, *args, **kwargs): - self.wg = kwargs.pop('wg', None) - self.user = kwargs.pop('user', None) - self.message = {} - super(RelatedWGForm, self).__init__(*args, **kwargs) - - def get_message(self): - return self.message - - def set_message(self, msg_type, msg_value): - self.message = {'type': msg_type, - 'value': msg_value, - } - - -class TagForm(RelatedWGForm): - - tags = forms.ModelMultipleChoiceField(AnnotationTag.objects.filter(workflow__name='Default WG Workflow'), - widget=forms.CheckboxSelectMultiple, required=False) - - def save(self): - workflow = get_workflow_for_wg(self.wg) - workflow.selected_tags.clear() - for tag in self.cleaned_data['tags']: - workflow.selected_tags.add(tag) - return workflow - - -class StateForm(RelatedWGForm): - - states = forms.ModelMultipleChoiceField(State.objects.filter(workflow__name='Default WG Workflow'), - widget=forms.CheckboxSelectMultiple, required=False) - - def update_transitions(self, workflow): - for transition in workflow.transitions.all(): - if not workflow.selected_states.filter(pk=transition.destination.pk).count(): - transition.delete() - continue - for state in transition.states.all(): - if not workflow.selected_states.filter(pk=state.pk).count(): - transition.states.remove(state) - if not transition.states.count(): - transition.delete() - continue - - def save(self): - workflow = get_workflow_for_wg(self.wg) - workflow.selected_states.clear() - for state in self.cleaned_data['states']: - workflow.selected_states.add(state) - for name in REQUIRED_STATES: - rstate = get_state_by_name(name) - if rstate: - workflow.selected_states.add(rstate) - self.update_transitions(workflow) - return workflow - - -class DeleteTransitionForm(RelatedWGForm): - - transitions = forms.ModelMultipleChoiceField(Transition.objects.all(), - widget=forms.CheckboxSelectMultiple) - - def __init__(self, *args, **kwargs): - super(DeleteTransitionForm, self).__init__(*args, **kwargs) - workflow = get_workflow_for_wg(self.wg) - self.fields['transitions'].queryset = self.fields['transitions'].queryset.filter(workflow=workflow) - - def save(self): - for transition in self.cleaned_data['transitions']: - transition.delete() - - -class TransitionForm(forms.ModelForm): - - states = forms.ModelMultipleChoiceField(State.objects.filter(workflow__name='Default WG Workflow')) - - class Meta: - model = Transition - fields = ('name', 'states', 'destination', ) - - def __init__(self, *args, **kwargs): - self.wg = kwargs.pop('wg', None) - self.user = kwargs.pop('user', None) - super(TransitionForm, self).__init__(*args, **kwargs) - workflow = get_workflow_for_wg(self.wg) - self.fields['states'].queryset = workflow.selected_states.all() - self.fields['destination'].queryset = workflow.selected_states.all() - self.fields['destination'].required = True - if self.instance.pk: - self.fields['states'].initial = [i.pk for i in self.instance.states.all()] - self.instance.workflow = workflow - - def as_row(self): - return self._html_output(u'%(errors)s%(field)s%(help_text)s', u'%s', '', u'
%s', False) - - def save(self, *args, **kwargs): - instance = super(TransitionForm, self).save(*args, **kwargs) - for state in self.cleaned_data['states']: - state.transitions.add(instance) - - -class TransitionFormSet(BaseModelFormSet): - - form = TransitionForm - can_delete = True - extra = 2 - max_num = 0 - can_order = False - model = Transition - - def __init__(self, *args, **kwargs): - self.wg = kwargs.pop('wg', None) - self.user = kwargs.pop('user', None) - super(TransitionFormSet, self).__init__(*args, **kwargs) - - def _construct_form(self, i, **kwargs): - kwargs = kwargs or {} - kwargs.update({'wg': self.wg, 'user': self.user}) - return super(TransitionFormSet, self)._construct_form(i, **kwargs) - - def as_table(self): - html = u'' - csscl = 'oddrow' - for form in self.forms: - html += u'' % csscl - html += form.as_row() - html += u'' - if csscl == 'oddrow': - csscl = 'evenrow' - else: - csscl = 'oddrow' - return mark_safe(u'\n'.join([unicode(self.management_form), html])) - - -def workflow_form_factory(request, wg, user): - - if request.POST.get('update_transitions', None): - return TransitionFormSet(wg=wg, user=user, data=request.POST) - elif request.POST.get('update_states', None): - return StateForm(wg=wg, user=user, data=request.POST) - return TagForm(wg=wg, user=user, data=request.POST) - - -class RemoveDelegateForm(RelatedWGForm): - - delete = forms.MultipleChoiceField() - - def __init__(self, *args, **kwargs): - super(RemoveDelegateForm, self).__init__(*args, **kwargs) - self.fields['delete'].choices = [(i.pk, i.pk) for i in self.wg.wgdelegate_set.all()] - - def save(self): - delegates = self.cleaned_data.get('delete') - save_group_in_history(Group.objects.get(pk=self.wg.pk)) - WGDelegate.objects.filter(pk__in=delegates).delete() - self.set_message('success', 'Delegates removed') - -def assign_shepherd(user, internetdraft, shepherd): - if internetdraft.shepherd == shepherd: - return - - from ietf.doc.models import save_document_in_history, DocEvent, Document - - # saving the proxy object is a bit of a mess, so convert it to a - # proper document - doc = Document.objects.get(name=internetdraft.name) - - save_document_in_history(doc) - - doc.time = datetime.datetime.now() - doc.shepherd = shepherd - doc.save() - - e = DocEvent(type="changed_document") - e.time = doc.time - e.doc = doc - e.by = user.get_profile() - if not shepherd: - e.desc = u"Unassigned shepherd" - else: - e.desc = u"Changed shepherd to %s" % shepherd.plain_name() - e.save() - - # update proxy too - internetdraft.shepherd = shepherd - -class AddDelegateForm(RelatedWGForm): - - email = forms.EmailField() - form_type = forms.CharField(widget=forms.HiddenInput, initial='single') - - def __init__(self, *args, **kwargs): - self.shepherd = kwargs.pop('shepherd', False) - super(AddDelegateForm, self).__init__(*args, **kwargs) - self.next_form = self - - def get_next_form(self): - return self.next_form - - def get_person(self, email): - persons = PersonOrOrgInfo.objects.filter(emailaddress__address=email).filter( - Q(iesglogin__isnull=False)| - Q(legacywgpassword__isnull=False)| - Q(legacyliaisonuser__isnull=False)).distinct() - if not persons: - raise PersonOrOrgInfo.DoesNotExist - if len(persons) > 1: - raise PersonOrOrgInfo.MultipleObjectsReturned - return persons[0] - - def save(self): - email = self.cleaned_data.get('email') - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - try: - person = Person.objects.filter(email__address=email).exclude(user=None).distinct().get() - except Person.DoesNotExist: - self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd) - self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system') - return - except Person.MultipleObjectsReturned: - self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd) - self.next_form.set_message('multiple', 'There are multiple users with this email in the system') - return - else: - try: - person = self.get_person(email) - except PersonOrOrgInfo.DoesNotExist: - self.next_form = NotExistDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd) - self.next_form.set_message('doesnotexist', 'There is no user with this email allowed to login to the system') - return - except PersonOrOrgInfo.MultipleObjectsReturned: - self.next_form = MultipleDelegateForm(wg=self.wg, user=self.user, email=email, shepherd=self.shepherd) - self.next_form.set_message('multiple', 'There are multiple users with this email in the system') - return - if self.shepherd: - self.assign_shepherd(person) - else: - self.create_delegate(person) - - def assign_shepherd(self, person): - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - assign_shepherd(self.user, self.shepherd, person) - else: - self.shepherd.shepherd = person - self.shepherd.save() - self.next_form = AddDelegateForm(wg=self.wg, user=self.user, shepherd=self.shepherd) - self.next_form.set_message('success', 'Shepherd assigned successfully') - - def create_delegate(self, person): - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - created = False - e = Email.objects.get(address=self.cleaned_data.get('email')) - if not Role.objects.filter(name="delegate", group=self.wg, person=person, email=e): - created = True - save_group_in_history(Group.objects.get(pk=self.wg.pk)) - delegate, _ = Role.objects.get_or_create( - name=RoleName.objects.get(slug="delegate"), group=self.wg, person=e.person, email=e) - else: - (delegate, created) = WGDelegate.objects.get_or_create(wg=self.wg, - person=person) - if not created: - self.set_message('error', 'The email belongs to a person who is already a delegate') - else: - self.next_form = AddDelegateForm(wg=self.wg, user=self.user) - self.next_form.set_message('success', 'A new delegate has been added') - - -class MultipleDelegateForm(AddDelegateForm): - - email = forms.EmailField(widget=forms.HiddenInput) - form_type = forms.CharField(widget=forms.HiddenInput, initial='multiple') - persons = forms.ChoiceField(widget=forms.RadioSelect, help_text='Please select one person from the list') - submit_msg = 'Designate as delegate' - - def __init__(self, *args, **kwargs): - self.email = kwargs.pop('email', None) - super(MultipleDelegateForm, self).__init__(*args, **kwargs) - if not self.email: - self.email = self.data.get('email', None) - self.fields['email'].initial = self.email - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - self.fields['persons'].choices = [(i.pk, unicode(i)) for i in Person.objects.filter(email__address=self.email).exclude(user=None).distinct().order_by('name')] - else: - self.fields['persons'].choices = [(i.pk, unicode(i)) for i in PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).filter( - Q(iesglogin__isnull=False)| - Q(legacywgpassword__isnull=False)| - Q(legacyliaisonuser__isnull=False)).distinct().order_by('first_name')] - - def save(self): - person_id = self.cleaned_data.get('persons') - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - person = Person.objects.get(pk=person_id) - else: - person = PersonOrOrgInfo.objects.get(pk=person_id) - if self.shepherd: - self.assign_shepherd(person) - else: - self.create_delegate(person) - - -class NotExistDelegateForm(MultipleDelegateForm): - - email = forms.EmailField(widget=forms.HiddenInput) - form_type = forms.CharField(widget=forms.HiddenInput, initial='notexist') - can_cancel = True - submit_msg = 'Send email to these addresses' - - def __init__(self, *args, **kwargs): - super(NotExistDelegateForm, self).__init__(*args, **kwargs) - self.email_list = [] - del(self.fields['persons']) - - def get_email_list(self): - if self.email_list: - return self.email_list - email_list = [self.email] - email_list.append('IETF Secretariat ') - email_list += ['%s <%s>' % i.person.email() for i in self.wg.wgchair_set.all() if i.person.email()] - self.email_list = email_list - return email_list - - def as_p(self): - email_list = self.get_email_list() - info = render_to_string('wgchairs/notexistdelegate.html', {'email_list': email_list, 'shepherd': self.shepherd}) - return info + super(NotExistDelegateForm, self).as_p() - - def send_email(self, to_email, template): - if self.shepherd: - subject = 'WG shepherd needs system credentials' - else: - subject = 'WG Delegate needs system credentials' - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - persons = Person.objects.filter(email__address=self.email).distinct() - else: - persons = PersonOrOrgInfo.objects.filter(emailaddress__address=self.email).distinct() - body = render_to_string(template, - {'chair': get_person_for_user(self.user), - 'delegate_email': self.email, - 'shepherd': self.shepherd, - 'delegate_persons': persons, - 'wg': self.wg, - }) - - send_mail_text(self.request, to_email, settings.DEFAULT_FROM_EMAIL, subject, body) - - def save(self): - self.next_form = AddDelegateForm(wg=self.wg, user=self.user) - if settings.DEBUG: - self.next_form.set_message('warning', 'Email was not sent cause tool is in DEBUG mode') - else: - # this is ugly... - email_list = self.get_email_list() - delegate = email_list[0] - secretariat = email_list[1] - wgchairs = email_list[2:] - self.send_email(delegate, 'wgchairs/notexistsdelegate_delegate_email.txt') - self.send_email(secretariat, 'wgchairs/notexistsdelegate_secretariat_email.txt') - self.send_email(wgchairs, 'wgchairs/notexistsdelegate_wgchairs_email.txt') - self.next_form.set_message('success', 'Email sent successfully') - - -def add_form_factory(request, wg, user, shepherd=False): - if request.method != 'POST' or request.POST.get('update_shepehrd'): - return AddDelegateForm(wg=wg, user=user, shepherd=shepherd) - - if request.POST.get('form_type', None) == 'multiple': - f = MultipleDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd) - elif request.POST.get('form_type', None) == 'notexist': - f = NotExistDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd) - elif request.POST.get('form_type', None) == 'single': - f = AddDelegateForm(wg=wg, user=user, data=request.POST.copy(), shepherd=shepherd) - else: - f = AddDelegateForm(wg=wg, user=user, shepherd=shepherd) - - f.request = request - return f - -class WriteUpEditForm(RelatedWGForm): - - writeup = forms.CharField(widget=forms.Textarea, required=False) - followup = forms.BooleanField(required=False) - comment = forms.CharField(widget=forms.Textarea, required=False) - - def __init__(self, *args, **kwargs): - self.doc = kwargs.pop('doc', None) - self.doc_writeup = self.doc.protowriteup_set.all() - if self.doc_writeup.count(): - self.doc_writeup = self.doc_writeup[0] - else: - self.doc_writeup = None - super(WriteUpEditForm, self).__init__(*args, **kwargs) - self.person = get_person_for_user(self.user) - - def get_writeup(self): - return self.data.get('writeup', self.doc_writeup and self.doc_writeup.writeup or '') - - def save(self): - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - e = WriteupDocEvent(type="changed_protocol_writeup") - e.doc = self.doc - e.by = self.person - e.desc = e.get_type_display() - e.text = self.cleaned_data['writeup'] - e.save() - from ietf.wgchairs.models import ProtoWriteUpProxy - self.doc_writeup = ProtoWriteUpProxy.objects.get(pk=e.pk) - else: - if not self.doc_writeup: - self.doc_writeup = ProtoWriteUp.objects.create( - person=self.person, - draft=self.doc, - writeup=self.cleaned_data['writeup']) - else: - self.doc_writeup.writeup = self.cleaned_data['writeup'] - self.doc_writeup.save() - - if self.data.get('modify_tag', False): - followup = self.cleaned_data.get('followup', False) - comment = self.cleaned_data.get('comment', False) - try: - shepherd = self.doc.shepherd - except PersonOrOrgInfo.DoesNotExist: - shepherd = None - if shepherd: - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - extra_notify = [shepherd.formatted_email()] - else: - extra_notify = ['%s <%s>' % shepherd.email()] - else: - extra_notify = [] - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - tags = DocTagName.objects.filter(slug="sheph-u") - else: - tags = [FOLLOWUP_TAG] - if followup: - update_tags(self.request, self.doc, comment, self.person, set_tags=tags, extra_notify=extra_notify) - else: - update_tags(self.request, self.doc, comment, self.person, reset_tags=tags, extra_notify=extra_notify) - return self.doc_writeup - - def is_valid(self): - if self.data.get('confirm', False) and self.data.get('modify_tag', False): - self.fields['comment'].required = True - else: - self.fields['comment'].required = False - return super(WriteUpEditForm, self).is_valid() diff --git a/ietf/wgchairs/migrations/.gitignore b/ietf/wgchairs/migrations/.gitignore deleted file mode 100644 index a74b07aee..000000000 --- a/ietf/wgchairs/migrations/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.pyc diff --git a/ietf/wgchairs/migrations/0001_initial.py b/ietf/wgchairs/migrations/0001_initial.py deleted file mode 100644 index 6aa9fb58f..000000000 --- a/ietf/wgchairs/migrations/0001_initial.py +++ /dev/null @@ -1,110 +0,0 @@ - -from south.db import db -from django.db import models -from ietf.wgchairs.models import * - -class Migration: - - def forwards(self, orm): - - # Adding model 'WGDelegate' - db.create_table('wgchairs_wgdelegate', ( - ('id', orm['wgchairs.WGDelegate:id']), - ('person', orm['wgchairs.WGDelegate:person']), - ('wg', orm['wgchairs.WGDelegate:wg']), - )) - db.send_create_signal('wgchairs', ['WGDelegate']) - - - - def backwards(self, orm): - - # Deleting model 'WGDelegate' - db.delete_table('wgchairs_wgdelegate') - - - - models = { - 'idtracker.acronym': { - 'Meta': {'db_table': "'acronym'"}, - 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}), - 'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'idtracker.area': { - 'Meta': {'db_table': "'areas'"}, - 'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}), - 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"}) - }, - 'idtracker.areadirector': { - 'Meta': {'db_table': "'area_directors'"}, - 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}) - }, - 'idtracker.areastatus': { - 'Meta': {'db_table': "'area_status'"}, - 'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.ietfwg': { - 'Meta': {'db_table': "'groups_ietf'"}, - 'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}), - 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}), - 'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}), - 'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}), - 'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}), - 'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}), - 'last_modified_date': ('django.db.models.fields.DateField', [], {}), - 'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}), - 'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}), - 'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"}) - }, - 'idtracker.personororginfo': { - 'Meta': {'db_table': "'person_or_org_info'"}, - 'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}), - 'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), - 'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}), - 'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), - 'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), - 'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}) - }, - 'idtracker.wgstatus': { - 'Meta': {'db_table': "'g_status'"}, - 'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.wgtype': { - 'Meta': {'db_table': "'g_type'"}, - 'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"}) - }, - 'wgchairs.wgdelegate': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}), - 'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}) - } - } - - complete_apps = ['wgchairs'] diff --git a/ietf/wgchairs/migrations/0002_add_writeup.py b/ietf/wgchairs/migrations/0002_add_writeup.py deleted file mode 100644 index e1754ed22..000000000 --- a/ietf/wgchairs/migrations/0002_add_writeup.py +++ /dev/null @@ -1,163 +0,0 @@ - -from south.db import db -from django.db import models -from ietf.wgchairs.models import * - -class Migration: - - def forwards(self, orm): - - # Adding model 'ProtoWriteUp' - db.create_table('wgchairs_protowriteup', ( - ('id', orm['wgchairs.protowriteup:id']), - ('person', orm['wgchairs.protowriteup:person']), - ('draft', orm['wgchairs.protowriteup:draft']), - ('date', orm['wgchairs.protowriteup:date']), - ('writeup', orm['wgchairs.protowriteup:writeup']), - )) - db.send_create_signal('wgchairs', ['ProtoWriteUp']) - - - - def backwards(self, orm): - - # Deleting model 'ProtoWriteUp' - db.delete_table('wgchairs_protowriteup') - - - - models = { - 'idtracker.acronym': { - 'Meta': {'db_table': "'acronym'"}, - 'acronym': ('django.db.models.fields.CharField', [], {'max_length': '12'}), - 'acronym_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name_key': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'idtracker.area': { - 'Meta': {'db_table': "'areas'"}, - 'area_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}), - 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'extra_email_addresses': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'last_modified_date': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'blank': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaStatus']"}) - }, - 'idtracker.areadirector': { - 'Meta': {'db_table': "'area_directors'"}, - 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Area']", 'null': 'True', 'db_column': "'area_acronym_id'"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'db_column': "'person_or_org_tag'"}) - }, - 'idtracker.areastatus': { - 'Meta': {'db_table': "'area_status'"}, - 'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.idintendedstatus': { - 'Meta': {'db_table': "'id_intended_status'"}, - 'intended_status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'intended_status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.idstatus': { - 'Meta': {'db_table': "'id_status'"}, - 'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.ietfwg': { - 'Meta': {'db_table': "'groups_ietf'"}, - 'area_director': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.AreaDirector']", 'null': 'True'}), - 'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'concluded_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'dormant_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'email_address': ('django.db.models.fields.CharField', [], {'max_length': '60', 'blank': 'True'}), - 'email_archive': ('django.db.models.fields.CharField', [], {'max_length': '95', 'blank': 'True'}), - 'email_keyword': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'email_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '120', 'blank': 'True'}), - 'group_acronym': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['idtracker.Acronym']", 'unique': 'True', 'primary_key': 'True'}), - 'group_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGType']"}), - 'last_modified_date': ('django.db.models.fields.DateField', [], {}), - 'meeting_scheduled': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}), - 'meeting_scheduled_old': ('django.db.models.fields.CharField', [], {'max_length': '3', 'blank': 'True'}), - 'proposed_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.WGStatus']"}) - }, - 'idtracker.internetdraft': { - 'Meta': {'db_table': "'internet_drafts'"}, - 'abstract': ('django.db.models.fields.TextField', [], {}), - 'b_approve_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'b_discussion_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'b_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'comments': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}), - 'dunn_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True'}), - 'expired_tombstone': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'extension_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '20'}), - 'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}), - 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.Acronym']", 'db_column': "'group_acronym_id'"}), - 'id_document_key': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'id_document_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'intended_status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDIntendedStatus']"}), - 'last_modified_date': ('django.db.models.fields.DateField', [], {}), - 'lc_changes': ('django.db.models.fields.CharField', [], {'max_length': '3', 'null': 'True'}), - 'lc_expiration_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'lc_sent_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}), - 'local_path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'replaced_by': ('django.db.models.fields.related.ForeignKey', ["orm['idtracker.InternetDraft']"], {'related_name': "'replaces_set'", 'null': 'True', 'db_column': "'replaced_by'", 'blank': 'True'}), - 'review_by_rfc_editor': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'revision': ('django.db.models.fields.CharField', [], {'max_length': '2'}), - 'revision_date': ('django.db.models.fields.DateField', [], {}), - 'rfc_number': ('django.db.models.fields.IntegerField', [], {'db_index': 'True', 'null': 'True', 'blank': 'True'}), - 'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']", 'null': 'True', 'blank': 'True'}), - 'start_date': ('django.db.models.fields.DateField', [], {}), - 'status': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IDStatus']"}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_column': "'id_document_name'"}), - 'txt_page_count': ('django.db.models.fields.IntegerField', [], {}), - 'wgreturn_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}) - }, - 'idtracker.personororginfo': { - 'Meta': {'db_table': "'person_or_org_info'"}, - 'address_type': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'created_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}), - 'date_created': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), - 'date_modified': ('django.db.models.fields.DateField', [], {'auto_now': 'True', 'null': 'True', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'first_name_key': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'last_name_key': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'middle_initial': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'middle_initial_key': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}), - 'modified_by': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}), - 'name_prefix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), - 'name_suffix': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}), - 'person_or_org_tag': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'record_type': ('django.db.models.fields.CharField', [], {'max_length': '8', 'null': 'True', 'blank': 'True'}) - }, - 'idtracker.wgstatus': { - 'Meta': {'db_table': "'g_status'"}, - 'status': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'status_value'"}), - 'status_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) - }, - 'idtracker.wgtype': { - 'Meta': {'db_table': "'g_type'"}, - 'group_type_id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'type': ('django.db.models.fields.CharField', [], {'max_length': '25', 'db_column': "'group_type'"}) - }, - 'wgchairs.protowriteup': { - 'date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now()'}), - 'draft': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.InternetDraft']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}), - 'writeup': ('django.db.models.fields.TextField', [], {}) - }, - 'wgchairs.wgdelegate': { - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.PersonOrOrgInfo']"}), - 'wg': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['idtracker.IETFWG']"}) - } - } - - complete_apps = ['wgchairs'] diff --git a/ietf/wgchairs/migrations/__init__.py b/ietf/wgchairs/migrations/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/ietf/wgchairs/models.py b/ietf/wgchairs/models.py deleted file mode 100644 index ea0a74c97..000000000 --- a/ietf/wgchairs/models.py +++ /dev/null @@ -1,87 +0,0 @@ -import datetime - -from django.db import models -from django.conf import settings - -from ietf.idtracker.models import (IETFWG, PersonOrOrgInfo, - InternetDraft) - - -class WGDelegate(models.Model): - person = models.ForeignKey( - PersonOrOrgInfo, - ) - - wg = models.ForeignKey(IETFWG, related_name="old_wgdelegate_set" if settings.USE_DB_REDESIGN_PROXY_CLASSES else None) - - def __unicode__(self): - return "%s" % self.person - - class Meta: - verbose_name = "WG Delegate" - -class ProtoWriteUp(models.Model): - person = models.ForeignKey( - PersonOrOrgInfo, - blank=False, - null=False, - ) - - if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.idtracker.models import InternetDraftOld as InternetDraft - - draft = models.ForeignKey( - InternetDraft, - blank=False, - null=False, - ) - - date = models.DateTimeField( - default=datetime.datetime.now(), - blank=False, - null=False, - ) - - writeup = models.TextField( - blank=False, - null=False, - ) - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.group.models import Role - class WGDelegateProxy(Role): - #person = models.ForeignKey(PersonOrOrgInfo) # same name - #wg = models.ForeignKey(IETFWG) - @property - def wg(self): - return self.group - - def __unicode__(self): - return u"%s" % self.person - - class Meta: - proxy = True - - from ietf.doc.models import WriteupDocEvent - class ProtoWriteUpProxy(WriteupDocEvent): - #person = models.ForeignKey(PersonOrOrgInfo, blank=False, null=False) - @property - def person(self): - return self.by - #draft = models.ForeignKey(InternetDraft, blank=False, null=False) - @property - def draft(self): - return self.doc - #date = models.DateTimeField(default=datetime.datetime.now(), blank=False, null=False) - @property - def date(self): - return self.time - #writeup = models.TextField(blank=False, null=False) - @property - def writeup(self): - return self.text - class Meta: - proxy = True - - #WGDelegateOld = WGDelegate - WGDelegate = WGDelegateProxy diff --git a/ietf/wgchairs/templatetags/.gitignore b/ietf/wgchairs/templatetags/.gitignore deleted file mode 100644 index a74b07aee..000000000 --- a/ietf/wgchairs/templatetags/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/*.pyc diff --git a/ietf/wgchairs/templatetags/__init__.py b/ietf/wgchairs/templatetags/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/ietf/wgchairs/templatetags/wgchairs_tags.py b/ietf/wgchairs/templatetags/wgchairs_tags.py deleted file mode 100644 index df51dafae..000000000 --- a/ietf/wgchairs/templatetags/wgchairs_tags.py +++ /dev/null @@ -1,47 +0,0 @@ -from django.conf import settings -from django import template - -from ietf.ietfworkflows.utils import get_state_for_draft -from ietf.wgchairs.accounts import (can_manage_workflow_in_group, - can_manage_delegates_in_group, - can_manage_shepherds_in_group) - - -register = template.Library() - - -@register.inclusion_tag('wgchairs/wgchairs_admin_options.html', takes_context=True) -def wgchairs_admin_options(context, wg): - request = context.get('request', None) - user = request and request.user - return {'user': user, - 'can_manage_delegates': can_manage_delegates_in_group(user, wg), - 'can_manage_workflow': can_manage_workflow_in_group(user, wg), - 'can_manage_shepherds': can_manage_shepherds_in_group(user, wg), - 'wg': wg, - 'selected': context.get('selected', None), - } - -@register.simple_tag -def writeup(doc): - writeup = doc.protowriteup_set.all() - if not writeup: - return '' - else: - return writeup[0].writeup - - -@register.simple_tag -def writeupdate(doc): - writeup = doc.protowriteup_set.all() - if not writeup: - return '' - else: - return writeup[0].date - - -@register.inclusion_tag('wgchairs/draft_state.html', takes_context=True) -def show_state(context, doc): - return {'doc': doc, - 'state': get_state_for_draft(doc), - } diff --git a/ietf/wgchairs/tests.py b/ietf/wgchairs/tests.py deleted file mode 100644 index 8433e9399..000000000 --- a/ietf/wgchairs/tests.py +++ /dev/null @@ -1,214 +0,0 @@ -import datetime, os, shutil - -from django.conf import settings -from django.contrib.auth.models import User -from django.core.urlresolvers import reverse as urlreverse -import django.test -from StringIO import StringIO -from pyquery import PyQuery - -from ietf.utils.test_utils import login_testing_unauthorized -from ietf.utils.test_data import make_test_data -from ietf.utils.mail import outbox - -if settings.USE_DB_REDESIGN_PROXY_CLASSES: - from ietf.person.models import Person, Email - from ietf.group.models import Group, GroupHistory, Role, GroupStateTransitions - from ietf.doc.models import Document, State, WriteupDocEvent - from ietf.name.models import DocTagName - -class ManageDelegatesTestCase(django.test.TestCase): - fixtures = ['names'] - - def test_delete_delegate(self): - make_test_data() - - url = urlreverse('manage_delegates', kwargs=dict(acronym="mars")) - login_testing_unauthorized(self, "secretary", url) - - delegates = Role.objects.filter(name="delegate", group__acronym="mars") - self.assertTrue(len(delegates) > 0) - - # get - r = self.client.get(url) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('form input[name=delete]')), len(delegates)) - - # delete - r = self.client.post(url, - dict(remove="1", - delete=[d.pk for d in delegates])) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('form input[name=delete]')), 0) - self.assertEquals(Role.objects.filter(name="delegate", group__acronym="mars").count(), 0) - - def test_add_not_existing_delegate(self): - make_test_data() - - url = urlreverse('manage_delegates', kwargs=dict(acronym="mars")) - login_testing_unauthorized(self, "secretary", url) - - # get - r = self.client.get(url) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('form input[name=email]')), 1) - - # add non-existing - r = self.client.post(url, - dict(email="unknown@example.com", - form_type="single")) - self.assertEquals(r.status_code, 200) - self.assertTrue("unknown@example.com" in r.content) - q = PyQuery(r.content) - self.assertEquals(len(q('form input[type=submit][value*="Send email"]')), 1) - - # we get back a warning and offer to send email, do that - mailbox_before = len(outbox) - r = self.client.post(url, - dict(email="unknown@example.com", - form_type="notexist")) - self.assertEquals(r.status_code, 200) - self.assertTrue("Email sent" in r.content) - self.assertEquals(len(outbox), mailbox_before + 3) - - def test_add_delegate(self): - make_test_data() - - url = urlreverse('manage_delegates', kwargs=dict(acronym="mars")) - login_testing_unauthorized(self, "secretary", url) - - # get - r = self.client.get(url) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('form input[name=email]')), 1) - - # add existing person - history_before = GroupHistory.objects.filter(acronym="mars").count() - r = self.client.post(url, - dict(email="plain@example.com", - form_type="single")) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertTrue("new delegate" in r.content) - self.assertTrue(Email.objects.get(address="plain@example.com").person.plain_name() in r.content) - self.assertEquals(Role.objects.filter(name="delegate", group__acronym="mars", email__address="plain@example.com").count(), 1) - self.assertEquals(history_before + 1, GroupHistory.objects.filter(acronym="mars").count()) - - -class ManageShepherdsTestCase(django.test.TestCase): - fixtures = ['names'] - - def test_manage_shepherds(self): - make_test_data() - - url = urlreverse('manage_shepherds', kwargs=dict(acronym="mars")) - login_testing_unauthorized(self, "secretary", url) - - # setup test documents - group = Group.objects.get(acronym="mars") - - from ietf.doc.models import Document - common = dict(group=group, - ad=Person.objects.get(user__username="ad"), - type_id="draft") - Document.objects.create(name="test-shepherd-no", - title="No shepherd", - shepherd=None, - **common) - Document.objects.create(name="test-shepherd-me", - title="Shepherd me", - shepherd=Person.objects.get(user__username="secretary"), - **common) - Document.objects.create(name="test-shepherd-other", title="Shepherd other", - shepherd=Person.objects.get(user__username="plain"), - **common) - for d in Document.objects.filter(name__startswith="test-shepherd"): - d.set_state(State.objects.get(used=True, type="draft", slug="active")) - - # get and make sure they are divided correctly - r = self.client.get(url) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('div#noshepherd a:contains("No shepherd")')), 1) - self.assertEquals(len(q('div#mydocs a:contains("Shepherd me")')), 1) - self.assertEquals(len(q('div#othershepherds a:contains("Shepherd other")')), 1) - - -class ManageWorkflowTestCase(django.test.TestCase): - fixtures = ['names'] - - def test_manage_workflows(self): - make_test_data() - - group = Group.objects.get(acronym="mars") - - url = urlreverse('manage_workflow', kwargs=dict(acronym=group.acronym)) - login_testing_unauthorized(self, "secretary", url) - - state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-lc") - self.assertTrue(state not in group.unused_states.all()) - - # get - r = self.client.get(url) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='0']")), 1) - - # deactivate state - r = self.client.post(url, - dict(action="setstateactive", - state=state.pk, - active="0")) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q("form.set-state").find("input[name=state][value='%s']" % state.pk).parents("form").find("input[name=active][value='1']")), 1) - group = Group.objects.get(acronym=group.acronym) - self.assertTrue(state in group.unused_states.all()) - - # change next states - state = State.objects.get(used=True, type="draft-stream-ietf", slug="wg-doc") - next_states = State.objects.filter(used=True, type=b"draft-stream-ietf", slug__in=["parked", "dead", "wait-wgw", 'sub-pub']).values_list('pk', flat=True) - r = self.client.post(url, - dict(action="setnextstates", - state=state.pk, - next_states=next_states)) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q("form.set-next-states").find("input[name=state][value='%s']" % state.pk).parents('form').find("input[name=next_states][checked=checked]")), len(next_states)) - transitions = GroupStateTransitions.objects.filter(group=group, state=state) - self.assertEquals(len(transitions), 1) - self.assertEquals(set(transitions[0].next_states.values_list("pk", flat=True)), set(next_states)) - - # change them back to default - next_states = state.next_states.values_list("pk", flat=True) - r = self.client.post(url, - dict(action="setnextstates", - state=state.pk, - next_states=next_states)) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - transitions = GroupStateTransitions.objects.filter(group=group, state=state) - self.assertEquals(len(transitions), 0) - - # deactivate tag - tag = DocTagName.objects.get(slug="w-expert") - r = self.client.post(url, - dict(action="settagactive", - tag=tag.pk, - active="0")) - self.assertEquals(r.status_code, 200) - q = PyQuery(r.content) - self.assertEquals(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1) - group = Group.objects.get(acronym=group.acronym) - self.assertTrue(tag in group.unused_tags.all()) - -if not settings.USE_DB_REDESIGN_PROXY_CLASSES: - # the above tests only work with the new schema - del ManageDelegatesTestCase - del ManageShepherdsTestCase - del ManageWorkflowTestCase - del ManageWriteupCase diff --git a/ietf/wgchairs/urls.py b/ietf/wgchairs/urls.py deleted file mode 100644 index b9b32c240..000000000 --- a/ietf/wgchairs/urls.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright The IETF Trust 2008, All Rights Reserved - -from django.conf.urls.defaults import patterns, url - -urlpatterns = patterns('ietf.wgchairs.views', - url(r'^delegates/$', 'manage_delegates', name='manage_delegates'), -) diff --git a/ietf/wgchairs/views.py b/ietf/wgchairs/views.py deleted file mode 100644 index 1f9552e3d..000000000 --- a/ietf/wgchairs/views.py +++ /dev/null @@ -1,73 +0,0 @@ -from django.conf import settings -from ietf.idtracker.models import IETFWG, InternetDraft -from django.shortcuts import get_object_or_404, render_to_response -from django.template import RequestContext -from django.http import HttpResponseForbidden, Http404 - -from ietf.wgchairs.forms import (RemoveDelegateForm, add_form_factory, - workflow_form_factory, TransitionFormSet, - WriteUpEditForm, assign_shepherd) -from ietf.wgchairs.accounts import (can_manage_delegates_in_group, get_person_for_user, - can_manage_shepherds_in_group, - can_manage_workflow_in_group, - can_manage_shepherd_of_a_document, - can_manage_writeup_of_a_document, - can_manage_writeup_of_a_document_no_state, - ) -from ietf.ietfworkflows.constants import REQUIRED_STATES -from ietf.ietfworkflows.utils import (get_workflow_for_wg, - get_default_workflow_for_wg, - get_state_by_name, - get_annotation_tags_for_draft, - get_state_for_draft, WAITING_WRITEUP, - FOLLOWUP_TAG) -from ietf.name.models import DocTagName -from ietf.doc.models import State -from ietf.doc.utils import get_tags_for_stream_id - -def manage_delegates(request, acronym): - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - user = request.user - if not can_manage_delegates_in_group(user, wg): - return HttpResponseForbidden('You have no permission to access this view') - delegates = wg.wgdelegate_set.all() - add_form = add_form_factory(request, wg, user) - if request.method == 'POST': - if request.POST.get('remove', None): - form = RemoveDelegateForm(wg=wg, data=request.POST.copy()) - if form.is_valid(): - form.save() - elif add_form.is_valid(): - add_form.save() - add_form = add_form.get_next_form() - max_delegates = getattr(settings, 'MAX_WG_DELEGATES', 3) - return render_to_response('wgchairs/manage_delegates.html', - {'wg': wg, - 'delegates': delegates, - 'selected': 'manage_delegates', - 'can_add': delegates.count() < max_delegates, - 'max_delegates': max_delegates, - 'add_form': add_form, - }, RequestContext(request)) - - -def wg_shepherd_documents(request, acronym): - wg = get_object_or_404(IETFWG, group_acronym__acronym=acronym, group_type=1) - user = request.user - if not can_manage_shepherds_in_group(user, wg): - return HttpResponseForbidden('You have no permission to access this view') - current_person = get_person_for_user(user) - - base_qs = InternetDraft.objects.filter(group=wg, states__type="draft", states__slug="active").select_related("status").order_by('title') - documents_no_shepherd = base_qs.filter(shepherd=None) - documents_my = base_qs.filter(shepherd=current_person) - documents_other = base_qs.exclude(shepherd=None).exclude(shepherd__pk__in=[current_person.pk, 0]) - context = { - 'no_shepherd': documents_no_shepherd, - 'my_documents': documents_my, - 'other_shepherds': documents_other, - 'selected': 'manage_shepherds', - 'wg': wg, - } - return render_to_response('wgchairs/wg_shepherd_documents.html', context, RequestContext(request)) -