Add charter documents to iesg/agenda and iesg/agenda/documents

Keep the ordering for drafts the same on iesg/agenda and iesg/agenda/documents
Allow setting the responsible AD for a charter document
Change the UI of the charter page to use editlink for changing attributes and buttons for actions (to align with drafts and conflict-reviews)
 - Legacy-Id: 4769
This commit is contained in:
Robert Sparks 2012-08-21 03:57:17 +00:00
parent 7a1a67fca4
commit 735efac3b0
9 changed files with 153 additions and 49 deletions

View file

@ -207,6 +207,9 @@ def agenda_docs(date, next_agenda):
m.balloting_started = e.time if e else datetime.datetime.min
docmatches.append(m)
# Be careful to keep this the same as what's used in agenda_documents
docmatches.sort(key=lambda d: d.balloting_started)
res = dict(("s%s%s%s" % (i, j, k), []) for i in range(2, 5) for j in range (1, 4) for k in range(1, 4))
for id in docmatches:
@ -232,7 +235,8 @@ def agenda_wg_actions(date):
section_key = "s" + get_wg_section(c.group)
if section_key not in res:
res[section_key] = []
res[section_key].append({'obj': c.group})
# Cleanup - Older view code wants obj, newer wants doc. Older code should be moved forward
res[section_key].append({'obj': c.group, 'doc': c})
return res
def agenda_management_issues(date):
@ -370,6 +374,7 @@ def _agenda_data(request, date=None):
def agenda(request, date=None):
data = _agenda_data(request, date)
data['private'] = 'private' in request.REQUEST
data['settings'] = settings
return render_to_response("iesg/agenda.html", data, context_instance=RequestContext(request))
def agenda_txt(request):

View file

@ -1,4 +1,6 @@
{% extends "base.html" %}
{% extends "idrfc/doc_main.html" %}
{% comment extends "base.html" %}
{% endcomment %}
{% load ietf_filters %}
@ -37,37 +39,25 @@
<td><a href="/doc/help/state/charter/">Charter State</a>:</td>
<td>
<div>
<a title="{{ doc.get_state.desc }}"{% if not snapshot and user|has_role:"Area Director,Secretariat" %} href="{% url charter_change_state name=doc.name %}"{% endif %}>{{ doc.get_state.name }}</a>
{% if chartering == "initial" %}(Initial Chartering){% endif %}
{% if chartering == "rechartering" %}(Rechartering){% endif %}
<a title="{{ doc.get_state.desc }}"
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
class="editlink" href="{% url charter_change_state name=doc.name %}"
{% endif %}>
{{ doc.get_state.name }}
</a>
{% if chartering == "initial" %} - (Initial Chartering){% endif %}
{% if chartering == "rechartering" %} - (Rechartering){% endif %}
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
{% if chartering %}
- <a href="{% url charter_startstop_process name=doc.name option='abandon' %}">Abandon effort</a>
{% if request.user|has_role:"Secretariat" %}
- <a href="{% url charter_approve name=doc.name %}">Approve charter</a>
{% endif %}
{% else %}
{% if group.state_id == "proposed" or group.state_id == "bof" %}
- <a href="{% url charter_submit name=doc.name option='initcharter' %}">Start chartering</a>
{% else %}
- <a href="{% url charter_submit name=doc.name option='recharter' %}">Recharter</a>
{% endif %}
{% endif %}
{% endif %}
</div>
{% if not snapshot and chartering %}
<div class="telechat">
{% if not telechat %}Not on agenda of IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% endif %}
{% if user|has_role:"Area Director,Secretariat" %}
- <a href="{% url charter_telechat_date name=doc.name %}">Change</a>
{% endif %}
<a
{% if user|has_role:"Area Director,Secretariat" %}
class="editlink" href="{% url charter_telechat_date name=doc.name %}"
{% endif %}>
{% if not telechat %}Not on agenda of IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% endif %}
</a>
</div>
{% if ballot_summary %}
@ -88,14 +78,20 @@
</tr>
{% endif %}
<tr>
<td>Responsible AD:</td>
<td><a {% if request.user|has_role:"Area Director,Secretariat" %}class="editlink" href="{% url charter_edit_ad name=doc.name %}"{% endif %}>{{ doc.ad|default:"none" }}</a> </td>
</tr>
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
<tr>
<td>Send notices to:</td>
<td>{{ doc.notify|default:"none" }}
{% if user|has_role:"Area Director,Secretariat" %}
- <a href="{% url charter_edit_notify name=doc.name %}">Change</a>
{% endif %}
<td><a {% if user|has_role:"Area Director,Secretariat" %}
class="editlink" href="{% url charter_edit_notify name=doc.name %}"
{% endif %}>
{{ doc.notify|default:"none" }}
</a>
</td>
</tr>
@ -107,6 +103,26 @@
<div class="actions">
<a href="/feed/group-changes/{{ group.acronym }}/">Atom feed</a>
</div>
<div>
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
{% if chartering %}
<span id="charter_abandon_effort_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_startstop_process name=doc.name option='abandon' as abandon_url %}{% if abandon_url %}<span class="first-child"><a href="{{abandon_url}}">Abandon Effort</a></span>{% endif %}</span>
{% if request.user|has_role:"Secretariat" %}
<span id="charter_approve_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_approve name=doc.name as approve_url %}{% if approve_url %}<span class="first-child"><a href="{{approve_url}}">Approve Charter</a></span>{% endif %}</span>
{% endif %}
{% else %}
{% if group.state_id == "proposed" or group.state_id == "bof" %}
<span id="charter_start_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_submit name=doc.name option='initcharter' as start_url %}{% if start_url %}<span class="first-child"><a href="{{start_url}}">Start Chartering</a></span>{% endif %}</span>
{% else %}
<span id="charter_recharter_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_submit name=doc.name option='recharter' as recharter_url %}{% if recharter_url %}<span class="first-child"><a href="{{recharter_url}}">Recharter</a></span>{% endif %}</span>
{% endif %}
{% endif %}
{% endif %}
</div>
</div>
<p>Other versions: <a href="{{ txt_url }}">plain text</a></p>

View file

@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #}
.agenda blockquote { margin-left: 30px; width: 70ex; font-style:italic;}
table.agenda-doc { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
table.agenda-doc > tbody > tr { vertical-align:top; }
div.agenda-wg { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
{% endblock morecss %}
{% block pagehead %}

View file

@ -131,6 +131,22 @@ font-size:80%; font-style:italic;
{% if t.docs.s333 %}<tr class="header"><td colspan="6">3.3.3 For Action</td></tr>{% endif %}
{% for doc in t.docs.s333 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
<tr class="header"><td colspan="6">4. Working Group Actions</td></tr>
{% if t.docs.s411 or t.docs.s412%}<tr class="header"><td colspan="6">4.1 WG Creation</td></tr>{% endif %}
{% if t.docs.s411 %}<tr class="header"><td colspan="6">4.1.1 Proposed for IETF Review</td></tr>{% endif %}
{% for doc in t.docs.s411 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
{% if t.docs.s412 %}<tr class="header"><td colspan="6">4.1.2 Proposed for Approval</td></tr>{% endif %}
{% for doc in t.docs.s412 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
{% if t.docs.s421 or t.docs.s422 %}<tr class="header"><td colspan="6">4.2 WG Rechartering</td></tr>{% endif %}
{% if t.docs.s421 %}<tr class="header"><td colspan="6">4.2.1 Under Evaluation for IETF Review</td></tr>{% endif %}
{% for doc in t.docs.s421 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
{% if t.docs.s422 %}<tr class="header"><td colspan="6">4.2.2 Proposed for Approval</td></tr>{% endif %}
{% for doc in t.docs.s422 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
{% endfor %}
</table>

View file

@ -39,6 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<tr
{% if user|in_group:"Area_Director" %}
{% if doc|my_position:user|equal:"Discuss" %}style="background:#ffa0a0;"{% endif %}
{% if doc|my_position:user|equal:"Block" %}style="background:#ffa0a0;"{% endif %}
{% if doc|my_position:user|equal:"Abstain" %}style="background:#ffff00;"{% endif %}
{% if doc|my_position:user|equal:"Yes" or doc|my_position:user|slugify|equal:"no-objection" %}style="background:#a0ffa0;"{% endif %}
{% if doc|my_position:user|equal:"Recuse" %}style="background:#c0c0c0;"{% endif %}

View file

@ -31,30 +31,24 @@ 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 ballot_icon_redesign %}
{% if title2_first %}{% if title1_first %}<h2>{{ title1 }}</h2>
{% endif %}
<h3>{{ title2 }}</h3>
{% endif %}<h4>{{ title3 }}</h4>
{% for wg in section_wgs %}
{% if forloop.first %}
<table>
<tr><th>Area</th><th>Date</th><th></th></tr>
{% endif %}
<tr>
<td>{{ wg.obj.parent.acronym|upper }}</td>
<td>{{ wg.obj.time|date:"M d"}}</td>
<td>
<a href="{{ wg.obj.txt_link }}">
{{ wg.obj.name|escape }} ({{wg.obj.acronym}})
</a>
</td>
</tr>
{% if forloop.last %}
</table>
{% endif %}
<div class="agenda-wg">
<span width="30%" style="float:right;">
{% ballot_icon wg.doc %}
</span>
<span width="30%">
<div> <a href="{{ wg.doc.get_absolute_url }}">{{ wg.doc.name}}-({{wg.doc.rev}})</a> <a href="{{ settings.CHARTER_TXT_URL }}{{ wg.doc.filename_with_rev }}">[txt]</a> </div>
<div>{{ wg.doc.group.name|escape }} ({{wg.doc.group.acronym}})</div>
<div>Area: {{ wg.doc.group.parent.acronym|upper }} ({{ wg.doc.ad|default:"Sponsoring AD not assigned" }})</div>
</span>
</div>
{% empty %}
<p>NONE</p>

View file

@ -132,6 +132,29 @@ class EditCharterTestCase(django.test.TestCase):
charter = Document.objects.get(name=charter.name)
self.assertEquals(charter.notify, "someone@example.com, someoneelse@example.com")
def test_edit_ad(self):
make_test_data()
charter = Group.objects.get(acronym="mars").charter
url = urlreverse('charter_edit_ad', kwargs=dict(name=charter.name))
login_testing_unauthorized(self, "secretary", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('select[name=ad]')),1)
# post
self.assertTrue(not charter.ad)
ad2 = Person.objects.get(name='Ad No2')
r = self.client.post(url,dict(ad=str(ad2.pk)))
self.assertEquals(r.status_code, 302)
charter = Document.objects.get(name=charter.name)
self.assertEquals(charter.ad, ad2)
def test_submit_charter(self):
make_test_data()

View file

@ -7,6 +7,7 @@ urlpatterns = patterns('',
url(r'^(?P<option>initcharter|recharter|abandon)/$', "ietf.wgcharter.views.change_state", name='charter_startstop_process'),
url(r'^telechat/$', "ietf.wgcharter.views.telechat_date", name='charter_telechat_date'),
url(r'^notify/$', "ietf.wgcharter.views.edit_notify", name='charter_edit_notify'),
url(r'^ad/$', "ietf.wgcharter.views.edit_ad", name='charter_edit_ad'),
url(r'^(?P<ann>action|review)/$', "ietf.wgcharter.views.announcement_text", name="charter_edit_announcement"),
url(r'^ballotwriteupnotes/$', "ietf.wgcharter.views.ballot_writeupnotes"),
url(r'^approve/$', "ietf.wgcharter.views.approve", name='charter_approve'),

View file

@ -267,6 +267,53 @@ def edit_notify(request, name):
login=login),
context_instance=RequestContext(request))
class AdForm(forms.Form):
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
label="Responsible AD", empty_label="(None)", required=True)
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
# if previous AD is now ex-AD, append that person to the list
ad_pk = self.initial.get('ad')
choices = self.fields['ad'].choices
if ad_pk and ad_pk not in [pk for pk, name in choices]:
self.fields['ad'].choices = list(choices) + [("", "-------"), (ad_pk, Person.objects.get(pk=ad_pk).plain_name())]
@role_required("Area Director", "Secretariat")
def edit_ad(request, name):
"""Change the responsible Area Director for this charter."""
charter = get_object_or_404(Document, type="charter", name=name)
login = request.user.get_profile()
if request.method == 'POST':
form = AdForm(request.POST)
if form.is_valid():
new_ad = form.cleaned_data['ad']
if new_ad != charter.ad:
save_document_in_history(charter)
e = DocEvent(doc=charter, by=login)
e.desc = "Responsible AD changed to %s" % new_ad.plain_name()
if charter.ad:
e.desc += " from %s" % charter.ad.plain_name()
e.type = "changed_document"
e.save()
charter.ad = new_ad
charter.time = e.time
charter.save()
return HttpResponseRedirect(reverse('doc_view', kwargs={'name': charter.name}))
else:
init = { "ad" : charter.ad_id }
form = AdForm(initial=init)
return render_to_response('wgcharter/change_ad.html',
{'form': form,
'charter': charter,
},
context_instance = RequestContext(request))
class UploadForm(forms.Form):
content = forms.CharField(widget=forms.Textarea, label="Charter text", help_text="Edit the charter text", required=False)