Merged [4806] from rjsparks@nostrum.com:

Better handling for BoFs, particularly those that won't create WGs
 - Legacy-Id: 4939
This commit is contained in:
Henrik Levkowetz 2012-10-21 14:40:02 +00:00
parent d9619aaa0a
commit d0214d3b25
11 changed files with 244 additions and 23 deletions

View file

@ -131,7 +131,7 @@ class IETFWG(Group):
#status = models.ForeignKey(WGStatus)
@property
def status_id(self):
return { "active": 1, "dormant": 2, "conclude": 3, "proposed": 4, "bof": 4, }[self.state_id]
return { "active": 1, "dormant": 2, "conclude": 3, "proposed": 4, "bof": 4, "abandon": 4 }[self.state_id]
#area_director = models.ForeignKey(AreaDirector, null=True)
#meeting_scheduled = models.CharField(blank=True, max_length=3)
@property

View file

@ -0,0 +1,157 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
class Migration(DataMigration):
def forwards(self, orm):
GroupStateName(slug='abandon',name='Abandonded',desc='Formation of the group (most likely a BoF or Proposed WG) was abandoned',used=True).save()
def backwards(self, orm):
pass
models = {
'name.ballotpositionname': {
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.constraintname': {
'Meta': {'ordering': "['order']", 'object_name': 'ConstraintName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.docrelationshipname': {
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.docremindertypename': {
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.doctagname': {
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.doctypename': {
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.groupballotpositionname': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupBallotPositionName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.groupstatename': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.grouptypename': {
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.intendedstdlevelname': {
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.liaisonstatementpurposename': {
'Meta': {'ordering': "['order']", 'object_name': 'LiaisonStatementPurposeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.meetingtypename': {
'Meta': {'ordering': "['order']", 'object_name': 'MeetingTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.rolename': {
'Meta': {'ordering': "['order']", 'object_name': 'RoleName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.sessionstatusname': {
'Meta': {'ordering': "['order']", 'object_name': 'SessionStatusName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.stdlevelname': {
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.streamname': {
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'name.timeslottypename': {
'Meta': {'ordering': "['order']", 'object_name': 'TimeSlotTypeName'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
}
}
complete_apps = ['name']

View file

@ -17,7 +17,7 @@ class NameModel(models.Model):
ordering = ['order']
class GroupStateName(NameModel):
"""BOF, Proposed, Active, Dormant, Concluded"""
"""BOF, Proposed, Active, Dormant, Concluded, Abandoned"""
class GroupTypeName(NameModel):
"""IETF, Area, WG, RG, Team, etc."""
class RoleName(NameModel):

View file

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

View file

@ -0,0 +1,40 @@
{% extends "base.html" %}
{% block title %}BoFs{% endblock %}
{% block content %}
{% load ietf_filters %}
{% load ballot_icon %}
<h1>Bofs</h1>
<p>Groups in the BoF state</p>
{% if user|has_role:"Area Director,Secretariat" %}
<p><a href="{% url bof_create %}">Create a new BoF</a></p>
{% endif %}
{% if not groups %}
<p><b>No groups found.</b></p>
{% else %}
<table class="ietf-table ietf-doctable">
<tr>
<th>Group</th>
<th>Name</th>
<th>Date</th>
</tr>
{% for g in groups %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td class="acronym">
<a href="{% url wg_charter acronym=g.acronym %}">{{ g.acronym }}</a>
</td>
<td class="title">
<a {%comment%}href="{% url doc_view name=g.charter.name %}"{%endcomment%}>{{ g.name }}</a>
</td>
<td class="date">{{ g.time|date:"Y-m-d" }}</td>
</tr>
{% endfor %}
</table>
{% endif %}
{% endblock %}

View file

@ -26,11 +26,16 @@ ul.errorlist li { color: #a00; margin: 0px; padding: 0px; list-style: none; }
{% block content %}
{% load ietf_filters %}
<h1>{% if wg %}
<h1>
{% ifequal action "edit" %}
Edit WG {{ wg.acronym }}
{% else %}
{% else %}
{% ifequal action "charter" %}
Start chartering new WG
{% endif %}
{% else %}
Create new WG or BoF
{% endifequal %}
{% endifequal %}
</h1>
<form class="edit" action="" method="POST">
@ -60,12 +65,16 @@ Start chartering new WG
<tr>
<td></td>
<td class="actions">
{% if wg %}
{% ifequal action "edit" %}
<a href="{% url wg_charter acronym=wg.acronym %}">Back</a>
<input type="submit" value="Save"/>
{% else %}
<input type="submit" value="Start chartering"/>
{% endif %}
{% else %}
{% ifequal action "charter" %}
<input type="submit" value="Start chartering"/>
{% else %}
<input type="submit" value="Create group or bof"/>
{% endifequal %}
{% endifequal %}
</td>
</tr>
</table>

View file

@ -38,6 +38,8 @@ from django.conf import settings
from django.template import TemplateDoesNotExist
from django.test.simple import run_tests as django_run_tests
import debug
import ietf.utils.mail
loaded_templates = set()

View file

@ -75,6 +75,7 @@ def change_state(request, name, option=None):
elif option == "abandon":
if wg.state_id in ("proposed","bof","unknown"):
charter_state = State.objects.get(type="charter", slug="notrev")
#TODO : set an abandoned state and leave some comments here
else:
charter_state = State.objects.get(type="charter", slug="approved")
charter_rev = approved_revision(charter.rev)
@ -160,7 +161,7 @@ def change_state(request, name, option=None):
"abandon": "Abandon effort on WG %s" % wg.acronym,
}.get(option)
if not title:
title = "Change state of WG %s" % wg.acronym
title = "Change chartering state of WG %s" % wg.acronym
def state_pk(slug):
return State.objects.get(type="charter", slug=slug).pk

View file

@ -9,6 +9,8 @@ from django import forms
from django.utils import simplejson
from django.utils.html import mark_safe
import debug
from ietf.ietfauth.decorators import role_required, has_role
from ietf.doc.models import *
@ -23,6 +25,7 @@ from ietf.person.forms import EmailsField
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)
@ -109,7 +112,7 @@ def edit(request, acronym=None, action="edit"):
if action == "edit":
wg = get_object_or_404(Group, acronym=acronym)
new_wg = False
elif action == "create":
elif action in ("create","charter"):
wg = None
new_wg = True
else:
@ -122,30 +125,29 @@ def edit(request, acronym=None, action="edit"):
if form.is_valid():
clean = form.cleaned_data
if new_wg:
# get ourselves a proposed WG
try:
wg = Group.objects.get(acronym=clean["acronym"])
save_group_in_history(wg)
wg.state = GroupStateName.objects.get(slug="proposed")
wg.time = datetime.datetime.now()
wg.save()
except Group.DoesNotExist:
wg = Group.objects.create(name=clean["name"],
acronym=clean["acronym"],
type=GroupTypeName.objects.get(slug="wg"),
state=GroupStateName.objects.get(slug="proposed"))
state=clean["state"]
)
e = ChangeStateGroupEvent(group=wg, type="changed_state")
e.time = wg.time
e.by = login
e.state_id = "proposed"
e.desc = "Proposed group"
e.state_id = clean["state"].slug
e.desc = clean["state"].name
e.save()
else:
save_group_in_history(wg)
if not wg.charter: # make sure we have a charter
if action=="charter" and not wg.charter: # make sure we have a charter
try:
charter = Document.objects.get(docalias__name="charter-ietf-%s" % wg.acronym)
except Document.DoesNotExist:
@ -159,8 +161,8 @@ def edit(request, acronym=None, action="edit"):
)
charter.save()
charter.set_state(State.objects.get(type="charter", slug="notrev"))
# Create an alias as well
# Create an alias as well
DocAlias.objects.create(
name=charter.name,
document=charter
@ -188,13 +190,14 @@ def edit(request, acronym=None, action="edit"):
# update the attributes, keeping track of what we're doing
diff('name', "Name")
diff('acronym', "Acronym")
diff('state', "State")
diff('ad', "Shepherding AD")
diff('parent', "IETF Area")
diff('list_email', "Mailing list email")
diff('list_subscribe', "Mailing list subscribe address")
diff('list_archive', "Mailing list archive")
if not new_wg and wg.acronym != prev_acronym:
if not new_wg and wg.acronym != prev_acronym and wg.charter:
save_document_in_history(wg.charter)
DocAlias.objects.get_or_create(
name="charter-ietf-%s" % wg.acronym,
@ -241,7 +244,7 @@ def edit(request, acronym=None, action="edit"):
wg.save()
if new_wg:
if action=="charter":
return redirect('charter_submit', name=wg.charter.name, option="initcharter")
return redirect('wg_charter', acronym=wg.acronym)
@ -250,6 +253,7 @@ def edit(request, acronym=None, action="edit"):
from ietf.person.forms import json_emails
init = dict(name=wg.name,
acronym=wg.acronym,
state=wg.state,
chairs=Email.objects.filter(role__group=wg, role__name="chair"),
secretaries=Email.objects.filter(role__group=wg, role__name="secr"),
techadv=Email.objects.filter(role__group=wg, role__name="techadv"),
@ -268,6 +272,7 @@ def edit(request, acronym=None, action="edit"):
return render_to_response('wginfo/edit.html',
dict(wg=wg,
form=form,
action=action,
user=request.user,
login=login),
context_instance=RequestContext(request))

View file

@ -14,8 +14,10 @@ urlpatterns = patterns('',
(r'^1wg-summary-by-acronym.txt', views.wg_summary_acronym),
(r'^1wg-charters.txt', views.wg_charters),
(r'^1wg-charters-by-acronym.txt', views.wg_charters_by_acronym),
(r'^chartering/create/$', edit.edit, {'action': "create"}, "wg_create"),
(r'^chartering/$', views.chartering_wgs),
(r'^bofs/$', views.bofs),
(r'^chartering/create/$', edit.edit, {'action': "charter"}, "wg_create"),
(r'^bofs/create/$', edit.edit, {'action': "create"}, "bof_create"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/documents/txt/$', views.wg_documents_txt),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/$', views.wg_documents_html, None, "wg_docs"),
(r'^(?P<acronym>[a-zA-Z0-9-]+)/charter/$', views.wg_charter, None, 'wg_charter'),

View file

@ -122,6 +122,10 @@ def wg_dirREDESIGN(request):
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
wg_dir = wg_dirREDESIGN
def bofs(request):
groups = Group.objects.filter(type="wg", state="bof")
return render_to_response('wginfo/bofs.html',dict(groups=groups),RequestContext(request))
def chartering_wgs(request):
charter_states = State.objects.filter(type="charter").exclude(slug__in=("approved", "notrev"))
groups = Group.objects.filter(type="wg", charter__states__in=charter_states).select_related("state", "charter")