Introduce basic charter support for non-WG groups
- Legacy-Id: 7550
This commit is contained in:
parent
25625a0241
commit
d3efeb421f
|
@ -1,6 +1,6 @@
|
|||
import os, datetime, shutil, textwrap, json
|
||||
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseNotFound, HttpResponseForbidden, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template import RequestContext
|
||||
|
@ -9,6 +9,7 @@ from django.utils.html import escape
|
|||
from django.utils.safestring import mark_safe
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
|
@ -21,7 +22,7 @@ from ietf.doc.utils_charter import ( historic_milestones_for_charter,
|
|||
approved_revision, default_review_text, default_action_text, email_state_changed,
|
||||
generate_ballot_writeup, generate_issue_ballot_mail, next_approved_revision, next_revision )
|
||||
from ietf.group.models import ChangeStateGroupEvent, MilestoneGroupEvent
|
||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history
|
||||
from ietf.group.utils import save_group_in_history, save_milestone_in_history, can_manage_group_type
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.ietfauth.utils import has_role, role_required
|
||||
from ietf.name.models import GroupStateName
|
||||
|
@ -33,25 +34,34 @@ from ietf.wginfo.mails import email_secretariat
|
|||
|
||||
|
||||
class ChangeStateForm(forms.Form):
|
||||
charter_state = forms.ModelChoiceField(State.objects.filter(used=True, type="charter", slug__in=["infrev", "intrev", "extrev", "iesgrev"]), label="Charter state", empty_label=None, required=False)
|
||||
charter_state = forms.ModelChoiceField(State.objects.filter(used=True, type="charter"), label="Charter state", empty_label=None, required=False)
|
||||
initial_time = forms.IntegerField(initial=0, label="Review time", help_text="(in weeks)", required=False)
|
||||
message = forms.CharField(widget=forms.Textarea, help_text="Leave blank to change state without notifying the Secretariat", required=False, label=mark_safe("Message to<br> Secretariat"))
|
||||
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the charter history", required=False)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.hide = kwargs.pop('hide', None)
|
||||
group = kwargs.pop('group')
|
||||
super(ChangeStateForm, self).__init__(*args, **kwargs)
|
||||
state_field = self.fields["charter_state"]
|
||||
if group.type_id == "wg":
|
||||
state_field.queryset = state_field.queryset.filter(slug__in=("infrev", "intrev", "extrev", "iesgrev"))
|
||||
else:
|
||||
state_field.queryset = state_field.queryset.filter(slug__in=("notrev", "approved"))
|
||||
# hide requested fields
|
||||
if self.hide:
|
||||
for f in self.hide:
|
||||
self.fields[f].widget = forms.HiddenInput
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
@login_required
|
||||
def change_state(request, name, option=None):
|
||||
"""Change state of charter, notifying parties as necessary and
|
||||
logging the change as a comment."""
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
|
||||
if not can_manage_group_type(request.user, group.type_id):
|
||||
return HttpResponseForbidden("You don't have permission to access this view")
|
||||
|
||||
chartering_type = get_chartering_type(charter)
|
||||
|
||||
initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
|
||||
|
@ -61,13 +71,17 @@ def change_state(request, name, option=None):
|
|||
login = request.user.person
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST)
|
||||
form = ChangeStateForm(request.POST, group=group)
|
||||
if form.is_valid():
|
||||
clean = form.cleaned_data
|
||||
charter_rev = charter.rev
|
||||
|
||||
if option in ("initcharter", "recharter"):
|
||||
charter_state = State.objects.get(used=True, type="charter", slug="infrev")
|
||||
if group.type_id == "wg":
|
||||
charter_state = State.objects.get(used=True, type="charter", slug="infrev")
|
||||
else:
|
||||
charter_state = clean['charter_state']
|
||||
|
||||
# make sure we have the latest revision set, if we
|
||||
# abandoned a charter before, we could have reset the
|
||||
# revision to latest approved
|
||||
|
@ -142,6 +156,8 @@ def change_state(request, name, option=None):
|
|||
default_action_text(group, charter, login)
|
||||
elif charter_state.slug == "iesgrev":
|
||||
create_ballot_if_not_open(charter, login, "approve")
|
||||
elif charter_state.slug == "approved":
|
||||
fix_charter_revision_after_approval(charter, login)
|
||||
|
||||
if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
|
||||
e = InitialReviewDocEvent(type="initial_review", by=login, doc=charter)
|
||||
|
@ -151,10 +167,10 @@ def change_state(request, name, option=None):
|
|||
|
||||
return redirect('doc_view', name=charter.name)
|
||||
else:
|
||||
if option == "recharter":
|
||||
if option == "recharter" and group.type_id == "wg":
|
||||
hide = ['initial_time', 'charter_state', 'message']
|
||||
init = dict()
|
||||
elif option == "initcharter":
|
||||
elif option == "initcharter" and group.type_id == "wg":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message='%s has initiated chartering of the proposed %s:\n "%s" (%s).' % (login.plain_name(), group.type.name, group.name, group.acronym))
|
||||
elif option == "abandon":
|
||||
|
@ -164,7 +180,7 @@ def change_state(request, name, option=None):
|
|||
hide = ['initial_time']
|
||||
s = charter.get_state()
|
||||
init = dict(charter_state=s.pk if s else None)
|
||||
form = ChangeStateForm(hide=hide, initial=init)
|
||||
form = ChangeStateForm(hide=hide, initial=init, group=group)
|
||||
|
||||
prev_charter_state = None
|
||||
charter_hists = DocHistory.objects.filter(doc=charter).exclude(states__type="charter", states__slug=charter.get_state_slug()).order_by("-time")[:1]
|
||||
|
@ -352,17 +368,16 @@ class UploadForm(forms.Form):
|
|||
else:
|
||||
destination.write(self.cleaned_data['content'].encode("utf-8"))
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def submit(request, name=None, acronym=None, option=None):
|
||||
if name:
|
||||
if not name.startswith('charter-'):
|
||||
name = "charter-ietf-" + name
|
||||
elif acronym:
|
||||
name = "charter-ietf-" + acronym
|
||||
@login_required
|
||||
def submit(request, name=None, option=None):
|
||||
if not name.startswith('charter-'):
|
||||
raise Http404
|
||||
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
group = charter.group
|
||||
|
||||
login = request.user.person
|
||||
if not can_manage_group_type(request.user, group.type_id):
|
||||
return HttpResponseForbidden("You don't have permission to access this view")
|
||||
|
||||
path = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
not_uploaded_yet = charter.rev.endswith("-00") and not os.path.exists(path)
|
||||
|
@ -386,7 +401,7 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
|
||||
charter.rev = next_rev
|
||||
|
||||
e = NewRevisionDocEvent(doc=charter, by=login, type="new_revision")
|
||||
e = NewRevisionDocEvent(doc=charter, by=request.user.person, type="new_revision")
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), charter.rev)
|
||||
e.rev = charter.rev
|
||||
e.save()
|
||||
|
@ -423,7 +438,8 @@ def submit(request, name=None, acronym=None, option=None):
|
|||
return render_to_response('doc/charter/submit.html',
|
||||
{'form': form,
|
||||
'next_rev': next_rev,
|
||||
'group': group },
|
||||
'group': group,
|
||||
'name': name },
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class AnnouncementTextForm(forms.Form):
|
||||
|
@ -568,6 +584,26 @@ def ballot_writeupnotes(request, name):
|
|||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def fix_charter_revision_after_approval(charter, by):
|
||||
# according to spec, 00-02 becomes 01, so copy file and record new revision
|
||||
try:
|
||||
old = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
|
||||
shutil.copy(old, new)
|
||||
except IOError:
|
||||
return HttpResponse("There was an error copying %s to %s" %
|
||||
('%s-%s.txt' % (charter.canonical_name(), charter.rev),
|
||||
'%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev))))
|
||||
|
||||
e = NewRevisionDocEvent(doc=charter, by=by, type="new_revision")
|
||||
e.rev = next_approved_revision(charter.rev)
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), e.rev)
|
||||
e.save()
|
||||
|
||||
charter.rev = e.rev
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
|
||||
@role_required("Secretariat")
|
||||
def approve(request, name):
|
||||
"""Approve charter, changing state, fixing revision, copying file to final location."""
|
||||
|
@ -618,24 +654,7 @@ def approve(request, name):
|
|||
|
||||
e = add_state_change_event(charter, login, prev_charter_state, new_charter_state)
|
||||
|
||||
# according to spec, 00-02 becomes 01, so copy file and record new revision
|
||||
try:
|
||||
old = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), charter.rev))
|
||||
new = os.path.join(charter.get_file_path(), '%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev)))
|
||||
shutil.copy(old, new)
|
||||
except IOError:
|
||||
return HttpResponse("There was an error copying %s to %s" %
|
||||
('%s-%s.txt' % (charter.canonical_name(), charter.rev),
|
||||
'%s-%s.txt' % (charter.canonical_name(), next_approved_revision(charter.rev))))
|
||||
|
||||
e = NewRevisionDocEvent(doc=charter, by=login, type="new_revision")
|
||||
e.rev = next_approved_revision(charter.rev)
|
||||
e.desc = "New version available: <b>%s-%s.txt</b>" % (charter.canonical_name(), e.rev)
|
||||
e.save()
|
||||
|
||||
charter.rev = e.rev
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
fix_charter_revision_after_approval(charter, login)
|
||||
|
||||
email_secretariat(request, group, "Charter state changed to %s" % new_charter_state.name, change_description)
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ from ietf.community.models import CommunityList
|
|||
from ietf.doc.mails import email_ad
|
||||
from ietf.doc.views_status_change import RELATION_SLUGS as status_change_relationships
|
||||
from ietf.group.models import Role
|
||||
from ietf.group.utils import can_manage_group_type
|
||||
from ietf.ietfauth.utils import has_role, is_authorized_in_doc_stream, user_is_person, role_required
|
||||
from ietf.name.models import StreamName, BallotPositionName
|
||||
from ietf.person.models import Email
|
||||
|
@ -401,6 +402,8 @@ def document_main(request, name, rev=None):
|
|||
if chartering and not snapshot:
|
||||
milestones = doc.group.groupmilestone_set.filter(state="charter")
|
||||
|
||||
can_manage = can_manage_group_type(request.user, doc.group.type_id)
|
||||
|
||||
return render_to_response("doc/document_charter.html",
|
||||
dict(doc=doc,
|
||||
top=top,
|
||||
|
@ -413,6 +416,7 @@ def document_main(request, name, rev=None):
|
|||
ballot_summary=ballot_summary,
|
||||
group=group,
|
||||
milestones=milestones,
|
||||
can_manage=can_manage,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ Charter submission for {{ group.acronym }} {{ group.type.name }}
|
|||
{% block content %}
|
||||
<h1>Charter submission for {{ group.acronym }} {{ group.type.name }}</h1>
|
||||
|
||||
<p>The text will be submitted as <strong>charter-ietf-{{ group.acronym }}-{{ next_rev }}</strong></p>
|
||||
<p>The text will be submitted as <strong>{{ name }}-{{ next_rev }}</strong></p>
|
||||
<form class="edit-info" action="" enctype="multipart/form-data" method="post">{% csrf_token %}
|
||||
<table>
|
||||
{% for field in form.visible_fields %}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
{% if snapshot %}Snapshot of{% endif %}
|
||||
{% if doc.get_state_slug != "approved" %}Proposed{% endif %}
|
||||
Charter for "{{ group.name }}"
|
||||
(<a {% if group.type.slug == "wg" %}href="{% url "ietf.wginfo.views.group_charter" group_type=group.type_id acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
|
||||
(<a {% if group.type_id == "wg" or group.type_id == "rg" %}href="{% url "ietf.wginfo.views.group_charter" group_type=group.type_id acronym=group.acronym %}"{% endif %}>{{ group.acronym }}</a>) {{ group.type.name }}
|
||||
</div>
|
||||
|
||||
<table id="metatable" width="100%">
|
||||
|
@ -38,7 +38,7 @@
|
|||
<td>
|
||||
<div>
|
||||
<a title="{{ doc.get_state.desc }}"
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
|
||||
{% if not snapshot and can_manage %}
|
||||
class="editlink" href="{% url "charter_change_state" name=doc.name %}"
|
||||
{% endif %}>
|
||||
{{ doc.get_state.name }}
|
||||
|
@ -69,7 +69,7 @@
|
|||
|
||||
<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>
|
||||
<td><a {% if 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>
|
||||
|
@ -94,13 +94,13 @@
|
|||
</div>
|
||||
|
||||
<div class="actions">
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
|
||||
{% if not snapshot and can_manage %}
|
||||
{% if chartering %}
|
||||
{% url "charter_startstop_process" name=doc.name option='abandon' as abandon_url %}{% if abandon_url %}<a class="button" href="{{ abandon_url }}">Abandon Effort</a>{% endif %}
|
||||
|
||||
{% if request.user|has_role:"Secretariat" %}
|
||||
{% url "charter_approve" name=doc.name as approve_url %}{% if approve_url %}<a class="button" href="{{ approve_url }}">Approve Charter</a>{% endif %}
|
||||
{% endif %}
|
||||
{% if user|has_role:"Secretariat" %}
|
||||
{% url "charter_approve" name=doc.name as approve_url %}{% if approve_url %}<a class="button" href="{{ approve_url }}">Approve Charter</a>{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if group.state_id == "proposed" or group.state_id == "bof" %}
|
||||
|
@ -118,7 +118,7 @@
|
|||
|
||||
<h3>Charter {{ doc.canonical_name }}-{{ doc.rev }}
|
||||
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" and chartering and group.state_id != "conclude" %}
|
||||
{% if not snapshot and can_manage and chartering and group.state_id != "conclude" %}
|
||||
<a class="edit" href="{% url "charter_submit" name=doc.name %}">Change charter text</a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
@ -131,7 +131,7 @@
|
|||
|
||||
{% if not snapshot and chartering %}
|
||||
<h3>Proposed Milestones
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
{% if can_manage %}
|
||||
<a class="edit" href="{% url "group_edit_charter_milestones" group_type=doc.group.type_id acronym=doc.group.acronym %}">Edit charter milestones</a>
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
|
|
@ -46,7 +46,7 @@ is occasionally incorrect.</span>
|
|||
<a href="{% url "doc_view" name=group.charter.name %}">{{ group.charter.name }}-{{ group.charter.rev }}</a> ({{ group.charter.get_state.name }})
|
||||
{% else %}
|
||||
none
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
{% if can_manage %}
|
||||
- <a href="{% url "ietf.wginfo.edit.submit_initial_charter" group_type=group.type_id acronym=group.acronym %}">Submit Charter</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
|
|
@ -19,7 +19,7 @@ from ietf.doc.utils import get_tags_for_stream_id
|
|||
from ietf.group.models import ( Group, Role, GroupEvent, GroupHistory, GroupStateName,
|
||||
GroupStateTransitions, GroupTypeName, GroupURL, ChangeStateGroupEvent )
|
||||
from ietf.group.utils import save_group_in_history, can_manage_group_type
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.person.forms import EmailsField
|
||||
from ietf.person.models import Person, Email
|
||||
from ietf.wginfo.mails import email_secretariat
|
||||
|
@ -166,8 +166,9 @@ def submit_initial_charter(request, group_type, acronym=None):
|
|||
if not group.charter:
|
||||
group.charter = get_or_create_initial_charter(group, group_type)
|
||||
group.save()
|
||||
|
||||
return redirect('charter_submit', name=group.charter.name, option="initcharter")
|
||||
|
||||
|
||||
@login_required
|
||||
def edit(request, group_type, acronym=None, action="edit"):
|
||||
"""Edit or create a group, notifying parties as
|
||||
|
|
|
@ -13,7 +13,6 @@ from ietf.doc.models import Document, DocEvent
|
|||
from ietf.doc.utils import get_chartering_type
|
||||
from ietf.group.models import Group, GroupMilestone, MilestoneGroupEvent
|
||||
from ietf.group.utils import save_milestone_in_history, can_manage_group_type, milestone_reviewer_for_group_type
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.name.models import GroupMilestoneStateName
|
||||
from ietf.wginfo.mails import email_milestones_changed
|
||||
|
||||
|
@ -380,7 +379,7 @@ def reset_charter_milestones(request, group_type, acronym):
|
|||
|
||||
return redirect('group_edit_charter_milestones', group_type=group.type_id, acronym=group.acronym)
|
||||
|
||||
return render('wginfo/reset_charter_milestones.html',
|
||||
return render(request, 'wginfo/reset_charter_milestones.html',
|
||||
dict(group=group,
|
||||
charter_milestones=charter_milestones,
|
||||
current_milestones=current_milestones,
|
||||
|
|
|
@ -50,7 +50,6 @@ from ietf.doc.utils import get_chartering_type
|
|||
from ietf.doc.templatetags.ietf_filters import clean_whitespace
|
||||
from ietf.group.models import Group, Role
|
||||
from ietf.group.utils import get_charter_text, can_manage_group_type, milestone_reviewer_for_group_type
|
||||
from ietf.ietfauth.utils import has_role
|
||||
from ietf.utils.pipe import pipe
|
||||
|
||||
def roles(group, role_name):
|
||||
|
@ -180,6 +179,9 @@ def bofs(request, group_type):
|
|||
return render(request, 'wginfo/bofs.html',dict(groups=groups))
|
||||
|
||||
def chartering_groups(request, group_type):
|
||||
if group_type != "wg":
|
||||
raise Http404
|
||||
|
||||
charter_states = State.objects.filter(used=True, type="charter").exclude(slug__in=("approved", "notrev"))
|
||||
groups = Group.objects.filter(type=group_type, charter__states__in=charter_states).select_related("state", "charter")
|
||||
|
||||
|
@ -305,12 +307,15 @@ def group_charter(request, group_type, acronym):
|
|||
rg="Research Group",
|
||||
)
|
||||
|
||||
can_manage = can_manage_group_type(request.user, group.type_id)
|
||||
|
||||
return render(request, 'wginfo/group_charter.html',
|
||||
construct_group_menu_context(request, group, "charter", {
|
||||
"milestones_in_review": group.groupmilestone_set.filter(state="review"),
|
||||
"milestone_reviewer": milestone_reviewer_for_group_type(group_type),
|
||||
"requested_close": requested_close,
|
||||
"long_group_type":long_group_types.get(group_type, "Group")
|
||||
"long_group_type":long_group_types.get(group_type, "Group"),
|
||||
"can_manage": can_manage,
|
||||
}))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue