Merge forward complete

- Legacy-Id: 5328
This commit is contained in:
Robert Sparks 2013-01-24 21:28:27 +00:00
parent 31a02c097e
commit 589ff698ee
35 changed files with 2803 additions and 110 deletions

37
ietf/doc/forms.py Normal file
View file

@ -0,0 +1,37 @@
import datetime
from django import forms
from ietf.iesg.models import TelechatDate
class TelechatForm(forms.Form):
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False)
returning_item = forms.BooleanField(required=False)
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
dates = [d.date for d in TelechatDate.objects.active().order_by('date')]
init = kwargs['initial'].get("telechat_date")
if init and init not in dates:
dates.insert(0, init)
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, d.strftime("%Y-%m-%d")) for d in dates]
from ietf.person.models import Person
class AdForm(forms.Form):
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
label="Shepherding 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())]
class NotifyForm(forms.Form):
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)

View file

@ -0,0 +1,427 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
from ietf.doc.models import StateType, State, BallotType, DocTypeName
from ietf.name.models import BallotPositionName
class Migration(DataMigration):
def forwards(self, orm):
statchg = StateType(slug='statchg',label='RFC Status Change')
statchg.save()
needshep = State(
type=statchg,slug="needshep",
name="Needs Shepherd",used=True,order=1,
desc="An RFC status change has been requested, but a shepherding AD has not yet been assigned")
needshep.save()
adrev = State(
type=statchg,slug="adrev",
name="AD Review",used=True,order=2,
desc="The sponsoring AD is preparing an RFC status change document")
adrev.save()
iesgeval = State(
type=statchg,slug="iesgeval",
name="IESG Evaluation",used=True,order=3,
desc="The IESG is considering the proposed RFC status changes")
iesgeval.save()
defer = State(
type=statchg,slug="defer",
name="IESG Evaluation - Defer",used=True, order=4,
desc="The evaluation of the proposed RFC status changes have been deferred to the next telechat")
defer.save()
appr_pr = State(
type=statchg,slug="appr-pr",
name="Approved - point raised", used=True,order=5,
desc="The IESG has approved the RFC status changes, but a point has been raised that should be cleared before proceeding to announcement to be sent")
appr_pr.save()
appr_pend = State(
type=statchg,slug="appr-pend",
name="Approved - announcement to be sent", used=True,order=6,
desc="The IESG has approved the RFC status changes, but the secretariat has not yet sent the announcement")
appr_pend.save()
appr_sent = State(
type=statchg,slug="appr-sent",
name="Approved - announcement sent",used=True,order=7,
desc="The secretariat has announced the IESG's approved RFC status changes")
appr_sent.save()
withdraw = State(
type=statchg,slug="withdraw",
name="Withdrawn",used=True,order=8,
desc="The request for RFC status changes was withdrawn")
withdraw.save()
dead = State(
type=statchg,slug="dead",
name="Dead",used=True,order=9,
desc="The RFC status changes have been abandoned")
dead.save()
needshep.next_states.add(adrev,withdraw,dead)
needshep.save()
adrev.next_states.add(iesgeval,withdraw,dead)
adrev.save()
iesgeval.next_states.add(appr_pr,appr_pend,defer,withdraw,dead)
iesgeval.save()
defer.next_states.add(iesgeval,appr_pend,appr_pr,withdraw,dead)
defer.save()
appr_pend.next_states.add(appr_sent,withdraw)
appr_pend.save()
withdraw.next_states.add(needshep)
withdraw.save()
dead.next_states.add(needshep)
dead.save()
statchg_ballot = BallotType(doc_type=DocTypeName.objects.get(slug='statchg'),
slug='statchg',name="Approve",used=True,
question="Do we approve these RFC status changes?")
statchg_ballot.save()
statchg_ballot.positions.add('yes','noobj','discuss','abstain','recuse','norecord')
statchg_ballot.save()
def backwards(self, orm):
StateType.objects.filter(slug='statchg').delete()
StateType.objects.filter(slug='statchg').delete()
BallotType.objects.filter(slug='statchg').delete()
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'doc.ballotdocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
},
'doc.ballotpositiondocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
},
'doc.ballottype': {
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'doc.docalias': {
'Meta': {'object_name': 'DocAlias'},
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
},
'doc.docevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
'desc': ('django.db.models.fields.TextField', [], {}),
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'doc.dochistory': {
'Meta': {'object_name': 'DocHistory'},
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
},
'doc.dochistoryauthor': {
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.IntegerField', [], {})
},
'doc.docreminder': {
'Meta': {'object_name': 'DocReminder'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'due': ('django.db.models.fields.DateTimeField', [], {}),
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
},
'doc.document': {
'Meta': {'object_name': 'Document'},
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
},
'doc.documentauthor': {
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
},
'doc.initialreviewdocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
'doc.lastcalldocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
},
'doc.newrevisiondocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
},
'doc.relateddochistory': {
'Meta': {'object_name': 'RelatedDocHistory'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
},
'doc.relateddocument': {
'Meta': {'object_name': 'RelatedDocument'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
},
'doc.state': {
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}),
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
},
'doc.statetype': {
'Meta': {'object_name': 'StateType'},
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
},
'doc.telechatdocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
},
'doc.writeupdocevent': {
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
},
'group.group': {
'Meta': {'object_name': 'Group'},
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
},
'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.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.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.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'})
},
'person.email': {
'Meta': {'object_name': 'Email'},
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
},
'person.person': {
'Meta': {'object_name': 'Person'},
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
}
}
complete_apps = ['doc']

View file

@ -150,8 +150,7 @@ class RelatedDocument(models.Model):
def action(self):
return self.relationship.name
def inverse_action():
infinitive = self.relationship.name[:-1]
return u"%sd by" % infinitive
return self.relationship.revname
def __unicode__(self):
return u"%s %s %s" % (self.source.name, self.relationship.name.lower(), self.target.name)

View file

@ -1,3 +1,4 @@
from ietf.doc.tests_conflict_review import *
from ietf.doc.tests_status_change import *

View file

@ -0,0 +1,392 @@
import os
import shutil
from pyquery import PyQuery
from StringIO import StringIO
from textwrap import wrap
import django.test
from django.conf import settings
from django.core.urlresolvers import reverse as urlreverse
from ietf.utils.test_utils import login_testing_unauthorized
from ietf.utils.test_data import make_test_data
from ietf.utils.mail import outbox
from ietf.doc.utils import create_ballot_if_not_open
from ietf.doc.views_status_change import default_approval_text
from ietf.doc.models import Document,DocEvent,NewRevisionDocEvent,BallotPositionDocEvent,TelechatDocEvent,DocAlias,State
from ietf.name.models import StreamName
from ietf.group.models import Person
from ietf.iesg.models import TelechatDate
class StatusChangeTestCase(django.test.TestCase):
fixtures = ['names']
def test_start_review(self):
url = urlreverse('start_rfc_status_change')
login_testing_unauthorized(self, "secretary", url)
# normal get should succeed and get a reasonable form
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form select[name=create_in_state]')),1)
ad_strpk = str(Person.objects.get(name='Aread Irector').pk)
state_strpk = str(State.objects.get(slug='adrev',type__slug='statchg').pk)
# faulty posts
## Must set a responsible AD
r = self.client.post(url,dict(document_name="bogus",title="Bogus Title",ad="",create_in_state=state_strpk,notify='ipu@ietf.org'))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
## Must set a name
r = self.client.post(url,dict(document_name="",title="Bogus Title",ad=ad_strpk,create_in_state=state_strpk,notify='ipu@ietf.org'))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
## Must not choose a document name that already exists
r = self.client.post(url,dict(document_name="imaginary-mid-review",title="Bogus Title",ad=ad_strpk,create_in_state=state_strpk,notify='ipu@ietf.org'))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
## Must set a title
r = self.client.post(url,dict(document_name="bogus",title="",ad=ad_strpk,create_in_state=state_strpk,notify='ipu@ietf.org'))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
# successful status change start
r = self.client.post(url,dict(document_name="imaginary-new",title="A new imaginary status change",ad=ad_strpk,
create_in_state=state_strpk,notify='ipu@ietf.org',new_relation_row_blah="rfc9999",
statchg_relation_row_blah="tois"))
self.assertEquals(r.status_code, 302)
status_change = Document.objects.get(name='status-change-imaginary-new')
self.assertEquals(status_change.get_state('statchg').slug,'adrev')
self.assertEquals(status_change.rev,u'00')
self.assertEquals(status_change.ad.name,u'Aread Irector')
self.assertEquals(status_change.notify,u'ipu@ietf.org')
self.assertTrue(status_change.relateddocument_set.filter(relationship__slug='tois',target__document__name='draft-ietf-random-thing'))
def test_change_state(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_change_state',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form select[name=new_state]')),1)
# faulty post
r = self.client.post(url,dict(new_state=""))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
# successful change to AD Review
adrev_pk = str(State.objects.get(slug='adrev',type__slug='statchg').pk)
r = self.client.post(url,dict(new_state=adrev_pk,comment='RDNK84ZD'))
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.get_state('statchg').slug,'adrev')
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('RDNK84ZD'))
self.assertFalse(doc.active_ballot())
# successful change to IESG Evaluation
iesgeval_pk = str(State.objects.get(slug='iesgeval',type__slug='statchg').pk)
r = self.client.post(url,dict(new_state=iesgeval_pk,comment='TGmZtEjt'))
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.get_state('statchg').slug,'iesgeval')
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('TGmZtEjt'))
self.assertTrue(doc.active_ballot())
self.assertEquals(doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes')
def test_edit_notices(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_notices',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form input[name=notify]')),1)
self.assertEquals(doc.notify,q('form input[name=notify]')[0].value)
# change notice list
newlist = '"Foo Bar" <foo@bar.baz.com>'
r = self.client.post(url,dict(notify=newlist))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.notify,newlist)
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Notification list changed'))
def test_edit_ad(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_ad',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", 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)
# change ads
ad2 = Person.objects.get(name='Ad No2')
r = self.client.post(url,dict(ad=str(ad2.pk)))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.ad,ad2)
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Shepherding AD changed'))
def test_edit_telechat_date(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_telechat_date',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('select[name=telechat_date]')),1)
# set a date
self.assertFalse(doc.latest_event(TelechatDocEvent, "scheduled_for_telechat"))
telechat_date = TelechatDate.objects.active().order_by('date')[0].date
r = self.client.post(url,dict(telechat_date=telechat_date.isoformat()))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date,telechat_date)
# move it forward a telechat (this should set the returning item bit)
telechat_date = TelechatDate.objects.active().order_by('date')[1].date
r = self.client.post(url,dict(telechat_date=telechat_date.isoformat()))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertTrue(doc.returning_item())
# clear the returning item bit
r = self.client.post(url,dict(telechat_date=telechat_date.isoformat()))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertFalse(doc.returning_item())
# set the returning item bit without changing the date
r = self.client.post(url,dict(telechat_date=telechat_date.isoformat(),returning_item="on"))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertTrue(doc.returning_item())
# Take the doc back off any telechat
r = self.client.post(url,dict(telechat_date=""))
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.latest_event(TelechatDocEvent, "scheduled_for_telechat").telechat_date,None)
def test_approve(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_approve',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "secretary", url)
# Some additional setup
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9999'),relationship_id='tois')
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9998'),relationship_id='tohist')
create_ballot_if_not_open(doc,Person.objects.get(name="Sec Retary"),"statchg")
doc.set_state(State.objects.get(slug='appr-pend',type='statchg'))
doc.save()
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form.approve')),1)
# There should be two messages to edit
self.assertEquals(q('input#id_form-TOTAL_FORMS').val(),'2')
self.assertTrue( '(rfc9999) to Internet Standard' in ''.join(wrap(r.content,2**16)))
self.assertTrue( '(rfc9998) to Historic' in ''.join(wrap(r.content,2**16)))
# submit
messages_before = len(outbox)
msg0=default_approval_text(doc,doc.relateddocument_set.all()[0])
msg1=default_approval_text(doc,doc.relateddocument_set.all()[1])
r = self.client.post(url,{'form-0-announcement_text':msg0,'form-1-announcement_text':msg1,'form-TOTAL_FORMS':'2','form-INITIAL_FORMS':'2','form-MAX_NUM_FORMS':''})
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.get_state_slug(),'appr-sent')
self.assertFalse(doc.ballot_open("statchg"))
self.assertEquals(len(outbox), messages_before + 2)
self.assertTrue('Action:' in outbox[-1]['Subject'])
self.assertTrue('(rfc9999) to Internet Standard' in ''.join(wrap(unicode(outbox[-1])+unicode(outbox[-2]),2**16)))
self.assertTrue('(rfc9998) to Historic' in ''.join(wrap(unicode(outbox[-1])+unicode(outbox[-2]),2**16)))
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('The following approval message was sent'))
def test_edit_relations(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_relations',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "secretary", url)
# Some additional setup
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9999'),relationship_id='tois')
doc.relateddocument_set.create(target=DocAlias.objects.get(name='rfc9998'),relationship_id='tohist')
# get
r = self.client.get(url)
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertEquals(len(q('form.edit-status-change-rfcs')),1)
# There should be three rows on the form
self.assertEquals(len(q('tr[id^=relation_row]')),3)
# Try to add a relation to an RFC that doesn't exist
r = self.client.post(url,dict(new_relation_row_blah="rfc9997",
statchg_relation_row_blah="tois"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
# Try to add a relation leaving the relation type blank
r = self.client.post(url,dict(new_relation_row_blah="rfc9999",
statchg_relation_row_blah=""))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
# Try to add a relation with an unknown relationship type
r = self.client.post(url,dict(new_relation_row_blah="rfc9999",
statchg_relation_row_blah="badslug"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(len(q('form ul.errorlist')) > 0)
# Successful change of relations
r = self.client.post(url,dict(new_relation_row_blah="rfc9999",
statchg_relation_row_blah="toexp",
new_relation_row_foo="rfc9998",
statchg_relation_row_foo="tobcp"))
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.relateddocument_set.count(),2)
verify9999 = doc.relateddocument_set.filter(target__name='rfc9999')
self.assertTrue(verify9999)
self.assertEquals(verify9999.count(),1)
self.assertEquals(verify9999[0].relationship.slug,'toexp')
verify9998 = doc.relateddocument_set.filter(target__name='rfc9998')
self.assertTrue(verify9998)
self.assertEquals(verify9998.count(),1)
self.assertEquals(verify9998[0].relationship.slug,'tobcp')
self.assertTrue(doc.latest_event(DocEvent,type="added_comment").desc.startswith('Affected RFC list changed.'))
def setUp(self):
make_test_data()
class StatusChangeSubmitTestCase(django.test.TestCase):
fixtures = ['names']
def test_initial_submission(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_submit',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", url)
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code,200)
q = PyQuery(r.content)
self.assertTrue(q('textarea')[0].text.startswith("Provide a description"))
# Faulty posts using textbox
# Right now, nothing to test - we let people put whatever the web browser will let them put into that textbox
# sane post using textbox
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
self.assertEquals(doc.rev,u'00')
self.assertFalse(os.path.exists(path))
r = self.client.post(url,dict(content="Some initial review text\n",submit_response="1"))
self.assertEquals(r.status_code,302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.rev,u'00')
with open(path) as f:
self.assertEquals(f.read(),"Some initial review text\n")
f.close()
self.assertTrue( "mid-review-00" in doc.latest_event(NewRevisionDocEvent).desc)
def test_subsequent_submission(self):
doc = Document.objects.get(name='status-change-imaginary-mid-review')
url = urlreverse('status_change_submit',kwargs=dict(name=doc.name))
login_testing_unauthorized(self, "ad", url)
# A little additional setup
# doc.rev is u'00' per the test setup - double-checking that here - if it fails, the breakage is in setUp
self.assertEquals(doc.rev,u'00')
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
with open(path,'w') as f:
f.write('This is the old proposal.')
f.close()
# normal get
r = self.client.get(url)
self.assertEquals(r.status_code,200)
q = PyQuery(r.content)
self.assertTrue(q('textarea')[0].text.startswith("This is the old proposal."))
# faulty posts trying to use file upload
# Copied from wgtracker tests - is this really testing the server code, or is it testing
# how client.post populates Content-Type?
test_file = StringIO("\x10\x11\x12") # post binary file
test_file.name = "unnamed"
r = self.client.post(url, dict(txt=test_file,submit_response="1"))
self.assertEquals(r.status_code, 200)
self.assertTrue("does not appear to be a text file" in r.content)
# sane post uploading a file
test_file = StringIO("This is a new proposal.")
test_file.name = "unnamed"
r = self.client.post(url,dict(txt=test_file,submit_response="1"))
self.assertEquals(r.status_code, 302)
doc = Document.objects.get(name='status-change-imaginary-mid-review')
self.assertEquals(doc.rev,u'01')
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
with open(path) as f:
self.assertEquals(f.read(),"This is a new proposal.")
f.close()
self.assertTrue( "mid-review-01" in doc.latest_event(NewRevisionDocEvent).desc)
# verify reset text button works
r = self.client.post(url,dict(reset_text="1"))
self.assertEquals(r.status_code, 200)
q = PyQuery(r.content)
self.assertTrue(q('textarea')[0].text.startswith("Provide a description"))
def setUp(self):
make_test_data()
self.test_dir = os.path.abspath("tmp-status-change-testdir")
os.mkdir(self.test_dir)
settings.STATUS_CHANGE_PATH = self.test_dir
def tearDown(self):
shutil.rmtree(self.test_dir)

View file

@ -0,0 +1,12 @@
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns('ietf.doc.views_status_change',
url(r'^state/$', "change_state", name='status_change_change_state'),
url(r'^submit/$', "submit", name='status_change_submit'),
url(r'^notices/$', "edit_notices", name='status_change_notices'),
url(r'^ad/$', "edit_ad", name='status_change_ad'),
url(r'^approve/$', "approve", name='status_change_approve'),
url(r'^telechat/$', "telechat_date", name='status_change_telechat_date'),
url(r'^relations/$', "edit_relations", name='status_change_relations'),
)

View file

@ -25,20 +25,15 @@ from ietf.person.models import Person
from ietf.iesg.models import TelechatDate
from ietf.group.models import Role, Group
from ietf.doc.forms import TelechatForm, AdForm, NotifyForm
class ChangeStateForm(forms.Form):
review_state = forms.ModelChoiceField(State.objects.filter(type="conflrev", used=True), label="Conflict review state", empty_label=None, required=True)
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history", required=False)
def __init__(self, *args, **kwargs):
self.hide = kwargs.pop('hide', None)
super(ChangeStateForm, self).__init__(*args, **kwargs)
# hide requested fields
if self.hide:
for f in self.hide:
self.fields[f].widget = forms.HiddenInput
@role_required("Area Director", "Secretariat")
def change_state(request, name, option=None):
"""Change state of and IESG review for IETF conflicts in other stream's documents, notifying parties as necessary
"""Change state of an IESG review for IETF conflicts in other stream's documents, notifying parties as necessary
and logging the change as a comment."""
review = get_object_or_404(Document, type="conflrev", name=name)
@ -86,22 +81,22 @@ def change_state(request, name, option=None):
return redirect('doc_view', name=review.name)
else:
hide = []
s = review.get_state()
init = dict(review_state=s.pk if s else None)
form = ChangeStateForm(hide=hide, initial=init)
form = ChangeStateForm(initial=init)
return render_to_response('doc/conflict_review/change_state.html',
return render_to_response('doc/change_state.html',
dict(form=form,
doc=review,
login=login,
help_url=reverse('help_conflict_review_states'),
),
context_instance=RequestContext(request))
def send_conflict_eval_email(request,review):
msg = render_to_string("doc/conflict_review/eval_email.txt",
dict(review=review,
review_url = settings.IDTRACKER_BASE_URL+review.get_absolute_url(),
msg = render_to_string("doc/eval_email.txt",
dict(doc=review,
doc_url = settings.IDTRACKER_BASE_URL+review.get_absolute_url(),
)
)
send_mail_preformatted(request,msg)
@ -202,9 +197,6 @@ def submit(request, name):
},
context_instance=RequestContext(request))
class NotifyForm(forms.Form):
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
@role_required("Area Director", "Secretariat")
def edit_notices(request, name):
@ -231,28 +223,15 @@ def edit_notices(request, name):
init = { "notify" : review.notify }
form = NotifyForm(initial=init)
return render_to_response('doc/conflict_review/notify.html',
{'form': form,
'review': review,
'conflictdoc' : review.relateddocument_set.get(relationship__slug='conflrev').target.document,
conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document
titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev)
return render_to_response('doc/notify.html',
{'form': form,
'doc': review,
'titletext' : titletext
},
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="Shepherding 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 shepherding Area Director for this review."""
@ -277,10 +256,13 @@ def edit_ad(request, name):
init = { "ad" : review.ad_id }
form = AdForm(initial=init)
return render_to_response('doc/conflict_review/change_ad.html',
{'form': form,
'review': review,
'conflictdoc' : review.relateddocument_set.get(relationship__slug='conflrev').target.document,
conflictdoc = review.relateddocument_set.get(relationship__slug='conflrev').target.document
titletext = 'the conflict review of %s-%s' % (conflictdoc.canonical_name(),conflictdoc.rev)
return render_to_response('doc/change_ad.html',
{'form': form,
'doc': review,
'titletext': titletext
},
context_instance = RequestContext(request))
@ -318,7 +300,7 @@ def approve(request, name):
review = get_object_or_404(Document, type="conflrev", name=name)
if review.get_state('conflrev').slug not in ('appr-reqnopub-pend','appr-noprob-pend'):
return Http404()
raise Http404
login = request.user.get_profile()
@ -465,22 +447,6 @@ def start_review(request, name):
context_instance = RequestContext(request))
# There should really only be one of these living in Doc instead of it being spread between idrfc,charter, and here
class TelechatForm(forms.Form):
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False)
returning_item = forms.BooleanField(required=False)
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
dates = [d.date for d in TelechatDate.objects.active().order_by('date')]
init = kwargs['initial'].get("telechat_date")
if init and init not in dates:
dates.insert(0, init)
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, d.strftime("%Y-%m-%d")) for d in dates]
@role_required("Area Director", "Secretariat")
def telechat_date(request, name):
doc = get_object_or_404(Document, type="conflrev", name=name)
@ -501,7 +467,7 @@ def telechat_date(request, name):
else:
form = TelechatForm(initial=initial)
return render_to_response('doc/conflict_review/edit_telechat_date.html',
return render_to_response('doc/edit_telechat_date.html',
dict(doc=doc,
form=form,
user=request.user,

View file

@ -0,0 +1,596 @@
import datetime, os, re
from django import forms
from django.shortcuts import render_to_response, get_object_or_404, redirect
from django.http import HttpResponseRedirect, Http404
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.template.loader import render_to_string
from django.conf import settings
from ietf.idrfc.utils import update_telechat
from ietf.doc.utils import log_state_changed
from ietf.doc.models import save_document_in_history
from ietf.doc.utils import create_ballot_if_not_open, close_open_ballots, get_document_content
from ietf.ietfauth.decorators import has_role, role_required
from ietf.utils.textupload import get_cleaned_text_file_content
from ietf.utils.mail import send_mail_preformatted
from ietf.doc.models import State, Document, DocHistory, DocAlias
from ietf.doc.models import DocEvent, NewRevisionDocEvent, WriteupDocEvent, TelechatDocEvent, BallotDocEvent, BallotPositionDocEvent
from ietf.person.models import Person
from ietf.iesg.models import TelechatDate
from ietf.group.models import Group
from ietf.name.models import DocRelationshipName, StdLevelName
from ietf.doc.forms import TelechatForm, AdForm, NotifyForm
class ChangeStateForm(forms.Form):
new_state = forms.ModelChoiceField(State.objects.filter(type="statchg", used=True), label="Status Change Evaluation State", empty_label=None, required=True)
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the review history", required=False)
@role_required("Area Director", "Secretariat")
def change_state(request, name, option=None):
"""Change state of an status-change document, notifying parties as necessary
and logging the change as a comment."""
status_change = get_object_or_404(Document, type="statchg", name=name)
login = request.user.get_profile()
if request.method == 'POST':
form = ChangeStateForm(request.POST)
if form.is_valid():
clean = form.cleaned_data
new_state = clean['new_state']
comment = clean['comment'].rstrip()
if comment:
c = DocEvent(type="added_comment", doc=status_change, by=login)
c.desc = comment
c.save()
if new_state != status_change.get_state():
save_document_in_history(status_change)
old_description = status_change.friendly_state()
status_change.set_state(new_state)
new_description = status_change.friendly_state()
log_state_changed(request, status_change, login, new_description, old_description)
status_change.time = datetime.datetime.now()
status_change.save()
if new_state.slug == "iesgeval":
create_ballot_if_not_open(status_change, login, "statchg")
ballot = status_change.latest_event(BallotDocEvent, type="created_ballot")
if has_role(request.user, "Area Director") and not status_change.latest_event(BallotPositionDocEvent, ad=login, ballot=ballot, type="changed_ballot_position"):
# The AD putting a status change into iesgeval who doesn't already have a position is saying "yes"
pos = BallotPositionDocEvent(doc=status_change, by=login)
pos.ballot = ballot
pos.type = "changed_ballot_position"
pos.ad = login
pos.pos_id = "yes"
pos.desc = "[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name())
pos.save()
send_status_change_eval_email(request,status_change)
return redirect('doc_view', name=status_change.name)
else:
s = status_change.get_state()
init = dict(new_state=s.pk if s else None,
type='statchg',
label='Status Change Evaluation State',
)
form = ChangeStateForm(initial=init)
return render_to_response('doc/change_state.html',
dict(form=form,
doc=status_change,
login=login,
help_url=reverse('help_status_change_states')
),
context_instance=RequestContext(request))
def send_status_change_eval_email(request,doc):
msg = render_to_string("doc/eval_email.txt",
dict(doc=doc,
doc_url = settings.IDTRACKER_BASE_URL+doc.get_absolute_url(),
)
)
send_mail_preformatted(request,msg)
class UploadForm(forms.Form):
content = forms.CharField(widget=forms.Textarea, label="Status change text", help_text="Edit the status change text", required=False)
txt = forms.FileField(label=".txt format", help_text="Or upload a .txt file", required=False)
def clean_content(self):
return self.cleaned_data["content"].replace("\r", "")
def clean_txt(self):
return get_cleaned_text_file_content(self.cleaned_data["txt"])
def save(self, doc):
filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
with open(filename, 'wb') as destination:
if self.cleaned_data['txt']:
destination.write(self.cleaned_data['txt'])
else:
destination.write(self.cleaned_data['content'])
#This is very close to submit on charter - can we get better reuse?
@role_required('Area Director','Secretariat')
def submit(request, name):
doc = get_object_or_404(Document, type="statchg", name=name)
login = request.user.get_profile()
path = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
not_uploaded_yet = doc.rev == "00" and not os.path.exists(path)
if not_uploaded_yet:
# this case is special - the status change text document doesn't actually exist yet
next_rev = doc.rev
else:
next_rev = "%02d" % (int(doc.rev)+1)
if request.method == 'POST':
if "submit_response" in request.POST:
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
save_document_in_history(doc)
doc.rev = next_rev
e = NewRevisionDocEvent(doc=doc, by=login, type="new_revision")
e.desc = "New version available: <b>%s-%s.txt</b>" % (doc.canonical_name(), doc.rev)
e.rev = doc.rev
e.save()
# Save file on disk
form.save(doc)
doc.time = datetime.datetime.now()
doc.save()
return HttpResponseRedirect(reverse('doc_view', kwargs={'name': doc.name}))
elif "reset_text" in request.POST:
init = { "content": render_to_string("doc/status_change/initial_template.txt",dict())}
form = UploadForm(initial=init)
# Protect against handcrufted malicious posts
else:
form = None
else:
form = None
if not form:
init = { "content": ""}
if not_uploaded_yet:
init["content"] = render_to_string("doc/status_change/initial_template.txt",
dict(),
)
else:
filename = os.path.join(settings.STATUS_CHANGE_PATH, '%s-%s.txt' % (doc.canonical_name(), doc.rev))
try:
with open(filename, 'r') as f:
init["content"] = f.read()
except IOError:
pass
form = UploadForm(initial=init)
return render_to_response('doc/status_change/submit.html',
{'form': form,
'next_rev': next_rev,
'doc' : doc,
},
context_instance=RequestContext(request))
@role_required("Area Director", "Secretariat")
def edit_notices(request, name):
"""Change the set of email addresses document change notificaitions go to."""
status_change = get_object_or_404(Document, type="statchg", name=name)
if request.method == 'POST':
form = NotifyForm(request.POST)
if form.is_valid():
status_change.notify = form.cleaned_data['notify']
status_change.save()
login = request.user.get_profile()
c = DocEvent(type="added_comment", doc=status_change, by=login)
c.desc = "Notification list changed to : "+status_change.notify
c.save()
return HttpResponseRedirect(reverse('doc_view', kwargs={'name': status_change.name}))
else:
init = { "notify" : status_change.notify }
form = NotifyForm(initial=init)
return render_to_response('doc/notify.html',
{'form': form,
'doc': status_change,
'titletext' : '%s-%s.txt' % (status_change.canonical_name(),status_change.rev)
},
context_instance = RequestContext(request))
@role_required("Area Director", "Secretariat")
def edit_ad(request, name):
"""Change the shepherding Area Director for this status_change."""
status_change = get_object_or_404(Document, type="statchg", name=name)
if request.method == 'POST':
form = AdForm(request.POST)
if form.is_valid():
status_change.ad = form.cleaned_data['ad']
status_change.save()
login = request.user.get_profile()
c = DocEvent(type="added_comment", doc=status_change, by=login)
c.desc = "Shepherding AD changed to "+status_change.ad.name
c.save()
return redirect("doc_view", name=status_change.name)
else:
init = { "ad" : status_change.ad_id }
form = AdForm(initial=init)
titletext = '%s-%s.txt' % (status_change.canonical_name(),status_change.rev)
return render_to_response('doc/change_ad.html',
{'form': form,
'doc': status_change,
'titletext' : titletext,
},
context_instance = RequestContext(request))
def newstatus(relateddoc):
level_map = {
'tops' : 'ps',
'tois' : 'std',
'tohist' : 'hist',
'toinf' : 'inf',
'tobcp' : 'bcp',
'toexp' : 'exp',
}
return StdLevelName.objects.get(slug=level_map[relateddoc.relationship.slug])
def default_approval_text(status_change,relateddoc):
filename = "%s-%s.txt" % (status_change.canonical_name(), status_change.rev)
current_text = get_document_content(filename, os.path.join(settings.STATUS_CHANGE_PATH, filename), split=False, markup=False)
if relateddoc.target.document.std_level.slug in ('std','ps','ds','bcp',):
action = "Protocol Action"
else:
action = "Document Action"
text = render_to_string("doc/status_change/approval_text.txt",
dict(status_change=status_change,
status_change_url = settings.IDTRACKER_BASE_URL+status_change.get_absolute_url(),
relateddoc= relateddoc,
relateddoc_url = settings.IDTRACKER_BASE_URL+relateddoc.target.document.get_absolute_url(),
approved_text = current_text,
action=action,
newstatus=newstatus(relateddoc),
)
)
return text
from django.forms.formsets import formset_factory
class AnnouncementForm(forms.Form):
announcement_text = forms.CharField(widget=forms.Textarea, label="Status Change Announcement", help_text="Edit the announcement message", required=True)
label = None
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
self.label = self.initial.get('label')
@role_required("Secretariat")
def approve(request, name):
"""Approve this status change, setting the appropriate state and send the announcements to the right parties."""
status_change = get_object_or_404(Document, type="statchg", name=name)
if status_change.get_state('statchg').slug not in ('appr-pend'):
raise Http404
login = request.user.get_profile()
AnnouncementFormSet = formset_factory(AnnouncementForm,extra=0)
if request.method == 'POST':
formset = AnnouncementFormSet(request.POST)
if formset.is_valid():
save_document_in_history(status_change)
old_description = status_change.friendly_state()
status_change.set_state(State.objects.get(type='statchg', slug='appr-sent'))
new_description = status_change.friendly_state()
log_state_changed(request, status_change, login, new_description, old_description)
close_open_ballots(status_change, login)
e = DocEvent(doc=status_change, by=login)
e.type = "iesg_approved"
e.desc = "IESG has approved the status change"
e.save()
status_change.time = e.time
status_change.save()
for form in formset.forms:
send_mail_preformatted(request,form.cleaned_data['announcement_text'])
c = DocEvent(type="added_comment", doc=status_change, by=login)
c.desc = "The following approval message was sent\n"+form.cleaned_data['announcement_text']
c.save()
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
# Add a document event to each target
c = DocEvent(type="added_comment", doc=rel.target.document, by=login)
c.desc = "New status of %s approved by the IESG\n%s%s" % (newstatus(rel), settings.IDTRACKER_BASE_URL,reverse('doc_view', kwargs={'name': status_change.name}))
c.save()
return HttpResponseRedirect(status_change.get_absolute_url())
else:
init = []
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
init.append({"announcement_text" : default_approval_text(status_change,rel),
"label": "Announcement text for %s to %s"%(rel.target.document.canonical_name(),newstatus(rel)),
})
formset = AnnouncementFormSet(initial=init)
for form in formset.forms:
form.fields['announcement_text'].label=form.label
return render_to_response('doc/status_change/approve.html',
dict(
doc = status_change,
formset = formset,
),
context_instance=RequestContext(request))
RELATION_SLUGS = ('tops','tois','tohist','toinf','tobcp','toexp')
def clean_helper(form, formtype):
cleaned_data = super(formtype, form).clean()
new_relations = {}
rfc_fields = {}
status_fields={}
for k in sorted(form.data.iterkeys()):
v = form.data[k]
if k.startswith('new_relation_row'):
if re.match('\d{4}',v):
v = 'rfc'+v
rfc_fields[k[17:]]=v
elif k.startswith('statchg_relation_row'):
status_fields[k[21:]]=v
for key in rfc_fields:
if rfc_fields[key]!="":
new_relations[rfc_fields[key]]=status_fields[key]
form.relations = new_relations
errors=[]
for key in new_relations:
if not re.match('(?i)rfc\d{4}',key):
errors.append(key+" is not a valid RFC - please use the form RFCxxxx\n")
elif not DocAlias.objects.filter(name=key):
errors.append(key+" does not exist\n")
if new_relations[key] not in RELATION_SLUGS:
errors.append("Please choose a new status level for "+key+"\n")
if errors:
raise forms.ValidationError(errors)
cleaned_data['relations']=new_relations
return cleaned_data
class EditStatusChangeForm(forms.Form):
relations={}
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
self.relations = self.initial.get('relations')
def clean(self):
return clean_helper(self,EditStatusChangeForm)
class StartStatusChangeForm(forms.Form):
document_name = forms.CharField(max_length=255, label="Document name", help_text="A descriptive name such as status-change-md2-to-historic is better than status-change-rfc1319", required=True)
title = forms.CharField(max_length=255, label="Title", required=True)
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
label="Shepherding AD", empty_label="(None)", required=True)
create_in_state = forms.ModelChoiceField(State.objects.filter(type="statchg", slug__in=("needshep", "adrev")), empty_label=None, required=False)
notify = forms.CharField(max_length=255, label="Notice emails", help_text="Separate email addresses with commas", required=False)
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False, widget=forms.Select(attrs={'onchange':'make_bold()'}))
relations={}
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
# telechat choices
dates = [d.date for d in TelechatDate.objects.active().order_by('date')]
self.fields['telechat_date'].choices = [("", "(not on agenda)")] + [(d, d.strftime("%Y-%m-%d")) for d in dates]
def clean_document_name(self):
name = self.cleaned_data['document_name']
if Document.objects.filter(name='status-change-%s'%name):
raise forms.ValidationError("status-change-%s already exists"%name)
return name
def clean(self):
return clean_helper(self,StartStatusChangeForm)
#TODO - cleaned data, especially on document_name
def rfc_status_changes(request):
"""Show the rfc status changes that are under consideration, and those that are completed."""
docs=Document.objects.filter(type__slug='statchg')
doclist=[x for x in docs]
doclist.sort(key=lambda obj: obj.get_state().order)
return render_to_response('doc/status_change/status_changes.html',
{'docs' : doclist,
},
context_instance = RequestContext(request))
@role_required("Area Director","Secretariat")
def start_rfc_status_change(request):
"""Start the RFC status change review process, setting the initial shepherding AD, and possibly putting the review on a telechat."""
login = request.user.get_profile()
relation_slugs = DocRelationshipName.objects.filter(slug__in=RELATION_SLUGS)
if request.method == 'POST':
form = StartStatusChangeForm(request.POST)
if form.is_valid():
iesg_group = Group.objects.get(acronym='iesg')
status_change=Document( type_id = "statchg",
name = 'status-change-'+form.cleaned_data['document_name'],
title = form.cleaned_data['title'],
rev = "00",
ad = form.cleaned_data['ad'],
notify = form.cleaned_data['notify'],
stream_id = 'ietf',
group = iesg_group,
)
status_change.set_state(form.cleaned_data['create_in_state'])
status_change.save()
DocAlias.objects.create( name= 'status-change-'+form.cleaned_data['document_name'], document=status_change )
for key in form.cleaned_data['relations']:
status_change.relateddocument_set.create(target=DocAlias.objects.get(name=key),
relationship_id=form.cleaned_data['relations'][key])
tc_date = form.cleaned_data['telechat_date']
if tc_date:
update_telechat(request, status_change, login, tc_date)
return HttpResponseRedirect(status_change.get_absolute_url())
else:
init = {
}
form = StartStatusChangeForm(initial=init)
return render_to_response('doc/status_change/start.html',
{'form': form,
'relation_slugs': relation_slugs,
},
context_instance = RequestContext(request))
@role_required("Area Director", "Secretariat")
def telechat_date(request, name):
doc = get_object_or_404(Document, type="statchg", name=name)
login = request.user.get_profile()
e = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
initial_returning_item = bool(e and e.returning_item)
initial = dict(telechat_date=e.telechat_date if e else None,
returning_item = initial_returning_item,
)
if request.method == "POST":
form = TelechatForm(request.POST, initial=initial)
if form.is_valid():
update_telechat(request, doc, login, form.cleaned_data['telechat_date'], form.cleaned_data['returning_item'])
return redirect("doc_view", name=doc.name)
else:
form = TelechatForm(initial=initial)
return render_to_response('doc/edit_telechat_date.html',
dict(doc=doc,
form=form,
user=request.user,
login=login),
context_instance=RequestContext(request))
@role_required("Area Director", "Secretariat")
def edit_relations(request, name):
"""Change the affected set of RFCs"""
status_change = get_object_or_404(Document, type="statchg", name=name)
login = request.user.get_profile()
relation_slugs = DocRelationshipName.objects.filter(slug__in=RELATION_SLUGS)
if request.method == 'POST':
form = EditStatusChangeForm(request.POST)
if form.is_valid():
old_relations={}
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
old_relations[rel.target.document.canonical_name()]=rel.relationship.slug
new_relations=form.cleaned_data['relations']
status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS).delete()
for key in new_relations:
status_change.relateddocument_set.create(target=DocAlias.objects.get(name=key),
relationship_id=new_relations[key])
c = DocEvent(type="added_comment", doc=status_change, by=login)
c.desc = "Affected RFC list changed.\nOLD:"
for relname,relslug in (set(old_relations.items())-set(new_relations.items())):
c.desc += "\n "+relname+": "+DocRelationshipName.objects.get(slug=relslug).name
c.desc += "\nNEW:"
for relname,relslug in (set(new_relations.items())-set(old_relations.items())):
c.desc += "\n "+relname+": "+DocRelationshipName.objects.get(slug=relslug).name
#for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
# c.desc +="\n"+rel.relationship.name+": "+rel.target.document.canonical_name()
c.desc += "\n"
c.save()
return HttpResponseRedirect(status_change.get_absolute_url())
else:
relations={}
for rel in status_change.relateddocument_set.filter(relationship__slug__in=RELATION_SLUGS):
relations[rel.target.document.canonical_name()]=rel.relationship.slug
init = { "relations":relations,
}
form = EditStatusChangeForm(initial=init)
return render_to_response('doc/status_change/edit_relations.html',
{
'doc': status_change,
'form': form,
'relation_slugs': relation_slugs,
},
context_instance = RequestContext(request))

View file

@ -33,6 +33,7 @@
from django.conf.urls.defaults import patterns, url, include
from ietf.idrfc import views_doc, views_search, views_edit, views_ballot, views
from ietf.doc.models import State
from ietf.doc import views_status_change
urlpatterns = patterns('',
(r'^/?$', views_search.search_main),
@ -40,6 +41,8 @@ urlpatterns = patterns('',
(r'^all/$', views_search.all),
(r'^active/$', views_search.active),
(r'^in-last-call/$', views_search.in_last_call),
url(r'^rfc-status-changes/$', views_status_change.rfc_status_changes, name='rfc_status_changes'),
url(r'^start-rfc-status-change/$', views_status_change.start_rfc_status_change, name='start_rfc_status_change'),
url(r'^ad/(?P<name>[A-Za-z0-9.-]+)/$', views_search.by_ad, name="doc_search_by_ad"),
url(r'^(?P<name>[A-Za-z0-9._+-]+)/((?P<rev>[0-9-]+)/)?$', views_doc.document_main, name="doc_view"),
@ -81,11 +84,13 @@ urlpatterns = patterns('',
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.wgcharter.urls')),
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
)
urlpatterns += patterns('django.views.generic.simple',
url(r'^help/state/charter/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(type="charter"),'title':"Charter" } }, name='help_charter_states'),
url(r'^help/state/conflict-review/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(type="conflrev").order_by("order"),'title':"Conflict Review" } }, name='help_conflict_review_states'),
url(r'^help/state/status-change/$', 'direct_to_template', { 'template': 'doc/states.html', 'extra_context': { 'states': State.objects.filter(type="statchg").order_by("order"),'title':"RFC Status Change" } }, name='help_status_change_states'),
)

View file

@ -60,14 +60,14 @@ def render_document_top(request, doc, tab, name):
tabs.append(("Document", "document", urlreverse("ietf.idrfc.views_doc.document_main", kwargs=dict(name=name)), True))
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
if doc.type_id in ("draft","conflrev"):
if doc.type_id in ("draft","conflrev","statchg"):
# if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot:
tabs.append(("IESG Evaluation Record", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot))
elif doc.type_id == "charter":
tabs.append(("IESG Review", "ballot", urlreverse("ietf.idrfc.views_doc.document_ballot", kwargs=dict(name=name)), ballot))
# FIXME: if doc.in_ietf_process and doc.ietf_process.has_iesg_ballot:
if doc.type_id != "conflrev":
if doc.type_id not in ("conflrev","statchg"):
tabs.append(("IESG Writeups", "writeup", urlreverse("ietf.idrfc.views_doc.document_writeup", kwargs=dict(name=doc.name)), True))
tabs.append(("History", "history", urlreverse("ietf.idrfc.views_doc.document_history", kwargs=dict(name=doc.name)), True))
@ -190,6 +190,33 @@ def document_main(request, name, rev=None):
),
context_instance=RequestContext(request))
if doc.type_id == "statchg":
filename = "%s-%s.txt" % (doc.canonical_name(), doc.rev)
pathname = os.path.join(settings.STATUS_CHANGE_PATH,filename)
if doc.rev == "00" and not os.path.isfile(pathname):
# This could move to a template
content = "Status change text has not yet been proposed."
else:
content = _get_html(filename, pathname, split=False)
ballot_summary = None
if doc.get_state_slug() in ("iesgeval"):
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
return render_to_response("idrfc/document_status_change.html",
dict(doc=doc,
top=top,
content=content,
revisions=revisions,
snapshot=snapshot,
telechat=telechat,
ballot_summary=ballot_summary,
approved_states=('appr-pend','appr-sent'),
sorted_relations=doc.relateddocument_set.all().order_by('relationship__name'),
),
context_instance=RequestContext(request))
raise Http404()

View file

@ -4,12 +4,15 @@ from models import *
class NameAdmin(admin.ModelAdmin):
list_display = ["slug", "name", "desc", "used"]
prepopulate_from = { "slug": ("name",) }
class DocRelationshipNameAdmin(NameAdmin):
list_display = ["slug", "name", "revname", "desc", "used"]
admin.site.register(GroupTypeName, NameAdmin)
admin.site.register(GroupStateName, NameAdmin)
admin.site.register(RoleName, NameAdmin)
admin.site.register(StreamName, NameAdmin)
admin.site.register(DocRelationshipName, NameAdmin)
admin.site.register(DocRelationshipName, DocRelationshipNameAdmin)
admin.site.register(DocTypeName, NameAdmin)
admin.site.register(DocTagName, NameAdmin)
admin.site.register(StdLevelName, NameAdmin)

View file

@ -72,24 +72,70 @@
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Obsoleted by</field>
</object>
<object pk="updates" model="name.docrelationshipname">
<field type="CharField" name="name">Updates</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Updated by</field>
</object>
<object pk="replaces" model="name.docrelationshipname">
<field type="CharField" name="name">Replaces</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Replaced by</field>
</object>
<object pk="conflrev" model="name.docrelationshipname">
<field type="CharField" name="name">conflict reviews</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Conflict reviewed by</field>
</object>
<object pk="tops" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to Proposed Standard</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to Proposed Standard by</field>
</object>
<object pk="tois" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to Internet Standard</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to Internet Standard by</field>
</object>
<object pk="tohist" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to Historic</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to Historic by</field>
</object>
<object pk="toinf" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to Informational</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to Informational by</field>
</object>
<object pk="tobcp" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to BCP</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to BCP by</field>
</object>
<object pk="toexp" model="name.docrelationshipname">
<field type="CharField" name="name">Moves to Experimental</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field type="CharField" name="revname">Moved to Experimental by</field>
</object>
<object pk="stream-s" model="name.docremindertypename">
<field type="CharField" name="name">Stream state should change</field>
@ -134,7 +180,7 @@
<field type="IntegerField" name="order">0</field>
</object>
<object pk="app-min" model="name.doctagname">
<field type="CharField" name="name">Approved in minute</field>
<field type="CharField" name="name">Approved in minutes</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
@ -313,14 +359,14 @@
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="maturity" model="name.doctypename">
<field type="CharField" name="name">Maturity Change</field>
<object pk="conflrev" model="name.doctypename">
<field type="CharField" name="name">Conflict Review</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="conflrev" model="name.doctypename">
<field type="CharField" name="name">Conflict Review</field>
<object pk="statchg" model="name.doctypename">
<field type="CharField" name="name">Status Change</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
@ -361,6 +407,12 @@
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="abandon" model="name.groupstatename">
<field type="CharField" name="name">Abandonded</field>
<field type="TextField" name="desc">Formation of the group (most likely a BoF or Proposed WG) was abandoned</field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="ietf" model="name.grouptypename">
<field type="CharField" name="name">IETF</field>
<field type="TextField" name="desc"></field>
@ -415,6 +467,12 @@
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="rfcedtyp" model="name.grouptypename">
<field type="CharField" name="name">RFC Editor</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="ps" model="name.intendedstdlevelname">
<field type="CharField" name="name">Proposed Standard</field>
<field type="TextField" name="desc"></field>
@ -559,6 +617,12 @@
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="atlarge" model="name.rolename">
<field type="CharField" name="name">At Large Member</field>
<field type="TextField" name="desc"></field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
</object>
<object pk="schedw" model="name.sessionstatusname">
<field type="CharField" name="name">Waiting for Scheduling</field>
<field type="TextField" name="desc"></field>
@ -760,6 +824,9 @@
<object pk="conflrev" model="doc.statetype">
<field type="CharField" name="label">Conflict Review State</field>
</object>
<object pk="statchg" model="doc.statetype">
<field type="CharField" name="label">RFC Status Change</field>
</object>
<object pk="81" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">agenda</field>
<field type="SlugField" name="slug">active</field>
@ -832,95 +899,113 @@
<field type="IntegerField" name="order">0</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
</object>
<object pk="89" model="doc.state">
<object pk="90" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">needshep</field>
<field type="CharField" name="name">Needs Shepherd</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">A conflict review has been requested, but a shepherding AD has not yet been assigned</field>
<field type="IntegerField" name="order">1</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="90"></object><object pk="97"></object><object pk="98"></object></field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="91"></object><object pk="98"></object><object pk="99"></object></field>
</object>
<object pk="90" model="doc.state">
<object pk="91" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">adrev</field>
<field type="CharField" name="name">AD Review</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The sponsoring AD is reviewing the document and preparing a proposed response</field>
<field type="IntegerField" name="order">2</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="91"></object><object pk="97"></object><object pk="98"></object></field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="92"></object><object pk="98"></object><object pk="99"></object></field>
</object>
<object pk="91" model="doc.state">
<object pk="92" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">iesgeval</field>
<field type="CharField" name="name">IESG Evaluation</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG is considering the proposed conflict review response</field>
<field type="IntegerField" name="order">3</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="92"></object><object pk="93"></object><object pk="94"></object><object pk="97"></object><object pk="98"></object></field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="93"></object><object pk="94"></object><object pk="95"></object><object pk="98"></object><object pk="99"></object></field>
</object>
<object pk="92" model="doc.state">
<object pk="93" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">defer</field>
<field type="CharField" name="name">IESG Evaluation - Defer</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The evaluation of the proposed conflict review response has been deferred to the next telechat</field>
<field type="IntegerField" name="order">4</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="91"></object><object pk="93"></object><object pk="94"></object><object pk="97"></object><object pk="98"></object></field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="92"></object><object pk="94"></object><object pk="95"></object><object pk="98"></object><object pk="99"></object></field>
</object>
<object pk="93" model="doc.state">
<object pk="100" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-reqnopub-pr</field>
<field type="CharField" name="name">Approved Request to Not Publish - point raised</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the conflict review response (a request to not publish), but a point has been raised that should be cleared before moving to announcement to be sent</field>
<field type="IntegerField" name="order">5</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="94"></object></field>
</object>
<object pk="101" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-noprob-pr</field>
<field type="CharField" name="name">Approved No Problem - point raised</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the conflict review response, but a point has been raised that should be cleared before proceeding to announcement to be sent</field>
<field type="IntegerField" name="order">6</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="95"></object></field>
</object>
<object pk="94" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-reqnopub-pend</field>
<field type="CharField" name="name">Approved Request to Not Publish - announcement to be sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the conflict review response (a request to not publish), but the secretariat has not yet sent the response</field>
<field type="IntegerField" name="order">5</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="95"></object><object pk="97"></object></field>
<field type="IntegerField" name="order">7</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="96"></object><object pk="98"></object></field>
</object>
<object pk="94" model="doc.state">
<object pk="95" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-noprob-pend</field>
<field type="CharField" name="name">Approved No Problem - announcement to be sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the conflict review response, but the secretariat has not yet sent the response</field>
<field type="IntegerField" name="order">6</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="96"></object><object pk="97"></object></field>
<field type="IntegerField" name="order">8</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="97"></object><object pk="98"></object></field>
</object>
<object pk="95" model="doc.state">
<object pk="96" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-reqnopub-sent</field>
<field type="CharField" name="name">Approved Request to Not Publish - announcement sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The secretariat has delivered the IESG's approved conflict review response (a request to not publish) to the requester</field>
<field type="IntegerField" name="order">7</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
<field type="IntegerField" name="order">9</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="96"></object></field>
</object>
<object pk="96" model="doc.state">
<object pk="97" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">appr-noprob-sent</field>
<field type="CharField" name="name">Approved No Problem - announcement sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The secretariat has delivered the IESG's approved conflict review response to the requester</field>
<field type="IntegerField" name="order">8</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
<field type="IntegerField" name="order">10</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="97"></object></field>
</object>
<object pk="97" model="doc.state">
<object pk="98" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">withdraw</field>
<field type="CharField" name="name">Withdrawn</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The request for conflict review was withdrawn</field>
<field type="IntegerField" name="order">9</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="89"></object></field>
<field type="IntegerField" name="order">11</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="90"></object></field>
</object>
<object pk="98" model="doc.state">
<object pk="99" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">dead</field>
<field type="CharField" name="name">Dead</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The conflict review has been abandoned</field>
<field type="IntegerField" name="order">10</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="89"></object></field>
<field type="IntegerField" name="order">12</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="90"></object></field>
</object>
<object pk="1" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft</field>
@ -1363,6 +1448,15 @@
<field type="IntegerField" name="order">0</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
</object>
<object pk="89" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-rfceditor</field>
<field type="SlugField" name="slug">auth48done</field>
<field type="CharField" name="name">AUTH48-DONE</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">Final approvals are complete</field>
<field type="IntegerField" name="order">0</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="74"></object></field>
</object>
<object pk="45" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-stream-iab</field>
<field type="SlugField" name="slug">candidat</field>
@ -1843,6 +1937,87 @@
<field type="IntegerField" name="order">2</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
</object>
<object pk="102" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">needshep</field>
<field type="CharField" name="name">Needs Shepherd</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">An RFC status change has been requested, but a shepherding AD has not yet been assigned</field>
<field type="IntegerField" name="order">1</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="103"></object><object pk="109"></object><object pk="110"></object></field>
</object>
<object pk="103" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">adrev</field>
<field type="CharField" name="name">AD Review</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The sponsoring AD is preparing an RFC status change document</field>
<field type="IntegerField" name="order">2</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="104"></object><object pk="109"></object><object pk="110"></object></field>
</object>
<object pk="104" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">iesgeval</field>
<field type="CharField" name="name">IESG Evaluation</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG is considering the proposed RFC status changes</field>
<field type="IntegerField" name="order">3</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="105"></object><object pk="106"></object><object pk="107"></object><object pk="109"></object><object pk="110"></object></field>
</object>
<object pk="105" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">defer</field>
<field type="CharField" name="name">IESG Evaluation - Defer</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The evaluation of the proposed RFC status changes have been deferred to the next telechat</field>
<field type="IntegerField" name="order">4</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="104"></object><object pk="106"></object><object pk="107"></object><object pk="109"></object><object pk="110"></object></field>
</object>
<object pk="106" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">appr-pr</field>
<field type="CharField" name="name">Approved - point raised</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the RFC status changes, but a point has been raised that should be cleared before proceeding to announcement to be sent</field>
<field type="IntegerField" name="order">5</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
</object>
<object pk="107" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">appr-pend</field>
<field type="CharField" name="name">Approved - announcement to be sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The IESG has approved the RFC status changes, but the secretariat has not yet sent the announcement</field>
<field type="IntegerField" name="order">6</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="108"></object><object pk="109"></object></field>
</object>
<object pk="108" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">appr-sent</field>
<field type="CharField" name="name">Approved - announcement sent</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The secretariat has announced the IESG's approved RFC status changes</field>
<field type="IntegerField" name="order">7</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"></field>
</object>
<object pk="109" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">withdraw</field>
<field type="CharField" name="name">Withdrawn</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The request for RFC status changes was withdrawn</field>
<field type="IntegerField" name="order">8</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="102"></object></field>
</object>
<object pk="110" model="doc.state">
<field to="doc.statetype" name="type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">dead</field>
<field type="CharField" name="name">Dead</field>
<field type="BooleanField" name="used">True</field>
<field type="TextField" name="desc">The RFC status changes have been abandoned</field>
<field type="IntegerField" name="order">9</field>
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="102"></object></field>
</object>
<object pk="5" model="doc.ballottype">
<field to="name.doctypename" name="doc_type" rel="ManyToOneRel">conflrev</field>
<field type="SlugField" name="slug">conflrev</field>
@ -1852,6 +2027,15 @@
<field type="IntegerField" name="order">0</field>
<field to="name.ballotpositionname" name="positions" rel="ManyToManyRel"><object pk="yes"></object><object pk="noobj"></object><object pk="discuss"></object><object pk="abstain"></object><object pk="recuse"></object><object pk="norecord"></object></field>
</object>
<object pk="6" model="doc.ballottype">
<field to="name.doctypename" name="doc_type" rel="ManyToOneRel">statchg</field>
<field type="SlugField" name="slug">statchg</field>
<field type="CharField" name="name">Approve</field>
<field type="TextField" name="question">Do we approve these RFC status changes?</field>
<field type="BooleanField" name="used">True</field>
<field type="IntegerField" name="order">0</field>
<field to="name.ballotpositionname" name="positions" rel="ManyToManyRel"><object pk="yes"></object><object pk="noobj"></object><object pk="discuss"></object><object pk="abstain"></object><object pk="recuse"></object><object pk="norecord"></object></field>
</object>
<object pk="1" model="doc.ballottype">
<field to="name.doctypename" name="doc_type" rel="ManyToOneRel">charter</field>
<field type="SlugField" name="slug">r-extrev</field>

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
from ietf.name.models import DocTypeName, DocRelationshipName
class Migration(DataMigration):
def forwards(self, orm):
DocTypeName(slug='statchg',name='Status Change',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

@ -0,0 +1,161 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'DocRelationshipName.revname'
db.add_column('name_docrelationshipname', 'revname', self.gf('django.db.models.fields.CharField')(default='fixme', max_length=255), keep_default=False)
def backwards(self, orm):
# Deleting field 'DocRelationshipName.revname'
db.delete_column('name_docrelationshipname', 'revname')
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'}),
'revname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'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

@ -0,0 +1,177 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
from ietf.name.models import DocRelationshipName
class Migration(DataMigration):
def update_reverse_name(self,slug,revname):
relation = DocRelationshipName.objects.get(slug=slug)
relation.revname = revname
relation.save()
def forwards(self, orm):
revnames = { 'obs' : 'Obsoleted by',
'updates' : 'Updated by',
'replaces': 'Replaced by',
'conflrev': 'Conflict reviewed by',
}
for key in revnames:
self.update_reverse_name(key,revnames[key])
DocRelationshipName(slug='tops', name='Moves to Proposed Standard', revname='Moved to Proposed Standard by', used=True).save()
DocRelationshipName(slug='tois', name='Moves to Internet Standard', revname='Moved to Internet Standard by', used=True).save()
DocRelationshipName(slug='tohist', name='Moves to Historic', revname='Moved to Historic by', used=True).save()
DocRelationshipName(slug='toinf', name='Moves to Informational', revname='Moved to Informational by', used=True).save()
DocRelationshipName(slug='tobcp', name='Moves to BCP', revname='Moved to BCP by', used=True).save()
DocRelationshipName(slug='toexp', name='Moves to Experimental', revname='Moved to Experimental by', 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'}),
'revname': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'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

@ -24,9 +24,12 @@ class RoleName(NameModel):
"""AD, Chair"""
class StreamName(NameModel):
"""IETF, IAB, IRTF, ISE, Legacy"""
class DocRelationshipName(NameModel):
"""Updates, Replaces, Obsoletes, Reviews, ... The relationship is
always recorded in one direction."""
revname = models.CharField(max_length=255)
class DocTypeName(NameModel):
"""Draft, Agenda, Minutes, Charter, Discuss, Guideline, Email,
Review, Issue, Wiki"""

View file

@ -206,6 +206,8 @@ CHARTER_PATH = '/a/www/ietf-ftp/charters/'
CHARTER_TXT_URL = 'http://www.ietf.org/charter/'
CONFLICT_REVIEW_PATH = '/a/www/ietf-ftp/conflict-reviews'
CONFLICT_REVIEW_TXT_URL = 'http://www.ietf.org/cr/'
STATUS_CHANGE_PATH = '/a/www/ietf-ftp/status-changes'
STATUS_CHANGE_TXT_URL = 'http://www.ietf.org/sc/'
AGENDA_PATH = '/a/www/www6s/proceedings/'
AGENDA_PATH_PATTERN = '/a/www/www6s/proceedings/%(meeting)s/agenda/%(wg)s.%(ext)s'
MINUTES_PATH_PATTERN = '/a/www/www6s/proceedings/%(meeting)s/minutes/%(wg)s.%(ext)s'

View file

@ -102,6 +102,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
{% else %}
<li><a href="http://{{ request.get_host }}/accounts/login/?next={{request.get_full_path|urlencode}}" rel="nofollow">Sign in to track drafts</a></li>
{% endif %}
{% if user|in_group:"Area_Director,Secretariat" %}
<li><a href="{% url rfc_status_changes %}">RFC status changes</a></li>
{% endif %}
<li class="sect">Meetings</li>

View file

@ -8,11 +8,11 @@
{% endblock %}
{% block title %}
Change the shepherding AD for the conflict review of {{ conflictdoc.canonical_name }}-{{ conflictdoc.rev }}
Change the shepherding AD for {{titletext}}
{% endblock %}
{% block content %}
<h1>Change the shepherding AD for the conflict review of {{ conflictdoc.canonical_name }}-{{ conflictdoc.rev }}</h1>
<h1>Change the shepherding AD for {{titletext}}</h1>
<form class="edit-info" action="" enctype="multipart/form-data" method="POST">
<table>
@ -29,7 +29,7 @@ Change the shepherding AD for the conflict review of {{ conflictdoc.canonical_na
<tr>
<td></td>
<td class="actions">
<a href="{% url doc_view name=review.canonical_name %}">Back</a>
<a href="{% url doc_view name=doc.canonical_name %}">Back</a>
<input type="submit" value="Submit"/>
</td>
</tr>

View file

@ -20,7 +20,7 @@ form.change-state .actions {
{% block content %}
<h1>Change State: {{doc.title}}</h1>
<p class="helptext">For help on the states, see the <a href="{% url help_conflict_review_states %}">state table</a>.</p>
<p class="helptext">For help on the states, see the <a href="{{help_url}}">state table</a>.</p>
<form class="change-state" action="" method="post">
<table>

View file

@ -1,8 +1,8 @@
{% load mail_filters %}{% autoescape off %}To: Internet Engineering Steering Group <iesg@ietf.org>
From: IESG Secretary <iesg-secretary@ietf.org>
Reply-To: IESG Secretary <iesg-secretary@ietf.org>
Subject: Evaluation: {{review.title}}
Subject: Evaluation: {{doc.title}}
Evaluation for {{ review.title }} can be found at <{{ review_url }}>
Evaluation for {{ doc.title }} can be found at <{{ doc_url }}>
{% endautoescape%}

View file

@ -11,11 +11,11 @@ form.edit-info #id_notify {
{% endblock %}
{% block title %}
Edit notification addresses for the conflict review of {{ conflictdoc.canonical_name }}-{{ conflictdoc.rev }}
Edit notification addresses for {{titletext}}
{% endblock %}
{% block content %}
<h1>Edit notification addresses for the conflict review of {{ conflictdoc.canonical_name }}-{{ conflictdoc.rev }}</h1>
<h1>Edit notification addresses for {{titletext}}</h1>
<form class="edit-info" action="" enctype="multipart/form-data" method="POST">
<table>
@ -32,7 +32,7 @@ Edit notification addresses for the conflict review of {{ conflictdoc.canonical_
<tr>
<td></td>
<td class="actions">
<a href="{% url doc_view name=review.canonical_name %}">Back</a>
<a href="{% url doc_view name=doc.canonical_name %}">Back</a>
<input type="submit" value="Submit"/>
</td>
</tr>

View file

@ -0,0 +1,25 @@
{% load mail_filters %}{% autoescape off %}From: The IESG <iesg-secretary@ietf.org>
To: IETF-Announce <ietf-announce@ietf.org>
Cc: RFC Editor <rfc-editor@rfc-editor.org>, {{status_change.notify}}
Subject: {{action}}: {{relateddoc.target.document.title}} to {{newstatus}}
{% filter wordwrap:73 %}The IESG has approved changing the status of the following document:
- {{relateddoc.target.document.title }}
({{relateddoc.target.document.canonical_name }}) to {{ newstatus }}
This {{action|lower}} is documented at:
{{status_change_url}}
A URL of the affected document is:
{{relateddoc_url}}
Status Change Details:
{{ approved_text }}
Personnel
{{status_change.ad.plain_name}} is the responsible Area Director.
{% endfilter %}
{% endautoescape %}

View file

@ -0,0 +1,41 @@
{% extends "base.html" %}
{% block title %}Approve {{doc.canonical_name }}{% endblock %}
{% block morecss %}
textarea[id^="id_form-"][id$="-announcement_text"] {
overflow-x: auto;
overflow-y: scroll;
width: 800px;
height: 400px;
border: 1px solid #bbb;
}
{% endblock %}
{% block content %}
<h1>Approve {{ doc.canonical_name }}</h1>
<form class="approve" action="" method="POST">
{{formset.management_form}}
<table>
{% for form in formset.forms %}
{% for field in form.visible_fields %}
<tr>
<td>
<div>{{ field.label_tag }}:</div>
{{ field }}
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
{{ field.errors }}
</td>
</tr>
{% endfor %}
{% endfor %}
<tr>
<td class="actions">
<a href="{% url doc_view name=doc.name %}">Back</a>
<input type="submit" value="Send out the announcement and close the ballot"/>
</td>
</tr>
</table>
</form>
{% endblock %}

View file

@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}Edit List of RFCs Affected By Status Change{% endblock %}
{% block morecss %}
form.start-rfc-status-change-review #id_notify {
width: 600px;
}
form.start-rfc-status-change-review #id_document_name {
width: 510px;
}
form.start-rfc-status-change-review .actions {
padding-top: 20px;
}
.warning {
font-weight: bold;
color: #a00;
}
{% endblock %}
{% block pagehead %}
{% include "doc/status_change/status-change-edit-relations-js.html" %}
{% endblock %}
{% block content %}
<h1>Edit List of RFCs Affected By Status Change</h1>
<form class="edit-status-change-rfcs" action="" method="post">
<table>
<th>Affects RFCs:</th>
<td><table><tbody id="relations_table">
{% for rfc,choice_slug in form.relations.items %}
<tr id="relation_row_{{rfc}}">
<td>
<input id="new_relation_row_{{rfc}}" name="new_relation_row_{{rfc}}"
type="text" maxlength="7"
value="{{rfc}}"
onchange="update_relation_row('relation_row_{{rfc}}')"/>
</td>
<td>
<select id="statchg_relation_row_{{rfc}}" name="statchg_relation_row_{{rfc}}"
style="vertical-align: top;">
<option value="" {% if choice_slug == "" %}selected="selected"{% endif %}>(None)</option>
{% for rel in relation_slugs %}
<option value="{{rel.slug}}" {% if choice_slug == rel.slug %}selected="selected"{%endif%}>{{rel.name}}</option>
{% endfor %}
</select>
<img src="/images/close.png" onclick="delete_relation('relation_row_{{rfc}}');"
style="cursor: pointer; padding-left: 4px;"/>
</td>
{% endfor %}
<tr id="relation_row_0">
<td>
<input id="new_relation_row_0" name="new_relation_row_0"
type="text" maxlength="7"
onkeypress="buff_out_row('relation_row_0');"
onchange="update_relation_row('relation_row_0')"/>
</td>
</tr>
</tbody></table>
<div class="help">Enter one of the affected RFC as RFCXXXX</div>
{{ form.non_field_errors }}
</td>
</tr>
<tr>
<td colspan="2" class="actions">
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form>
{% endblock %}

View file

@ -0,0 +1,17 @@
Provide a description of what RFCs status are changed and any necessary rational for the change.
This is a good place to document how the RFC6410 criteria for advancing to Internet Standard are met:
(1) There are at least two independent interoperating implementations
with widespread deployment and successful operational experience.
(2) There are no errata against the specification that would cause a
new implementation to fail to interoperate with deployed ones.
(3) There are no unused features in the specification that greatly
increase implementation complexity.
(4) If the technology required to implement the specification
requires patented or otherwise controlled technology, then the
set of implementations must demonstrate at least two independent,
separate and successful uses of the licensing process.

View file

@ -0,0 +1,89 @@
{% extends "base.html" %}
{% block title %}Begin RFC status change review {% endblock %}
{% block morecss %}
form.start-rfc-status-change-review #id_notify {
width: 600px;
}
form.start-rfc-status-change-review #id_document_name {
width: 510px;
}
form.start-rfc-status-change-review .actions {
padding-top: 20px;
}
.warning {
font-weight: bold;
color: #a00;
}
{% endblock %}
{% block pagehead %}
{% include "doc/status_change/status-change-edit-relations-js.html" %}
{% endblock %}
{% block content %}
<h1>Begin RFC status change review</h1>
<p class="helptext">For help on the initial state choice, see the <a href="{% url help_status_change_states %}">state table</a>.</p>
<form class="start-rfc-status-change-review" action="" method="post">
<table>
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}:</th>
<td>
{% if field.label == "Document name" %}status-change-{% endif %}
{{ field }}
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
{{ field.errors }}
</td>
</tr>
{% if field.label == "Document name" %}
<tr>
<th>Affects RFCs:</th>
<td><table><tbody id="relations_table">
{% for rfc,choice_slug in form.relations.items %}
<tr id="relation_row_{{rfc}}">
<td>
<input id="new_relation_row_{{rfc}}" name="new_relation_row_{{rfc}}"
type="text" maxlength="7"
value="{{rfc}}"
onchange="update_relation_row('relation_row_{{rfc}}')"/>
</td>
<td>
<select id="statchg_relation_row_{{rfc}}" name="statchg_relation_row_{{rfc}}"
style="vertical-align: top;">
<option value="" {% if choice_slug == "" %}selected="selected"{% endif %}>(None)</option>
{% for rel in relation_slugs %}
<option value="{{rel.slug}}" {% if choice_slug == rel.slug %}selected="selected"{%endif%}>{{rel.name}}</option>
{% endfor %}
</select>
<img src="/images/close.png" onclick="delete_relation('relation_row_{{rfc}}');"
style="cursor: pointer; padding-left: 4px;"/>
</td>
{% endfor %}
<tr id="relation_row_0">
<td>
<input id="new_relation_row_0" name="new_relation_row_0"
type="text" maxlength="7"
onkeypress="buff_out_row('relation_row_0');"
onchange="update_relation_row('relation_row_0')"/>
</td>
</tr>
</tbody></table>
<div class="help">Enter one of the affected RFC as RFCXXXX</div>
{{ form.non_field_errors }}
</td>
</tr>
{% endif %}
{% endfor %}
<tr>
<td colspan="2" class="actions">
<input type="submit" value="Submit"/>
</td>
</tr>
</table>
</form>
{% endblock %}

View file

@ -0,0 +1,78 @@
<script type="text/javascript">
function buff_out_row(id)
{
setTimeout(function() {
var input = document.getElementById("new_"+id);
if (input.value!="")
{
input.removeAttribute("onkeypress");
buff_out_row_guts(id);
}
}, 0);
}
function buff_out_row_guts(id)
{
var buff_row = document.getElementById(id);
var td = document.createElement("td");
statchg = document.createElement("select");
statchg.name = "statchg_"+id;
statchg.id = "statchg_"+id;
option_empty = document.createElement("option");
option_empty.setAttribute("value","");
option_empty.setAttribute("selected","selected");
option_empty.innerHTML="(None)";
statchg.appendChild(option_empty);
{% for rel in relation_slugs %}
option_{{rel.slug}} = document.createElement("option");
option_{{rel.slug}}.setAttribute("value","{{rel.slug}}");
option_{{rel.slug}}.innerHTML="{{rel.name}}";
statchg.appendChild(option_{{rel.slug}});
{% endfor %}
statchg.style.verticalAlign="top";
td.appendChild(statchg);
xbutton = document.createElement("img");
xbutton.src="/images/close.png";
xbutton.setAttribute("onclick","delete_relation('"+id+"');");
xbutton.style.cursor="pointer";
xbutton.style.paddingLeft="4px";
td.appendChild(xbutton);
buff_row.appendChild(td);
var tr = document.createElement("tr");
var date = new Date;
var id = "relation_row_"+date.getTime();
tr.id = id;
var td2 = document.createElement("td");
var input= document.createElement("input");
input.type="text";
input.id="new_"+id;
input.name="new_"+id;
input.setAttribute("maxlength","7");
input.setAttribute("onchange","update_relation_row('"+id+"');");
input.setAttribute("onkeypress","buff_out_row('"+id+"');");
td2.appendChild(input);
tr.appendChild(td2);
buff_row.parentNode.appendChild(tr);
}
function update_relation_row(id)
{
/*
This hook exists to eventually do an asynch lookup to get the title of the RFC and display it
var update_row = document.getElementById(id);
var td = document.createElement("td");
td.innerHTML="TODO: fetch title of RFC and show it here";
update_row.appendChild(td);
*/
}
function delete_relation(id)
{
var leaving_row = document.getElementById(id);
leaving_row.parentNode.removeChild(leaving_row);
}
</script>

View file

@ -0,0 +1,23 @@
{% extends "base.html" %}
{% load ietf_filters %}
{% block title %}RFC Status Changes{% endblock %}
{% block content %}
<h1>RFC Status Changes</h1>
{% if user|in_group:"Area_Director,Secretariat" %}
<p><a href="{% url start_rfc_status_change %}">Start new RFC status change document</a></p>
{% endif %}
{% regroup docs by get_state as state_groups %}
<table class="ietf-table ietf-doctable">
<tr><th class="doc">Document</th><th class="title">Title</th></tr>
{% for state in state_groups %}
<tr class="header"><td colspan="2">{{state.grouper}}</td></tr>
{% for doc in state.list %}
<tr class="{{ forloop.counter|divisibleby:2|yesno:"oddrow,evenrow" }}">
<td>{{ doc.displayname_with_link|safe }}</td>
<td>{{ doc.title }}</td>
</tr>
{% endfor %}
{% endfor %}
{% endblock content %}

View file

@ -0,0 +1,41 @@
{% extends "base.html" %}
{% block morecss %}
form #id_content {
width: 40em;
height: 450px;
}
{% endblock %}
{% block title %}
Edit status change text for {{doc.title}}
{% endblock %}
{% block content %}
<h1>Edit status change text for {{doc.title}}</h1>
<p>The text will be submitted as <strong>{{ doc.canonical_name }}-{{ next_rev }}</strong></p>
<form class="edit-info" action="" enctype="multipart/form-data" method="POST">
<table>
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}:</th>
<td>
{{ field }}
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
{{ field.errors }}
</td>
</tr>
{% endfor %}
<tr>
<td></td>
<td class="actions">
<a href="{% url doc_view name=doc.canonical_name %}">Back</a>
<input type="submit" name="reset_text" value="Reset to Template Text"/>
<input type="submit" name="submit_response" value="Submit"/>
</td>
</tr>
</table>
</form>
{% endblock %}

View file

@ -42,25 +42,26 @@
{% endif %}
</div>
{% if not snapshot %}
<div class="telechat">
</td>
</tr>
{% if not snapshot %}
<tr>
<td>Telechat Date:</td>
<td>
<a {% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug not in approved_states %}
class="editlink" href="{% url conflict_review_telechat_date name=doc.name %}"
{%endif%} >
{% if not telechat %}Not on agenda of an IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% if doc.returning_item %} (returning item){% endif %}{% endif %}
</a>
</div>
{% if ballot_summary %}
<div class="ballot-summary">
({{ ballot_summary }})
</div>
{% endif %}
{% endif %}
</td>
</tr>
{% endif %}
<tr>
<td>Shepherding AD:</td>

View file

@ -0,0 +1,135 @@
{% extends "idrfc/doc_main.html" %}
{% load ietf_filters %}
{% block title %}{{ doc.canonical_name }}-{{ doc.rev }}{% endblock %}
{% block pagehead %}
<link rel="stylesheet" type="text/css" href="/css/doc.css"></link>
{% endblock %}
{% block content %}
{{ top|safe }}
<div class="snapshots">
Versions:
<span class="revisions">
{% for rev in revisions %}
<a {% if rev != doc.rev %}href="{% url doc_view name=doc.name %}{% if not forloop.last %}{{ rev }}/{% endif %}"{% endif %}>{{ rev }}</a>
{% endfor %}
</span>
</div>
<div class="ietf-box metabox">
<div>
{% if snapshot %}Snapshot of{% endif %}
{% if doc.get_state_slug not in approved_states %}Proposed{% endif %}
Status change : {{ doc.title }} </a>
</div>
<table id="metatable" width="100%">
{% regroup sorted_relations by relationship.name as relation_groups %}
{% for relation_group in relation_groups %}
<tr>
<td>{{relation_group.grouper}}:</td>
<td>{% for rel in relation_group.list %}{{rel.target.document.canonical_name|upper|urlize_ietf_docs}}{% if not forloop.last %}, {% endif %}{% endfor %}</td>
</tr>
{% endfor %}
<tr>
<td><a href="/doc/help/state/status-change/">Review State</a>:</td>
<td>
<div>
<a title="{{ doc.get_state.desc }}"{% if not snapshot and user|has_role:"Area Director,Secretariat" %} class="editlink" href="{% url status_change_change_state name=doc.name %}"{% endif %}>{{ doc.get_state.name }}</a>
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
{% if request.user|has_role:"Secretariat" %}{% if doc.get_state_slug = 'appr-pend' %}
- <a href="{% url status_change_approve name=doc.name %}">Approve RFC status changes</a>
{% endif %}{% endif %}
{% endif %}
</div>
</td>
</tr>
<tr>
<td>Telechat Date:</td>
<td>
{% if not snapshot %}
<a {% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug not in approved_states %}
class="editlink" href="{% url status_change_telechat_date name=doc.name %}"
{%endif%} >
{% if not telechat %}Not on agenda of an IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% if doc.returning_item %} (returning item){% endif %}{% endif %}
</a>
{% if ballot_summary %}
<div class="ballot-summary">
({{ ballot_summary }})
</div>
{% endif %}
{% endif %}
</td>
</tr>
<tr>
<td>Shepherding AD:</td>
<td>
<a {% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug not in approved_states %}
class="editlink" href="{% url status_change_ad name=doc.name %}"
{% endif %}
>
{{doc.ad}}
</a>
</td>
</tr>
<tr>
<td>Send notices to:</td>
<td>
<a {% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug not in approved_states %}
class="editlink" href="{% url status_change_notices name=doc.name %}"
{% endif %}
>
{{doc.notify}}
</a>
</td>
</tr>
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
<tr><td>Last updated:</td><td> {{ doc.time|date:"Y-m-d" }}</td></tr>
{% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug not in approved_states %}
<tr><td colspan="2">
<span id="doc_request_resurrect_button" class="yui-button yui-link-button" style="margin-left:2px;">
<span class="first-child">
<a href="{% url status_change_relations name=doc.name %}">Edit Affected RFC List</a>
</span>
</span>
</td><tr/>
{% endif %}
{% comment %}
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
{% endcomment %}
</table>
</div>
<h3>RFC Status Change : {{ doc.title }}
{% if not snapshot and user|has_role:"Area Director,Secretariat" and doc.get_state_slug != 'apprsent' %}
<a class="edit" href="{% url status_change_submit name=doc.name %}">Change status change text</a>
{% endif %}
</h3>
{% if doc.rev %}
<div class="markup_draft">
{{ content|fill:"80"|safe|linebreaksbr|keep_spacing|sanitize_html|safe }}
</div>
{% endif %}
{% endblock %}

View file

@ -126,7 +126,7 @@ th {
<tr>
<th>{{person_form.ascii_short.label}}:</th>
<td></td>
<td colspan='2'>{{person_form.ascii_short}} - Short form, if any, of your name as renedered in ASCII (blank is okay)</td>
<td colspan='2'>{{person_form.ascii_short}} - Short form, if any, of your name as rendered in ASCII (blank is okay)</td>
</tr>
<tr>
<th>{{person_form.affiliation.label}}:</th>

View file

@ -400,4 +400,22 @@ def make_test_data():
crdoc.save()
crdoc.relateddocument_set.create(target=docalias,relationship_id='conflrev')
# A status change mid review
doc = Document.objects.create(name='status-change-imaginary-mid-review',type_id='statchg', rev='00', notify="fsm@ietf.org")
doc.set_state(State.objects.get(slug='needshep',type__slug='statchg'))
doc.save()
docalias = DocAlias.objects.create(name='status-change-imaginary-mid-review',document=doc)
# Some things for a status change to affect
target_rfc = Document.objects.create(name='draft-ietf-random-thing', type_id='draft', std_level_id='ps')
target_rfc.set_state(State.objects.get(slug='rfc',type__slug='draft'))
target_rfc.save()
docalias = DocAlias.objects.create(name='draft-ietf-random-thing',document=target_rfc)
docalias = DocAlias.objects.create(name='rfc9999',document=target_rfc)
target_rfc = Document.objects.create(name='draft-ietf-random-otherthing', type_id='draft', std_level_id='inf')
target_rfc.set_state(State.objects.get(slug='rfc',type__slug='draft'))
target_rfc.save()
docalias = DocAlias.objects.create(name='draft-ietf-random-otherthing',document=target_rfc)
docalias = DocAlias.objects.create(name='rfc9998',document=target_rfc)
return draft