Finish ballot support for charters (apart from non-generic ballot
deferral), remove a bunch of now obsolete charter code. - Legacy-Id: 4255
This commit is contained in:
parent
a9817e555a
commit
e4a9d8c7aa
|
@ -104,14 +104,15 @@ class DocHistoryAdmin(admin.ModelAdmin):
|
|||
admin.site.register(DocHistory, DocHistoryAdmin)
|
||||
|
||||
class DocAliasAdmin(admin.ModelAdmin):
|
||||
list_display = [ 'name', 'document_link', ]
|
||||
search_fields = [ 'name', 'document__name', ]
|
||||
list_display = ['name', 'document_link']
|
||||
search_fields = ['name', 'document__name']
|
||||
raw_id_fields = ['document']
|
||||
document_link = admin_link("document")
|
||||
admin.site.register(DocAlias, DocAliasAdmin)
|
||||
|
||||
|
||||
admin.site.register(BallotType)
|
||||
class BallotTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ["slug", "doc_type", "name", "question"]
|
||||
admin.site.register(BallotType, BallotTypeAdmin)
|
||||
|
||||
# events
|
||||
|
||||
|
|
690
ietf/doc/migrations/0001_initial.py
Normal file
690
ietf/doc/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,690 @@
|
|||
# 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 model 'StateType'
|
||||
db.create_table('doc_statetype', (
|
||||
('slug', self.gf('django.db.models.fields.CharField')(max_length=30, primary_key=True)),
|
||||
('label', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
))
|
||||
db.send_create_signal('doc', ['StateType'])
|
||||
|
||||
# Adding model 'State'
|
||||
db.create_table('doc_state', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.StateType'])),
|
||||
('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('used', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('desc', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('doc', ['State'])
|
||||
|
||||
# Adding M2M table for field next_states on 'State'
|
||||
db.create_table('doc_state_next_states', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('from_state', models.ForeignKey(orm['doc.state'], null=False)),
|
||||
('to_state', models.ForeignKey(orm['doc.state'], null=False))
|
||||
))
|
||||
db.create_unique('doc_state_next_states', ['from_state_id', 'to_state_id'])
|
||||
|
||||
# Adding model 'RelatedDocument'
|
||||
db.create_table('doc_relateddocument', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('source', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.Document'])),
|
||||
('target', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.DocAlias'])),
|
||||
('relationship', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocRelationshipName'])),
|
||||
))
|
||||
db.send_create_signal('doc', ['RelatedDocument'])
|
||||
|
||||
# Adding model 'DocumentAuthor'
|
||||
db.create_table('doc_documentauthor', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.Document'])),
|
||||
('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Email'])),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')(default=1)),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocumentAuthor'])
|
||||
|
||||
# Adding model 'Document'
|
||||
db.create_table('doc_document', (
|
||||
('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocTypeName'], null=True, blank=True)),
|
||||
('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('stream', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.StreamName'], null=True, blank=True)),
|
||||
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'], null=True, blank=True)),
|
||||
('abstract', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('rev', self.gf('django.db.models.fields.CharField')(max_length=16, blank=True)),
|
||||
('pages', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')(default=1, blank=True)),
|
||||
('intended_std_level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.IntendedStdLevelName'], null=True, blank=True)),
|
||||
('std_level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.StdLevelName'], null=True, blank=True)),
|
||||
('ad', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='ad_document_set', null=True, to=orm['person.Person'])),
|
||||
('shepherd', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='shepherd_document_set', null=True, to=orm['person.Person'])),
|
||||
('expires', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
('notify', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
|
||||
('external_url', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True)),
|
||||
('note', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('internal_comments', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255, primary_key=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['Document'])
|
||||
|
||||
# Adding M2M table for field states on 'Document'
|
||||
db.create_table('doc_document_states', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('document', models.ForeignKey(orm['doc.document'], null=False)),
|
||||
('state', models.ForeignKey(orm['doc.state'], null=False))
|
||||
))
|
||||
db.create_unique('doc_document_states', ['document_id', 'state_id'])
|
||||
|
||||
# Adding M2M table for field tags on 'Document'
|
||||
db.create_table('doc_document_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('document', models.ForeignKey(orm['doc.document'], null=False)),
|
||||
('doctagname', models.ForeignKey(orm['name.doctagname'], null=False))
|
||||
))
|
||||
db.create_unique('doc_document_tags', ['document_id', 'doctagname_id'])
|
||||
|
||||
# Adding model 'RelatedDocHistory'
|
||||
db.create_table('doc_relateddochistory', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('source', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.DocHistory'])),
|
||||
('target', self.gf('django.db.models.fields.related.ForeignKey')(related_name='reversely_related_document_history_set', to=orm['doc.DocAlias'])),
|
||||
('relationship', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocRelationshipName'])),
|
||||
))
|
||||
db.send_create_signal('doc', ['RelatedDocHistory'])
|
||||
|
||||
# Adding model 'DocHistoryAuthor'
|
||||
db.create_table('doc_dochistoryauthor', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.DocHistory'])),
|
||||
('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Email'])),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')()),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocHistoryAuthor'])
|
||||
|
||||
# Adding model 'DocHistory'
|
||||
db.create_table('doc_dochistory', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocTypeName'], null=True, blank=True)),
|
||||
('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('stream', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.StreamName'], null=True, blank=True)),
|
||||
('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group.Group'], null=True, blank=True)),
|
||||
('abstract', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('rev', self.gf('django.db.models.fields.CharField')(max_length=16, blank=True)),
|
||||
('pages', self.gf('django.db.models.fields.IntegerField')(null=True, blank=True)),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')(default=1, blank=True)),
|
||||
('intended_std_level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.IntendedStdLevelName'], null=True, blank=True)),
|
||||
('std_level', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.StdLevelName'], null=True, blank=True)),
|
||||
('ad', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='ad_dochistory_set', null=True, to=orm['person.Person'])),
|
||||
('shepherd', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='shepherd_dochistory_set', null=True, to=orm['person.Person'])),
|
||||
('expires', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
('notify', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)),
|
||||
('external_url', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True)),
|
||||
('note', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('internal_comments', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('doc', self.gf('django.db.models.fields.related.ForeignKey')(related_name='history_set', to=orm['doc.Document'])),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocHistory'])
|
||||
|
||||
# Adding M2M table for field states on 'DocHistory'
|
||||
db.create_table('doc_dochistory_states', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('dochistory', models.ForeignKey(orm['doc.dochistory'], null=False)),
|
||||
('state', models.ForeignKey(orm['doc.state'], null=False))
|
||||
))
|
||||
db.create_unique('doc_dochistory_states', ['dochistory_id', 'state_id'])
|
||||
|
||||
# Adding M2M table for field tags on 'DocHistory'
|
||||
db.create_table('doc_dochistory_tags', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('dochistory', models.ForeignKey(orm['doc.dochistory'], null=False)),
|
||||
('doctagname', models.ForeignKey(orm['name.doctagname'], null=False))
|
||||
))
|
||||
db.create_unique('doc_dochistory_tags', ['dochistory_id', 'doctagname_id'])
|
||||
|
||||
# Adding model 'DocAlias'
|
||||
db.create_table('doc_docalias', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('document', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.Document'])),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255, db_index=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocAlias'])
|
||||
|
||||
# Adding model 'DocReminder'
|
||||
db.create_table('doc_docreminder', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('event', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.DocEvent'])),
|
||||
('type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocReminderTypeName'])),
|
||||
('due', self.gf('django.db.models.fields.DateTimeField')()),
|
||||
('active', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocReminder'])
|
||||
|
||||
# Adding model 'DocEvent'
|
||||
db.create_table('doc_docevent', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('time', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now)),
|
||||
('type', self.gf('django.db.models.fields.CharField')(max_length=50)),
|
||||
('by', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])),
|
||||
('doc', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.Document'])),
|
||||
('desc', self.gf('django.db.models.fields.TextField')()),
|
||||
))
|
||||
db.send_create_signal('doc', ['DocEvent'])
|
||||
|
||||
# Adding model 'NewRevisionDocEvent'
|
||||
db.create_table('doc_newrevisiondocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('rev', self.gf('django.db.models.fields.CharField')(max_length=16)),
|
||||
))
|
||||
db.send_create_signal('doc', ['NewRevisionDocEvent'])
|
||||
|
||||
# Adding model 'BallotType'
|
||||
db.create_table('doc_ballottype', (
|
||||
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||
('doc_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['name.DocTypeName'], null=True, blank=True)),
|
||||
('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)),
|
||||
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
|
||||
('question', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('used', self.gf('django.db.models.fields.BooleanField')(default=True)),
|
||||
('order', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||
))
|
||||
db.send_create_signal('doc', ['BallotType'])
|
||||
|
||||
# Adding model 'BallotDocEvent'
|
||||
db.create_table('doc_ballotdocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('ballot_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.BallotType'])),
|
||||
))
|
||||
db.send_create_signal('doc', ['BallotDocEvent'])
|
||||
|
||||
# Adding model 'BallotPositionDocEvent'
|
||||
db.create_table('doc_ballotpositiondocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('ad', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])),
|
||||
('pos', self.gf('django.db.models.fields.related.ForeignKey')(default='norecord', to=orm['name.BallotPositionName'])),
|
||||
('discuss', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('discuss_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
('comment', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('comment_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['BallotPositionDocEvent'])
|
||||
|
||||
# Adding model 'WriteupDocEvent'
|
||||
db.create_table('doc_writeupdocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('text', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['WriteupDocEvent'])
|
||||
|
||||
# Adding model 'LastCallDocEvent'
|
||||
db.create_table('doc_lastcalldocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('expires', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['LastCallDocEvent'])
|
||||
|
||||
# Adding model 'TelechatDocEvent'
|
||||
db.create_table('doc_telechatdocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('telechat_date', self.gf('django.db.models.fields.DateField')(null=True, blank=True)),
|
||||
('returning_item', self.gf('django.db.models.fields.BooleanField')(default=False)),
|
||||
))
|
||||
db.send_create_signal('doc', ['TelechatDocEvent'])
|
||||
|
||||
# Adding model 'GroupBallotPositionDocEvent'
|
||||
db.create_table('doc_groupballotpositiondocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('ad', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['person.Person'])),
|
||||
('pos', self.gf('django.db.models.fields.related.ForeignKey')(default='norecord', to=orm['name.GroupBallotPositionName'])),
|
||||
('block_comment', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('block_comment_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
('comment', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||
('comment_time', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['GroupBallotPositionDocEvent'])
|
||||
|
||||
# Adding model 'InitialReviewDocEvent'
|
||||
db.create_table('doc_initialreviewdocevent', (
|
||||
('docevent_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['doc.DocEvent'], unique=True, primary_key=True)),
|
||||
('expires', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
|
||||
))
|
||||
db.send_create_signal('doc', ['InitialReviewDocEvent'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Deleting model 'StateType'
|
||||
db.delete_table('doc_statetype')
|
||||
|
||||
# Deleting model 'State'
|
||||
db.delete_table('doc_state')
|
||||
|
||||
# Removing M2M table for field next_states on 'State'
|
||||
db.delete_table('doc_state_next_states')
|
||||
|
||||
# Deleting model 'RelatedDocument'
|
||||
db.delete_table('doc_relateddocument')
|
||||
|
||||
# Deleting model 'DocumentAuthor'
|
||||
db.delete_table('doc_documentauthor')
|
||||
|
||||
# Deleting model 'Document'
|
||||
db.delete_table('doc_document')
|
||||
|
||||
# Removing M2M table for field states on 'Document'
|
||||
db.delete_table('doc_document_states')
|
||||
|
||||
# Removing M2M table for field tags on 'Document'
|
||||
db.delete_table('doc_document_tags')
|
||||
|
||||
# Deleting model 'RelatedDocHistory'
|
||||
db.delete_table('doc_relateddochistory')
|
||||
|
||||
# Deleting model 'DocHistoryAuthor'
|
||||
db.delete_table('doc_dochistoryauthor')
|
||||
|
||||
# Deleting model 'DocHistory'
|
||||
db.delete_table('doc_dochistory')
|
||||
|
||||
# Removing M2M table for field states on 'DocHistory'
|
||||
db.delete_table('doc_dochistory_states')
|
||||
|
||||
# Removing M2M table for field tags on 'DocHistory'
|
||||
db.delete_table('doc_dochistory_tags')
|
||||
|
||||
# Deleting model 'DocAlias'
|
||||
db.delete_table('doc_docalias')
|
||||
|
||||
# Deleting model 'DocReminder'
|
||||
db.delete_table('doc_docreminder')
|
||||
|
||||
# Deleting model 'DocEvent'
|
||||
db.delete_table('doc_docevent')
|
||||
|
||||
# Deleting model 'NewRevisionDocEvent'
|
||||
db.delete_table('doc_newrevisiondocevent')
|
||||
|
||||
# Deleting model 'BallotType'
|
||||
db.delete_table('doc_ballottype')
|
||||
|
||||
# Deleting model 'BallotDocEvent'
|
||||
db.delete_table('doc_ballotdocevent')
|
||||
|
||||
# Deleting model 'BallotPositionDocEvent'
|
||||
db.delete_table('doc_ballotpositiondocevent')
|
||||
|
||||
# Deleting model 'WriteupDocEvent'
|
||||
db.delete_table('doc_writeupdocevent')
|
||||
|
||||
# Deleting model 'LastCallDocEvent'
|
||||
db.delete_table('doc_lastcalldocevent')
|
||||
|
||||
# Deleting model 'TelechatDocEvent'
|
||||
db.delete_table('doc_telechatdocevent')
|
||||
|
||||
# Deleting model 'GroupBallotPositionDocEvent'
|
||||
db.delete_table('doc_groupballotpositiondocevent')
|
||||
|
||||
# Deleting model 'InitialReviewDocEvent'
|
||||
db.delete_table('doc_initialreviewdocevent')
|
||||
|
||||
|
||||
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']"}),
|
||||
'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'}),
|
||||
'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.groupballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'GroupBallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'block_comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'block_comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_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.GroupBallotPositionName']"})
|
||||
},
|
||||
'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.CharField', [], {'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'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False'})
|
||||
},
|
||||
'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'}),
|
||||
'valid_document_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTypeName']", 'symmetrical': 'False', 'blank': '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.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']
|
|
@ -0,0 +1,381 @@
|
|||
# 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 M2M table for field positions on 'BallotType'
|
||||
db.create_table('doc_ballottype_positions', (
|
||||
('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
|
||||
('ballottype', models.ForeignKey(orm['doc.ballottype'], null=False)),
|
||||
('ballotpositionname', models.ForeignKey(orm['name.ballotpositionname'], null=False))
|
||||
))
|
||||
db.create_unique('doc_ballottype_positions', ['ballottype_id', 'ballotpositionname_id'])
|
||||
|
||||
# Adding field 'BallotPositionDocEvent.ballot'
|
||||
db.add_column('doc_ballotpositiondocevent', 'ballot', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['doc.BallotDocEvent'], null=True), keep_default=False)
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing M2M table for field positions on 'BallotType'
|
||||
db.delete_table('doc_ballottype_positions')
|
||||
|
||||
# Deleting field 'BallotPositionDocEvent.ballot'
|
||||
db.delete_column('doc_ballotpositiondocevent', 'ballot_id')
|
||||
|
||||
|
||||
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', [], {'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.groupballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'GroupBallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'block_comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'block_comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_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.GroupBallotPositionName']"})
|
||||
},
|
||||
'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.CharField', [], {'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'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False'})
|
||||
},
|
||||
'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'}),
|
||||
'valid_document_types': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTypeName']", 'symmetrical': 'False', 'blank': '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.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']
|
0
ietf/doc/migrations/__init__.py
Normal file
0
ietf/doc/migrations/__init__.py
Normal file
|
@ -15,7 +15,7 @@ class StateType(models.Model):
|
|||
label = models.CharField(max_length=255, help_text="Label that should be used (e.g. in admin) for state drop-down for this type of state") # State, IESG state, WG state, ...
|
||||
|
||||
def __unicode__(self):
|
||||
return self.label
|
||||
return self.slug
|
||||
|
||||
class State(models.Model):
|
||||
type = models.ForeignKey(StateType)
|
||||
|
@ -374,14 +374,6 @@ class TelechatDocEvent(DocEvent):
|
|||
telechat_date = models.DateField(blank=True, null=True)
|
||||
returning_item = models.BooleanField(default=False)
|
||||
|
||||
# Charter ballot events
|
||||
class GroupBallotPositionDocEvent(DocEvent):
|
||||
ad = models.ForeignKey(Person)
|
||||
pos = models.ForeignKey(GroupBallotPositionName, verbose_name="position", default="norecord")
|
||||
block_comment = models.TextField(help_text="Blocking comment if position is comment", blank=True)
|
||||
block_comment_time = models.DateTimeField(help_text="Blocking comment was written", blank=True, null=True)
|
||||
comment = models.TextField(help_text="Non-blocking comment", blank=True)
|
||||
comment_time = models.DateTimeField(help_text="Time non-blocking comment was written", blank=True, null=True)
|
||||
|
||||
# charter events
|
||||
class InitialReviewDocEvent(DocEvent):
|
||||
expires = models.DateTimeField(blank=True, null=True)
|
||||
|
|
|
@ -817,7 +817,7 @@ class DocumentComment(DocEvent):
|
|||
class Position(BallotPositionDocEvent):
|
||||
def from_object(self, base):
|
||||
for f in base._meta.fields:
|
||||
if not f.name in ('discuss',): # don't overwrite properties
|
||||
if not f.name in ('discuss', 'ballot'): # don't overwrite properties
|
||||
setattr(self, f.name, getattr(base, f.name))
|
||||
return self
|
||||
|
||||
|
|
|
@ -86,9 +86,9 @@ def needed_ballot_positions(doc, active_positions):
|
|||
answer.append("Needs %d more positions." % more)
|
||||
else:
|
||||
if blocking:
|
||||
answer.append("Has enough positions to pass.")
|
||||
answer.append("Has enough positions to pass once %s positions are resolved." % blocking[0].pos.name.upper())
|
||||
else:
|
||||
answer.append("Has enough positions to pass once %s positions are resolved." % blocking[0].name.upper())
|
||||
answer.append("Has enough positions to pass.")
|
||||
|
||||
return " ".join(answer)
|
||||
|
||||
|
|
|
@ -75,7 +75,6 @@ def render_ballot_icon(context, doc):
|
|||
name = doc.document().filename()
|
||||
else:
|
||||
name = doc.document().filename
|
||||
tracker_id = doc.draft_id
|
||||
else:
|
||||
if doc.in_ietf_process() and doc.ietf_process.has_active_iesg_ballot():
|
||||
ballot = doc._idinternal.ballot
|
||||
|
@ -83,10 +82,8 @@ def render_ballot_icon(context, doc):
|
|||
return ""
|
||||
if doc.is_rfc_wrapper:
|
||||
name = "rfc"+str(doc.rfc_number)
|
||||
tracker_id = doc.rfc_number
|
||||
else:
|
||||
name = doc.draft_name
|
||||
tracker_id = doc.tracker_id
|
||||
adId = get_user_adid(context)
|
||||
red = 0
|
||||
green = 0
|
||||
|
@ -109,10 +106,15 @@ def render_ballot_icon(context, doc):
|
|||
blank = blank + 1
|
||||
if adId and (p['ad'].id == adId):
|
||||
my = position_to_string(p['pos'])
|
||||
return render_ballot_icon2(name, tracker_id, red,yellow,green,gray,blank, my, adId)+"<!-- adId="+str(adId)+" my="+str(my)+"-->"
|
||||
return render_ballot_icon2(name, red,yellow,green,gray,blank, my, adId)+"<!-- adId="+str(adId)+" my="+str(my)+"-->"
|
||||
|
||||
def render_ballot_icon2(draft_name, tracker_id, red,yellow,green,gray,blank, my,adId):
|
||||
edit_position_url = urlreverse('doc_edit_position', kwargs=dict(name=draft_name))
|
||||
def render_ballot_icon2(draft_name, red,yellow,green,gray,blank, my,adId):
|
||||
from ietf.doc.models import BallotDocEvent
|
||||
ballots = BallotDocEvent.objects.filter(doc__docalias__name=draft_name).order_by("-time", "-id")
|
||||
if ballots:
|
||||
edit_position_url = urlreverse('doc_edit_position', kwargs=dict(name=draft_name, ballot_id=ballots[0].pk))
|
||||
else:
|
||||
edit_position_url = ""
|
||||
if adId:
|
||||
res_cm = ' oncontextmenu="editBallot(\''+str(edit_position_url)+'\');return false;"'
|
||||
else:
|
||||
|
|
|
@ -418,7 +418,8 @@ class EditPositionTestCase(django.test.TestCase):
|
|||
|
||||
def test_edit_position(self):
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_edit_position', kwargs=dict(name=draft.name))
|
||||
url = urlreverse('doc_edit_position', kwargs=dict(name=draft.name,
|
||||
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
ad = Person.objects.get(name="Aread Irector")
|
||||
|
@ -479,7 +480,8 @@ class EditPositionTestCase(django.test.TestCase):
|
|||
|
||||
def test_edit_position_as_secretary(self):
|
||||
draft = make_test_data()
|
||||
url = urlreverse('doc_edit_position', kwargs=dict(name=draft.name))
|
||||
url = urlreverse('doc_edit_position', kwargs=dict(name=draft.name,
|
||||
ballot_id=draft.latest_event(BallotDocEvent, type="created_ballot").pk))
|
||||
ad = Person.objects.get(name="Aread Irector")
|
||||
url += "?ad=%s" % ad.pk
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
@ -507,13 +509,16 @@ class EditPositionTestCase(django.test.TestCase):
|
|||
draft.save()
|
||||
|
||||
ad = Person.objects.get(name="Aread Irector")
|
||||
|
||||
|
||||
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
|
||||
|
||||
BallotPositionDocEvent.objects.create(doc=draft, type="changed_ballot_position",
|
||||
by=ad, ad=ad, pos=BallotPositionName.objects.get(slug="yes"),
|
||||
comment="Test!",
|
||||
comment_time=datetime.datetime.now())
|
||||
by=ad, ballot=ballot, ad=ad, pos=BallotPositionName.objects.get(slug="yes"),
|
||||
comment="Test!",
|
||||
comment_time=datetime.datetime.now())
|
||||
|
||||
url = urlreverse('doc_send_ballot_comment', kwargs=dict(name=draft.name))
|
||||
url = urlreverse('doc_send_ballot_comment', kwargs=dict(name=draft.name,
|
||||
ballot_id=ballot.pk))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
# normal get
|
||||
|
@ -670,10 +675,13 @@ class BallotWriteupsTestCase(django.test.TestCase):
|
|||
url = urlreverse('doc_ballot_writeupnotes', kwargs=dict(name=draft.name))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
ballot = draft.latest_event(BallotDocEvent, type="created_ballot")
|
||||
|
||||
def create_pos(num, vote, comment="", discuss=""):
|
||||
ad = Person.objects.get(name="Ad No%s" % num)
|
||||
e = BallotPositionDocEvent()
|
||||
e.doc = draft
|
||||
e.ballot = ballot
|
||||
e.by = ad
|
||||
e.ad = ad
|
||||
e.pos = BallotPositionName.objects.get(slug=vote)
|
||||
|
|
|
@ -240,7 +240,7 @@ def edit_positionREDESIGN(request, name, ballot_id):
|
|||
if 'HTTP_REFERER' in request.META:
|
||||
return_to_url = request.META['HTTP_REFERER']
|
||||
else:
|
||||
return_to_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot=ballot_id))
|
||||
return_to_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id))
|
||||
|
||||
# if we're in the Secretariat, we can select an AD to act as stand-in for
|
||||
if not has_role(request.user, "Area Director"):
|
||||
|
@ -447,12 +447,12 @@ def send_ballot_commentREDESIGN(request, name, ballot_id):
|
|||
|
||||
return_to_url = request.GET.get('return_to_url')
|
||||
if not return_to_url:
|
||||
return_to_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot=ballot_id))
|
||||
return_to_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id))
|
||||
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
back_url = request.META['HTTP_REFERER']
|
||||
else:
|
||||
back_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot=ballot_id))
|
||||
back_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id))
|
||||
|
||||
# if we're in the Secretariat, we can select an AD to act as stand-in for
|
||||
if not has_role(request.user, "Area Director"):
|
||||
|
|
|
@ -242,7 +242,7 @@ def document_writeup(request, name):
|
|||
def document_ballot_content(request, doc, ballot_id, editable=True):
|
||||
"""Render HTML string with content of ballot page."""
|
||||
if ballot_id != None:
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot", pk=ballot)
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot", pk=ballot_id)
|
||||
else:
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
|
||||
|
||||
|
@ -276,10 +276,11 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
|
|||
latest.old_positions.append(e)
|
||||
|
||||
# add any missing ADs through fake No Record events
|
||||
norecord = BallotPositionName.objects.get(slug="norecord")
|
||||
for ad in active_ads:
|
||||
if ad not in seen:
|
||||
e = BallotPositionDocEvent(type="changed_ballot_position", doc=doc, ad=ad)
|
||||
e.pos_id = "norecord"
|
||||
e.pos = norecord
|
||||
e.old_ad = False
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
|
@ -299,6 +300,8 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
|
|||
text_positions = [p for p in positions if p.discuss or p.comment]
|
||||
text_positions.sort(key=lambda p: (p.old_ad, p.ad.plain_name()))
|
||||
|
||||
all_ballots = BallotDocEvent.objects.filter(doc=doc, type="created_ballot")
|
||||
|
||||
return render_to_string("idrfc/document_ballot_content.html",
|
||||
dict(doc=doc,
|
||||
ballot=ballot,
|
||||
|
@ -307,6 +310,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
|
|||
editable=editable,
|
||||
deferred=deferred,
|
||||
summary=summary,
|
||||
all_ballots=all_ballots,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
|
|
@ -71,27 +71,35 @@ def has_role(user, role_names):
|
|||
if not user or not user.is_authenticated():
|
||||
return False
|
||||
|
||||
from ietf.person.models import Person
|
||||
|
||||
try:
|
||||
person = user.get_profile()
|
||||
except Person.DoesNotExist:
|
||||
return False
|
||||
if not hasattr(user, "roles_check_cache"):
|
||||
user.roles_check_cache = {}
|
||||
|
||||
role_qs = {
|
||||
"Area Director": Q(person=person, name="ad", group__type="area", group__state="active"),
|
||||
"Secretariat": Q(person=person, name="secr", group__acronym="secretariat"),
|
||||
"IANA": Q(person=person, name="auth", group__acronym="iana"),
|
||||
"WG Chair": Q(person=person,name="chair", group__type="wg", group__state="active"),
|
||||
"WG Secretary": Q(person=person,name="secr", group__type="wg", group__state="active"),
|
||||
}
|
||||
key = frozenset(role_names)
|
||||
if key not in user.roles_check_cache:
|
||||
|
||||
filter_expr = Q()
|
||||
for r in role_names:
|
||||
filter_expr |= role_qs[r]
|
||||
from ietf.person.models import Person
|
||||
from ietf.group.models import Role
|
||||
|
||||
from ietf.group.models import Role
|
||||
return bool(Role.objects.filter(filter_expr)[:1])
|
||||
try:
|
||||
person = user.get_profile()
|
||||
except Person.DoesNotExist:
|
||||
return False
|
||||
|
||||
role_qs = {
|
||||
"Area Director": Q(person=person, name="ad", group__type="area", group__state="active"),
|
||||
"Secretariat": Q(person=person, name="secr", group__acronym="secretariat"),
|
||||
"IANA": Q(person=person, name="auth", group__acronym="iana"),
|
||||
"WG Chair": Q(person=person,name="chair", group__type="wg", group__state="active"),
|
||||
"WG Secretary": Q(person=person,name="secr", group__type="wg", group__state="active"),
|
||||
}
|
||||
|
||||
filter_expr = Q()
|
||||
for r in role_names:
|
||||
filter_expr |= role_qs[r]
|
||||
|
||||
user.roles_check_cache[key] = bool(Role.objects.filter(filter_expr)[:1])
|
||||
|
||||
return user.roles_check_cache[key]
|
||||
|
||||
def role_required(*role_names):
|
||||
"""View decorator for checking that the user is logged in and
|
||||
|
|
|
@ -5,36 +5,49 @@
|
|||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">1</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="noobj" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">No Objection</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">2</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="discuss" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Discuss</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">3</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="block" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Block</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">3</field>
|
||||
<field type="BooleanField" name="blocking">True</field>
|
||||
</object>
|
||||
<object pk="abstain" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Abstain</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">4</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="recuse" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">Recuse</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">5</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="norecord" model="name.ballotpositionname">
|
||||
<field type="CharField" name="name">No Record</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">6</field>
|
||||
<field type="BooleanField" name="blocking">False</field>
|
||||
</object>
|
||||
<object pk="conflict" model="name.constraintname">
|
||||
<field type="CharField" name="name">Conflicts with</field>
|
||||
|
@ -54,8 +67,8 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="replaces" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Replaces</field>
|
||||
<object pk="obs" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Obsoletes</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
|
@ -66,8 +79,8 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="obs" model="name.docrelationshipname">
|
||||
<field type="CharField" name="name">Obsoletes</field>
|
||||
<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>
|
||||
|
@ -78,6 +91,30 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="iana-crd" model="name.doctagname">
|
||||
<field type="CharField" name="name">IANA coordination</field>
|
||||
<field type="TextField" name="desc">RFC-Editor/IANA Registration Coordination</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="ref" model="name.doctagname">
|
||||
<field type="CharField" name="name">Holding for references</field>
|
||||
<field type="TextField" name="desc">Holding for normative reference</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="missref" model="name.doctagname">
|
||||
<field type="CharField" name="name">Missing references</field>
|
||||
<field type="TextField" name="desc">Awaiting missing normative reference</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="errata" model="name.doctagname">
|
||||
<field type="CharField" name="name">Has errata</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="rfc-rev" model="name.doctagname">
|
||||
<field type="CharField" name="name">Review by RFC Editor</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -90,24 +127,12 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="exp-tomb" model="name.doctagname">
|
||||
<field type="CharField" name="name">Expired tombstone</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<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="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="errata" model="name.doctagname">
|
||||
<field type="CharField" name="name">Has errata</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="need-sh" model="name.doctagname">
|
||||
<field type="CharField" name="name">Shepherd Needed</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -246,6 +271,12 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">11</field>
|
||||
</object>
|
||||
<object pk="charter" model="name.doctypename">
|
||||
<field type="CharField" name="name">Charter</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="agenda" model="name.doctypename">
|
||||
<field type="CharField" name="name">Agenda</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -276,12 +307,6 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="charter" model="name.doctypename">
|
||||
<field type="CharField" name="name">Charter</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="no" model="name.groupballotpositionname">
|
||||
<field type="CharField" name="name">No</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -396,6 +421,12 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="irtf" model="name.grouptypename">
|
||||
<field type="CharField" name="name">IRTF</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>
|
||||
|
@ -405,7 +436,7 @@
|
|||
<object pk="ds" model="name.intendedstdlevelname">
|
||||
<field type="CharField" name="name">Draft Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="BooleanField" name="used">False</field>
|
||||
<field type="IntegerField" name="order">2</field>
|
||||
</object>
|
||||
<object pk="std" model="name.intendedstdlevelname">
|
||||
|
@ -480,8 +511,8 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="ex-ad" model="name.rolename">
|
||||
<field type="CharField" name="name">Ex Area Director</field>
|
||||
<object pk="pre-ad" model="name.rolename">
|
||||
<field type="CharField" name="name">Incoming Area Director</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
|
@ -582,6 +613,12 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="deleted" model="name.sessionstatusname">
|
||||
<field type="CharField" name="name">Deleted</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="std" model="name.stdlevelname">
|
||||
<field type="CharField" name="name">Standard</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
|
@ -630,32 +667,38 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="legacy" model="name.streamname">
|
||||
<field type="CharField" name="name">Legacy</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="ietf" model="name.streamname">
|
||||
<field type="CharField" name="name">IETF</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="TextField" name="desc">IETF stream</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">1</field>
|
||||
</object>
|
||||
<object pk="ise" model="name.streamname">
|
||||
<field type="CharField" name="name">ISE</field>
|
||||
<field type="TextField" name="desc">Independent submission editor stream</field>
|
||||
<field type="TextField" name="desc">Independent Submission Editor stream</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
</object>
|
||||
<object pk="iab" model="name.streamname">
|
||||
<field type="CharField" name="name">IAB</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
<field type="IntegerField" name="order">2</field>
|
||||
</object>
|
||||
<object pk="irtf" model="name.streamname">
|
||||
<field type="CharField" name="name">IRTF</field>
|
||||
<field type="TextField" name="desc">Independent Submission Editor stream</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">3</field>
|
||||
</object>
|
||||
<object pk="iab" model="name.streamname">
|
||||
<field type="CharField" name="name">IAB</field>
|
||||
<field type="TextField" name="desc">IAB stream</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">4</field>
|
||||
</object>
|
||||
<object pk="legacy" model="name.streamname">
|
||||
<field type="CharField" name="name">Legacy</field>
|
||||
<field type="TextField" name="desc">Legacy stream</field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">5</field>
|
||||
</object>
|
||||
<object pk="other" model="name.timeslottypename">
|
||||
<field type="CharField" name="name">Other</field>
|
||||
<field type="TextField" name="desc"></field>
|
||||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="IntegerField" name="order">0</field>
|
||||
|
@ -697,10 +740,10 @@
|
|||
<field type="CharField" name="label">RFC Editor state</field>
|
||||
</object>
|
||||
<object pk="draft-stream-ietf" model="doc.statetype">
|
||||
<field type="CharField" name="label">WG state</field>
|
||||
<field type="CharField" name="label">IETF state</field>
|
||||
</object>
|
||||
<object pk="draft-stream-irtf" model="doc.statetype">
|
||||
<field type="CharField" name="label">RG state</field>
|
||||
<field type="CharField" name="label">IRTF state</field>
|
||||
</object>
|
||||
<object pk="draft-stream-ise" model="doc.statetype">
|
||||
<field type="CharField" name="label">ISE state</field>
|
||||
|
@ -919,7 +962,7 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">The document is now (finally!) being formally reviewed by the entire IESG. Documents are discussed in email or during a bi-weekly IESG telechat. In this phase, each AD reviews the document and airs any issues they may have. Unresolvable issues are documented as "discuss" comments that can be forwarded to the authors/WG. See the description of substates for additional details about the current state of the IESG discussion.</field>
|
||||
<field type="IntegerField" name="order">20</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="18"></object><object pk="10"></object><object pk="22"></object></field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="18"></object><object pk="9"></object><object pk="22"></object></field>
|
||||
</object>
|
||||
<object pk="18" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iesg</field>
|
||||
|
@ -937,7 +980,7 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">The IESG has approved the document for publication, but the Secretariat has not yet sent out on official approval message.</field>
|
||||
<field type="IntegerField" name="order">27</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="17"></object></field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="10"></object></field>
|
||||
</object>
|
||||
<object pk="10" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iesg</field>
|
||||
|
@ -946,7 +989,7 @@
|
|||
<field type="BooleanField" name="used">True</field>
|
||||
<field type="TextField" name="desc">The IESG has approved the document for publication, and the Secretariat has sent out the official approval message to the RFC editor.</field>
|
||||
<field type="IntegerField" name="order">30</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="9"></object></field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"><object pk="17"></object></field>
|
||||
</object>
|
||||
<object pk="17" model="doc.state">
|
||||
<field to="doc.statetype" name="type" rel="ManyToOneRel">draft-iesg</field>
|
||||
|
@ -1581,4 +1624,31 @@
|
|||
<field type="IntegerField" name="order">2</field>
|
||||
<field to="doc.state" name="next_states" rel="ManyToManyRel"></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>
|
||||
<field type="CharField" name="name">Ready for external review</field>
|
||||
<field type="TextField" name="question">Is this charter ready for external review?</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="block"></object><object pk="abstain"></object><object pk="norecord"></object></field>
|
||||
</object>
|
||||
<object pk="2" model="doc.ballottype">
|
||||
<field to="name.doctypename" name="doc_type" rel="ManyToOneRel">charter</field>
|
||||
<field type="SlugField" name="slug">approve</field>
|
||||
<field type="CharField" name="name">Approve</field>
|
||||
<field type="TextField" name="question">Do we approve of this charter?</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="block"></object><object pk="abstain"></object><object pk="norecord"></object></field>
|
||||
</object>
|
||||
<object pk="3" model="doc.ballottype">
|
||||
<field to="name.doctypename" name="doc_type" rel="ManyToOneRel">draft</field>
|
||||
<field type="SlugField" name="slug">approve</field>
|
||||
<field type="CharField" name="name">Approve</field>
|
||||
<field type="TextField" name="question"></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>
|
||||
</django-objects>
|
|
@ -37,9 +37,10 @@ for n in dir(ietf.name.models):
|
|||
objects.extend(model.objects.all())
|
||||
|
||||
|
||||
import ietf.doc.models # FIXME
|
||||
import ietf.doc.models # also pick some other name-like types while we're at it
|
||||
objects += ietf.doc.models.StateType.objects.all()
|
||||
objects += ietf.doc.models.State.objects.all()
|
||||
objects += ietf.doc.models.BallotType.objects.all()
|
||||
|
||||
output("names", objects)
|
||||
|
||||
|
|
|
@ -33,6 +33,17 @@
|
|||
|
||||
</div>
|
||||
|
||||
<div class="ballot-content">
|
||||
|
||||
{% if all_ballots and all_ballots|length > 1 %}
|
||||
<div class="other-ballots">
|
||||
Other ballots:
|
||||
{% for b in all_ballots %}
|
||||
<a{% if b != ballot %} href="{% url doc_ballot name=doc.name,ballot_id=b.pk %}"{% endif %}>{{ b.ballot_type.name }} ({{ b.time|date:"Y-m-d" }})</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<h2 style="margin-top:12px;">Q: {{ ballot.ballot_type.question }}</h2>
|
||||
|
||||
<p>Summary: <i>{{ summary }}</i></p>
|
||||
|
@ -50,3 +61,5 @@
|
|||
<pre>{{ p.comment|fill:"80"|escape }}</pre>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
|
|
@ -30,7 +30,7 @@ form.approve-ballot .announcement {
|
|||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{% url wg_view name=wg.acronym %}">Back</a>
|
||||
<a href="{% url doc_ballot name=wg.charter.name %}">Back</a>
|
||||
<input type="submit" value="Send out the announcement, close ballot and update revision"/>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
{% autoescape off %}{{ ad }} has entered the following ballot position for
|
||||
{{ charter.name }}-{{ charter.rev }}: {{ pos.name }}
|
||||
|
||||
When responding, please keep the subject line intact and reply to all
|
||||
email addresses included in the To and CC lines. (Feel free to cut this
|
||||
introductory paragraph, however.)
|
||||
|
||||
{% if not block_comment and not comment %}
|
||||
There is no BLOCK or COMMENT text associated with this position.
|
||||
{% endif %}
|
||||
|
||||
{% if block_comment %}----------------------------------------------------------------------
|
||||
BLOCK:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
{{ block_comment|safe|wordwrap:73 }}
|
||||
|
||||
|
||||
{% endif %}{% if comment %}----------------------------------------------------------------------
|
||||
COMMENT:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
{{ comment|safe|wordwrap:73 }}
|
||||
{% endif %}
|
||||
{% endautoescape %}
|
|
@ -1,29 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% block title %}Working Groups for {{ area_name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Working Groups for {{ area_name }}</h1>
|
||||
|
||||
<p>
|
||||
<span id="create_wg" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="/wgcharter/create/">Start new WG charter effort</a></span></span>
|
||||
</p>
|
||||
|
||||
{% if not recs %}
|
||||
<p><b>No WGs match your query.</b></p>
|
||||
{% else %}
|
||||
<table class="ietf-table ietf-doctable">
|
||||
<tr>
|
||||
{% for hdr in meta.hdrs %}
|
||||
{% include "wgcharter/table_header.html" %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for wg in recs %}
|
||||
{% include "wgcharter/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
|
@ -45,14 +45,13 @@ form.change-state .actions {
|
|||
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if field.name == "charter_state" and field.errors == "warning" %}
|
||||
<ul><li>The initial review time hasn't elapsed. Select this checkbox to proceed anyway: <label><input type="checkbox" name="confirm_state" /></label></li></ul>
|
||||
{% else %}
|
||||
{{ field.errors }}
|
||||
{% endif %}
|
||||
{{ field.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% if initial_review %}
|
||||
<tr><td></td><td class="warning">Warning: Announced initial review time hasn't elapsed yet. It does so at {{ initial_review.expires }}.</td></tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td colspan="2" class="actions">
|
||||
{% if option %}
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<div class="ietf-box diffTool">
|
||||
<h2 style="margin-top:0;margin-bottom:4px;">Diffs</h2>
|
||||
<form action="http{% if request.is_secure %}s{% endif %}://tools.ietf.org/rfcdiff" method="get" target="_blank" style="margin:0;">
|
||||
<table>
|
||||
<tr><td>
|
||||
<label>From:</label> <select name="url1">
|
||||
{% for c in versions %}
|
||||
<option value="{{ charter_text_url }}{{c.name}}-{{c.rev}}.txt" {% ifequal forloop.counter 2 %} selected="selected" {% endifequal %}>{{c.name}}-{{c.rev}} ({{c.date}})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td rowspan="2" valign="top">
|
||||
Format:
|
||||
<select name="difftype">
|
||||
<option value="--html" selected="selected">Side-by-side</option>
|
||||
<option value="--abdiff">Before-after</option>
|
||||
<option value="--chbars">Change bars</option>
|
||||
<option value="--hwdiff">Wdiff</option>
|
||||
</select> <input name="submit" value="Go!" type="submit" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<label>To:</label>
|
||||
<select name="url2">
|
||||
{% for c in versions %}
|
||||
<option value="{{ charter_text_url }}{{c.name}}-{{c.rev}}.txt" {% ifequal forloop.counter 1 %} selected="selected" {% endifequal %}>{{c.name}}-{{c.rev}} ({{c.date}})</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
{% load ietf_filters %}<td class="date">{{ wg.time|date:"Y-m-d" }}
|
||||
</td>
|
|
@ -1,71 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Change position for {{ ad.plain_name }} on {{ wg.acronym }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.position-form .position ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
form.position-form .position li {
|
||||
list-style-type: none;
|
||||
float: left;
|
||||
padding-right: 10px;
|
||||
}
|
||||
form.position-form .last-edited {
|
||||
font-style: italic;
|
||||
}
|
||||
form.position-form .block_comment {
|
||||
padding-top: 20px
|
||||
}
|
||||
form.position-form #id_block_comment,
|
||||
form.position-form #id_comment {
|
||||
width: 700px;
|
||||
height: 250px;
|
||||
}
|
||||
form.position-form .comment {
|
||||
margin-top: 20px;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change position for {{ ad.plain_name }} on {{ wg.acronym }}</h1>
|
||||
|
||||
<form class="position-form" action="" method="POST">
|
||||
<div>
|
||||
<span class="position">{{ form.position }}</span>
|
||||
<span class="actions">
|
||||
<input type="submit" name="send_mail" value="Save and send email"/>
|
||||
<input type="submit" value="Save"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style="clear:left"></div>
|
||||
|
||||
<div class="block_comment-widgets" {% ifnotequal form.position.initial "block" %}style="display:none"{% endifnotequal %}>
|
||||
<div class="block_comment">
|
||||
{{ form.block_comment.label_tag }}:
|
||||
{% if old_pos and old_pos.block_comment_time %}<span class="last-edited">(last edited {{ old_pos.block_comment_time }})</span>{% endif %}
|
||||
</div>
|
||||
{{ form.block_comment.errors }}
|
||||
{{ form.block_comment }}
|
||||
</div>
|
||||
|
||||
<div class="comment">
|
||||
{{ form.comment.label_tag }}:
|
||||
{% if old_pos and old_pos.comment_time %}<span class="last-edited">(last edited {{ old_pos.comment_time }}){% endif %}</span>
|
||||
</div>
|
||||
{{ form.comment }}
|
||||
|
||||
<div class="actions">
|
||||
<a href="{{ return_to_url }}">Back</a>
|
||||
</div>
|
||||
|
||||
{{ form.return_to_url }}
|
||||
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_end %}
|
||||
<script type="text/javascript" src="/js/wg-edit-position.js"></script>
|
||||
{% endblock %}
|
|
@ -1,5 +1,6 @@
|
|||
{% autoescape off %}
|
||||
{{ text }}
|
||||
{% load ietf_filters %}{% autoescape off %}
|
||||
{{ text|fill:70 }}
|
||||
|
||||
WG URL: {{ url }}
|
||||
WG: {{ wg_url }}
|
||||
Charter: {{ charter_url }}
|
||||
{% endautoescape %}
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% block title %}Working Groups in IESG process{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Working Groups in IESG process</h1>
|
||||
|
||||
<p>
|
||||
<span id="create_wg" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="/wgcharter/create/">Start new WG charter effort</a></span></span>
|
||||
</p>
|
||||
|
||||
{% if not recs %}
|
||||
<p><b>No WGs match your query.</b></p>
|
||||
{% else %}
|
||||
<table class="ietf-table ietf-doctable">
|
||||
<tr>
|
||||
{% for hdr in meta.hdrs %}
|
||||
{% include "wgcharter/table_header.html" %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for wg in recs %}
|
||||
{% include "wgcharter/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endblock content %}
|
|
@ -1,144 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
<form name="search_form" id="search_form" class="search_form" action="/wgcharter/search/" method="get">
|
||||
|
||||
<div class="search_field">
|
||||
<label>Name/acronym:</label> {{ form.nameacronym }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label>Types:</label>
|
||||
<table id="search_types">
|
||||
<tr><td>{{ form.inprocess }} WGs (in chartering process)</td></tr>
|
||||
<tr><td>{{ form.active }} WGs (approved charter)</td></tr>
|
||||
<tr><td>{{ form.concluded }} WGs (concluded or not under review)</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<span onclick="toggleAdvanced();"><b><img src="/images/{% if meta.advanced %}minus{% else %}plus{% endif %}.png" alt="" id="search_advanced-img" /> Advanced</b></span>
|
||||
|
||||
<div id="search_advanced" style="{% if not meta.advanced %}display:none;{%endif%}margin-top:1em;">
|
||||
Additional search criteria:
|
||||
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="state" {% ifequal meta.by "state" %}checked="checked"{% endifequal %} onclick="changeBy();"/> State:</label> {{ form.state }} :: {{ form.charter_state }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="ad" {% ifequal meta.by "ad" %}checked="checked"{% endifequal %} onclick="changeBy();"/> Assigned AD:</label> {{ form.ad }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="area" {% ifequal meta.by "area" %}checked="checked"{% endifequal %} onclick="changeBy();"/> Area:</label> {{ form.area }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="anyfield" {% ifequal meta.by "anyfield" %}checked="checked"{% endifequal %} onclick="changeBy();"/> Text in any field:</label> {{ form.anyfield }}
|
||||
</div>
|
||||
<div class="search_field">
|
||||
<label><input type="radio" class="radio" name="by" value="eacronym" {% ifequal meta.by "eacronym" %}checked="checked"{% endifequal %} onclick="changeBy();"/> Earlier acronym:</label> {{ form.eacronym }}
|
||||
</div>
|
||||
</div><!-- end of advanced -->
|
||||
|
||||
<div style="padding-top:0.5em;">
|
||||
<span class="first-child">
|
||||
<button type="submit" name="search_submit" id="id_search_submit">Search</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div style="padding-top:0.5em;">
|
||||
Quick search: <a href="{% url wg_search %}?nameacronym=&inprocess=on&by=state&state=&charter_state=intrev">WGs in Internal review</a> | <a href="{% url wg_search %}?nameacronym=&inprocess=on&by=state&state=&charter_state=extrev">WGs in External review</a> | <a href="{% url wg_search %}?nameacronym=&inprocess=on&by=state&state=&charter_state=iesgrev">WGs in IESG review</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
// we want to disable our submit button if we have no search text,
|
||||
// and we have no advanced options selected
|
||||
function toggleSubmit() {
|
||||
var button = document.getElementById("id_search_submit");
|
||||
var by = findCheckedSearchBy();
|
||||
var value = findSearchByValue(by);
|
||||
var concluded = document.getElementById("id_concluded");
|
||||
var text = document.getElementById("id_nameacronym");
|
||||
if ((value == "") && (text.value == "" && concluded.checked)) {
|
||||
button.disabled = true;
|
||||
} else {
|
||||
button.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// check our button status after every change to text fields
|
||||
// Internet Explorer uses 'onpropertychange', everyone else 'oninput'
|
||||
window.oninput = toggleSubmit;
|
||||
window.onpropertychange = toggleSubmit;
|
||||
|
||||
// check our button status after every change to selection pulldowns
|
||||
window.onchange = toggleSubmit;
|
||||
|
||||
function togglePlusMinus(id) {
|
||||
var el = document.getElementById(id);
|
||||
var imgEl = document.getElementById(id+"-img");
|
||||
if (el.style.display == 'none') {
|
||||
el.style.display = 'block';
|
||||
imgEl.src = "/images/minus.png";
|
||||
} else {
|
||||
el.style.display = 'none';
|
||||
imgEl.src = "/images/plus.png";
|
||||
}
|
||||
}
|
||||
|
||||
function findCheckedSearchBy() {
|
||||
var by='';
|
||||
var f = document.search_form;
|
||||
for (var i = 0; i < f.by.length; i++) {
|
||||
if (f.by[i].checked) {
|
||||
by = f.by[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return by;
|
||||
}
|
||||
|
||||
function findSearchByValue(by) {
|
||||
if (by == 'state') {
|
||||
// state might be wg state...
|
||||
state_value = document.getElementById("id_state").value;
|
||||
if (state_value) { return state_value; }
|
||||
// ...or charter state
|
||||
return document.getElementById("id_charter_state").value;
|
||||
}
|
||||
if (by == 'ad') { return document.getElementById("id_ad").value; }
|
||||
if (by == 'area') { return document.getElementById("id_area").value; }
|
||||
if (by == 'anyfield') { return document.getElementById("id_anyfield").value; }
|
||||
if (by == 'eacronym') { return document.getElementById("id_eacronym").value; }
|
||||
return '';
|
||||
}
|
||||
|
||||
function changeBy() {
|
||||
var by=findCheckedSearchBy();
|
||||
var f = document.search_form;
|
||||
f.state.disabled=true; f.charter_state.disabled=true;
|
||||
f.ad.disabled=true;
|
||||
f.area.disabled=true;
|
||||
f.anyfield.disabled=true;
|
||||
f.eacronym.disabled=true;
|
||||
if (by=='state') { f.state.disabled=false; f.charter_state.disabled=false;}
|
||||
if (by=='ad') { f.ad.disabled=false; }
|
||||
if (by=='area') { f.area.disabled=false;}
|
||||
if (by=='anyfield') { f.anyfield.disabled=false;}
|
||||
if (by=='eacronym') { f.eacronym.disabled=false;}
|
||||
|
||||
toggleSubmit();
|
||||
}
|
||||
|
||||
function toggleAdvanced() {
|
||||
togglePlusMinus("search_advanced");
|
||||
var f = document.search_form;
|
||||
for (var i = 0; i < f.by.length; i++) { f.by[i].checked = false; }
|
||||
changeBy();
|
||||
}
|
||||
|
||||
changeBy();
|
||||
|
||||
//]]>
|
||||
</script>
|
|
@ -1,25 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% comment %}
|
||||
Copyright 2011 The IETF Trust. All rights reserved.
|
||||
{% endcomment %}
|
||||
|
||||
{% block title %}Working Group Charters{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Working Group Charters</h1>
|
||||
|
||||
<div class="ietf-box search_form_box">
|
||||
{% include "wgcharter/search_form.html" %}
|
||||
</div>
|
||||
|
||||
<div id="search_results">
|
||||
{% if meta.searching %}
|
||||
{% include "wgcharter/search_results.html" %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
{% block scripts %}
|
||||
YAHOO.util.Event.onContentReady("search_submit_button", function () {
|
||||
var oButton = new YAHOO.widget.Button("search_submit_button", {});
|
||||
});
|
||||
{% endblock scripts %}
|
|
@ -1,13 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
<tr class="{% cycle oddrow,evenrow %}">
|
||||
<td class="acronym">
|
||||
<a href="{% url wg_view name=wg.acronym %}">{{ wg.acronym|safe }}</a>
|
||||
</td>
|
||||
<td class="title">{{ wg.name }}</td>
|
||||
{% include "wgcharter/date_column.html" %}
|
||||
{% include "wgcharter/status_columns.html" %}
|
||||
</tr>
|
|
@ -1,22 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% if meta.max %}
|
||||
<p><b>Too many WGs match the query! Returning partial result only.</b></p>
|
||||
{% endif %}
|
||||
{% if not recs %}
|
||||
<p><b>No WGs match your query.</b></p>
|
||||
{% else %}
|
||||
<table class="ietf-table ietf-doctable">
|
||||
<tr>
|
||||
{% for hdr in meta.hdrs %}
|
||||
{% include "wgcharter/table_header.html" %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for wg in recs %}
|
||||
{% include "wgcharter/search_result_row.html" %}
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
{% endif %}
|
|
@ -1,40 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
{% load ietf_filters %}
|
||||
{% block title %}Send ballot position email for {{ ad }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
form.send-ballot pre {
|
||||
margin: 0;
|
||||
padding: 4px;
|
||||
border-top: 4px solid #eee;
|
||||
border-bottom: 4px solid #eee;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Send ballot position email for {{ ad }}</h1>
|
||||
|
||||
<form class="send-ballot" action="" method="POST">
|
||||
<table>
|
||||
<tr><th>From:</th> <td>{{ frm }}</td></tr>
|
||||
<tr><th>To:</th> <td>{{ to }}</td></tr>
|
||||
<tr>
|
||||
<th>Cc:<br/>
|
||||
<span class="help">separated<br/> by comma</span></th>
|
||||
<td><input type="text" name="cc" value="" size="75" /></td>
|
||||
</tr>
|
||||
<tr><th>Subject:</th> <td>{{ subject }}</td></tr>
|
||||
<tr>
|
||||
<th>Body:</th>
|
||||
<td><pre>{{ body|wrap_text }}</pre></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{{ back_url }}">Back</a>
|
||||
<input type="submit" value="Send"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -1,17 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
{% load ietf_filters ietf_streams %}{% load wg_ballot_icon %}
|
||||
<td class="status">
|
||||
{% if wg.charter %}
|
||||
{{ wg.charter.get_state|safe }} {% ifequal wg.state_id "proposed" %}{% ifnotequal wg.charter.get_state_slug "notrev" %}(Initial Chartering){% endifnotequal %}{% else %}{% ifequal wg.state_id "active" %}{% ifnotequal wg.charter.get_state_slug "approved" %}(Rechartering){% endifnotequal %}{% endifequal %}{% ifequal wg.state_id "conclude" %}(Concluded){% endifequal %}{% endifequal %}
|
||||
{% else %}
|
||||
(data missing)
|
||||
{% endif %}
|
||||
{% if wg.charter.telechat_date %}<br/>IESG Telechat: {{ wg.charter.telechat_date }}{% endif %}
|
||||
|
||||
{% block extra_status %}{% endblock %}
|
||||
</td>
|
||||
<td class="ballot">
|
||||
{% if wg.charter.get_state_slug == "iesgrev" %}{% wg_ballot_icon wg.acronym %}{% endif %}
|
||||
</td>
|
|
@ -30,7 +30,7 @@ Charter submission for {{ wg.acronym }}
|
|||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url wg_view name=wg.acronym %}">Back</a>
|
||||
<a href="{% url doc_view name=wg.charter.name %}">Back</a>
|
||||
<input type="submit" value="Submit"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
{# Copyright The IETF Trust 2011, All Rights Reserved #}
|
||||
|
||||
<th class="{{hdr.htype}}"{% if hdr.colspan %}colspan="{{ hdr.colspan }}" {% endif %}
|
||||
onclick="location=unescape('{{ meta.rqps }}&sortBy={{hdr.htype}}');"
|
||||
style="white-space: nowrap;"
|
||||
>
|
||||
<span>
|
||||
<label>{{hdr.htitle}}</label>
|
||||
{% if hdr.selected %}
|
||||
<img style="border-style: none;vertical-align:top" src="/images/sort-header-filled.png"/>
|
||||
{% else %}
|
||||
<img style="border-style: none;vertical-align:top" src="/images/sort-header-clear.png"/>
|
||||
{% endif %}
|
||||
</span>
|
||||
</th>
|
|
@ -1,57 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
{% load ietf_filters %}
|
||||
<table class="ietf-ballot"><tr valign="top"><td class="left">
|
||||
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
{% if user|in_group:"Area_Director" %}
|
||||
<div style="margin-top:8px; margin-bottom:8px;"><span id="wg_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url wg_edit_position name=wg.acronym %}">Edit position</a></span></span></div>
|
||||
{% endif %}
|
||||
{% if user|in_group:"Secretariat" %}
|
||||
{% if not info.pos_block %}<div style="margin-top:8px; margin-bottom:8px;"><span id="wg_ballot_button" class="yui-button yui-link-button"><span class="first-child"><a href="{% url wg_approve_ballot name=wg.acronym %}">Approve ballot</a></span></span></div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<p style="margin-top:1em;"><span class="square" style="background:#c00000;"></span><b>Blocking</b><br/>
|
||||
{% with info.pos_block as positions %}{% include "wgcharter/wg_ballot_list.html" %}{% endwith %}</p>
|
||||
|
||||
<p><span class="square" style="background:#80ff80;"></span><b>Yes</b><br/>
|
||||
{% with info.pos_yes as positions %}{% include "wgcharter/wg_ballot_list.html" %}{% endwith %}</p>
|
||||
|
||||
<p><span class="square" style="background:#80ff80;"></span><b>No</b><br/>
|
||||
{% with info.pos_no as positions %}{% include "wgcharter/wg_ballot_list.html" %}{% endwith %}</p>
|
||||
|
||||
<p><span class="square" style="background:#ffff00;"></span><b>Abstain</b><br/>
|
||||
{% with info.pos_abstain as positions %}{% include "wgcharter/wg_ballot_list.html" %}{% endwith %}</p>
|
||||
|
||||
<p><span class="square" style="background:white;"></span><b>No Record</b><br/>
|
||||
{% for p in info.pos_no_record %}
|
||||
<a{% if user|in_group:"Secretariat" %} href="{% url wg_edit_position name=wg.acronym %}?ad={{ p.id }}" title="Click to edit the position of {{ p.name }}"{% endif %}>{{p.name}}{% if user|in_group:"Secretariat" %}</a>{% endif %}<br/>
|
||||
{% empty %}
|
||||
<i>none</i>
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
||||
</td>
|
||||
<td class="right">
|
||||
|
||||
<h2 style="margin-top:12px;">Comments</h2>
|
||||
|
||||
{% for pos in info.positions %}
|
||||
{% if pos.comment or pos.block_comment %}
|
||||
<h2 class="ballot_ad"><a name="{{pos.ad|slugify}}">{{pos.ad|escape}}</a></h2>
|
||||
|
||||
{% if pos.block_comment %}
|
||||
<p><b>Blocking ({{pos.block_comment_time}})</b> <img src="/images/comment.png" width="14" height="12" alt=""/></p>
|
||||
<pre>{{pos.block_comment|fill:"80"|escape }}</pre>
|
||||
{% endif %}
|
||||
|
||||
{% if pos.comment %}
|
||||
<p><b>Comment ({{pos.comment_time}})</b> <img src="/images/comment.png" width="14" height="12" alt=""/></p>
|
||||
<pre>{{pos.comment|fill:"80"|escape }}</pre>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td></tr></table>
|
|
@ -1,6 +0,0 @@
|
|||
{% load ietf_filters %}
|
||||
{% for p in positions %}
|
||||
{% for oad in info.old_ads %}{% ifequal oad p.ad %}[{%endifequal%}{% endfor %}<a{% if user|in_group:"Secretariat" %} href="{% url wg_edit_position name=wg.acronym %}?ad={{ p.ad_id }}" title="Click to edit the position of {{ p.ad }}"{% endif %}>{{p.ad}}</a>{% for oad in info.old_ads %}{% ifequal oad p.ad %}]{%endifequal%}{% endfor %}{% if p.comment or p.block_comment %} <a href="#{{p.ad|slugify}}"><img src="/images/comment.png" width="14" height="12" alt="*" border="0"/></a>{% endif %}<br/>
|
||||
{% empty %}
|
||||
<i>none</i>
|
||||
{% endfor %}
|
|
@ -1 +0,0 @@
|
|||
IETF Working Group {{ wg.name }} ({{ wg.acronym }}){% if wg.parent %} under the {{ wg.parent }}{% endif %}
|
|
@ -1,40 +0,0 @@
|
|||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
<table class="ietf-table">
|
||||
<tr><th class="comment_date">Date</th><th>Version</th><th>By</th><th>Text</th></tr>
|
||||
|
||||
{% for c in history %}
|
||||
<tr class="{% cycle oddrow,evenrow %}"{% if c.is_com %} id="history-{{c.comment.id }}"{% endif %}>
|
||||
<td class="comment_date">{{ c.date|date:"Y-m-d" }}</td>
|
||||
|
||||
{% if c.is_rev %}
|
||||
<td>{{ c.info.version }}</td>
|
||||
<td>(System)</td>
|
||||
<td>New version available: <a href="{{ c.txt_url }}charter-ietf-{{ c.group.acronym }}-{{c.charter.rev}}.txt">charter-ietf-{{ c.group.acronym }}-{{ c.charter.rev }}</a> {% if c.prev_charter %}(<a href="http://tools.ietf.org/rfcdiff?url1={{ c.txt_url }}charter-ietf-{{ c.group.acronym }}-{{c.charter.rev}}.txt&url2={{ c.txt_url }}charter-ietf-{{ c.prev_group.acronym }}-{{c.prev_charter.rev}}.txt">diff from -{{ c.prev_charter.rev }}</a>){% endif %}</td>
|
||||
{% endif %}
|
||||
|
||||
{% if c.is_com %}
|
||||
<td>{{ c.info.version }}</td>
|
||||
<td>{{ c.info.by|escape }}</td>
|
||||
<td>{% if c.comment.ballot %}
|
||||
[Ballot {{ c.comment.get_ballot_display }}]<br />
|
||||
{% endif %}
|
||||
{% if c.info.snipped %}
|
||||
<div id="commentS{{c.comment.id}}">{{ c.info.textSnippet|safe }}</div>
|
||||
<span class="comment_toggle" onclick="toggleComment({{c.comment.id}})" id="commentT{{c.comment.id}}">[show all]</span>
|
||||
<div id="commentF{{c.comment.id}}" style="display:none;">
|
||||
{{ c.info.text|fill:"80"|safe|urlize|linebreaksbr|keep_spacing|sanitize_html|safe }}
|
||||
</div>
|
||||
{% else %}
|
||||
{{ c.info.text|fill:"80"|safe|urlize|linebreaksbr|keep_spacing|sanitize_html|safe }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endif %}
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
|
@ -1,72 +0,0 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
{% block morecss %}
|
||||
.metabox { width: 99%; margin-top:8px; padding:4px; margin-bottom:1em; }
|
||||
#metatable { border: 0; border-spacing: 0; }
|
||||
#metatable tr { vertical-align:top ;}
|
||||
.comment_toggle { text-decoration: underline; color: blue; }
|
||||
.comment_date { white-space: nowrap; }
|
||||
|
||||
div.diffTool { padding: 8px 4px; margin: 8px 0;}
|
||||
.diffTool label { float:left; width:50px; }
|
||||
|
||||
.markup_draft pre {line-height: 1.2em; margin: 0; }
|
||||
.m_hdr, .m_ftr { color: #808080; }
|
||||
.m_ftr { border-bottom: 1px solid #a0a0a0; }
|
||||
.m_h { font-family: arial; font-weight:bold;}
|
||||
.ietf-concluded-bg {background-color: #F8F8D0; }
|
||||
.ietf-concluded-warning { background:red;color:white;padding:2px 2px;}
|
||||
.ietf-proposed-bg { }
|
||||
.ietf-proposed-warning { background:green;color:white;padding:2px 2px;}
|
||||
{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
<link rel="alternate" type="application/atom+xml" href="/feed/wgcomments/{{ wg.acronym }}/" />
|
||||
<meta name="description" content="{% include "wgcharter/wg_description.html" %}" />
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{% include "wgcharter/wg_title.html" %}{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% include "wgcharter/wg_title.html" %}
|
||||
{% ifequal wg.state_id "conclude" %}<br/><span class="ietf-concluded-warning">(concluded WG)</span>{% endifequal %}
|
||||
{% ifequal wg.state_id "proposed" %}<br/><span class="ietf-proposed-warning">(proposed WG)</span>{% endifequal %}
|
||||
</h1>
|
||||
|
||||
<div id="mytabs" class="yui-navset">
|
||||
<ul class="yui-nav">
|
||||
<li{% ifequal tab "charter" %} class="selected"{% endifequal %}><a href="/wgcharter/{{ wg.acronym }}"><em>Charter {% if snapshot %}(snapshot){% endif %}</em></a></li>
|
||||
<li{% if wg.charter %}{% ifequal wg.charter.get_state_slug "iesgrev" %}{% ifequal tab "ballot" %} class="selected"{% endifequal %}{%else%} class="disabled"{%endifequal%}{% else %} class="disabled"{% endif %}{% if snapshot %} class="disabled"{% endif %}><a href="/wgcharter/{{ wg.acronym }}/ballot/"><em>IESG Review</em></a></li>
|
||||
<li{% if wg.charter %}{% ifequal tab "writeup" %} class="selected"{% endifequal %}{% ifequal wg.charter.get_state_slug "notrev" %} class="disabled"{%endifequal%}{% else %} class="disabled"{% endif %}{% if snapshot %} class="disabled"{% endif %}><a href="/wgcharter/{{ wg.acronym }}/writeup/"><em>IESG Writeups</em></a></li>
|
||||
<li{% ifequal tab "history" %} class="selected"{% endifequal %}{% if snapshot %} class="disabled"{% endif %}><a href="/wgcharter/{{ wg.acronym }}/history/"><em>History</em></a></li>
|
||||
</ul>
|
||||
<div class="yui-content">
|
||||
|
||||
{% block tab_content %}{% endblock %}
|
||||
|
||||
</div> <!-- yui-content -->
|
||||
</div> <!-- mytabs -->
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block scripts %}
|
||||
function toggleComment(n) {
|
||||
var el = document.getElementById("commentF"+n);
|
||||
var el2 = document.getElementById("commentS"+n);
|
||||
var el3 = document.getElementById("commentT"+n);
|
||||
if (el.style.display == 'none') {
|
||||
el.style.display = 'block';
|
||||
el2.style.display = 'none';
|
||||
el3.innerHTML = ""; //[hide]";
|
||||
} else {
|
||||
el.style.display = 'none';
|
||||
el2.style.display= 'block';
|
||||
el3.innerHTML = "[show all]";
|
||||
}
|
||||
}
|
||||
{% endblock scripts %}
|
|
@ -1,11 +0,0 @@
|
|||
{% extends "wgcharter/wg_main.html" %}
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block tab_content %}
|
||||
{% include "wgcharter/wg_ballot.html" %}
|
||||
{% endblock tab_content %}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
{% extends "wgcharter/wg_main.html" %}
|
||||
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block tab_content %}
|
||||
{% block wg_revision %}{% endblock %}
|
||||
<div class="ietf-box metabox">
|
||||
<table id="metatable" width="100%">
|
||||
{% block wg_metatable %}{% endblock %}
|
||||
</table>
|
||||
|
||||
<div style="padding-top:6px;padding-bottom:6px;padding-left:2px;">
|
||||
{% block wg_metalinks %}{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block wg_metabuttons %}
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
{% if not snapshot %}
|
||||
<div style="padding-bottom:2px;">
|
||||
{% if wg.charter.get_state_slug != "notrev" and wg.charter.get_state_slug != "approved" %}
|
||||
<span id="wg_edit_state_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_startstop_process name=wg.acronym option='abandon' %}">Abandon effort</a></span></span>
|
||||
<span id="wg_edit_state_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_change_state name=wg.acronym %}">Change state</a></span></span>
|
||||
{% ifnotequal wg.state_id "conclude" %}
|
||||
<span id="wg_edit_info_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_submit name=wg.acronym %}">Edit charter</a></span></span>
|
||||
{% endifnotequal %}
|
||||
{% else %}
|
||||
<span id="wg_edit_state_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_startstop_process name=wg.acronym option='recharter' %}">Recharter</a></span></span>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endif %}{# if not snapshot #}
|
||||
{% endif %}{# if user in group #}
|
||||
{% endblock wg_metabuttons%}
|
||||
</div> <!-- metabox -->
|
||||
|
||||
<div id="charterText">
|
||||
{% block charter_text %}{% endblock %}
|
||||
</div> <!-- charterText -->
|
||||
{% endblock tab_content %}
|
||||
|
||||
{% block content_end %}
|
||||
{% endblock content_end %}
|
|
@ -1,81 +0,0 @@
|
|||
{% extends "wgcharter/wg_tab_base.html" %}
|
||||
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block wg_revision %}
|
||||
Snapshots: {% for d in versions reversed %}{% if forloop.first %}<strong>{% ifnotequal rev wg.charter.rev %}<a href="{% url wg_view name=wg.acronym %}">{% endifnotequal %}{% else %}{% ifnotequal rev d.rev %}{% ifequal d.rev wg.charter.rev %}<a href="{% url wg_view name=wg.acronym %}">{% else %}<a href="{% url wg_view name=wg.acronym %}{{d.rev}}/">{% endifequal %}{% endifnotequal %}{% endif %}{{ d.rev }}{% ifnotequal rev d.rev %}</a>{% endifnotequal %}{% if forloop.first %}{% ifnotequal rev wg.charter.rev %}</a>{% endifnotequal %}</strong>{% endif %} {% endfor %}
|
||||
{% endblock %}
|
||||
|
||||
{% block wg_metatable %}
|
||||
<tr><td style="width: 15em">WG name:</td><td>{% if not snapshot %}{{ wg.name }}{% else %} {{ gh.name }} {% endif %}</td></tr>
|
||||
<tr><td>WG acronym:</td><td>{% if not snapshot %}{{ wg.acronym }} {% if info.prev_acronyms %}(previous acronyms: {% for a in info.prev_acronyms %}{{ a }}{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}{% else %}{{ gh.acronym }}{% endif %}</td></tr>
|
||||
<tr><td>IETF area:</td><td>{% if not snapshot %}{{ wg.parent|default:"-" }}{% else %}{{ gh.parent|default:"-" }}{% endif %}</td></tr>
|
||||
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
<tr><td>WG chairs:</td><td>{% if not snapshot %}{% for n in info.chairs %}{{ n }}{% if not forloop.last %}, {% endif %}{% endfor %}{% else %}{% for n in info.history_chairs %}{{ n }}{% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}</td></tr>
|
||||
{% if not snapshot %}
|
||||
<tr><td>WG secretaries:</td><td>{% for n in info.secr %}{{ n }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
|
||||
<tr><td>WG technical advisors:</td><td>{% for n in info.techadv %}{{ n }}{% if not forloop.last %}, {% endif %}{% endfor %}</td></tr>
|
||||
{% endif %}
|
||||
<tr><td>Assigned AD:</td><td>{% if not snapshot %}{{ wg.ad }}{% else %}{{ gh.ad }}{% endif %}</td></tr>
|
||||
|
||||
{% if not snapshot %}
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
<tr><td>Mailing list:</td><td><a href="mailto:{{ wg.list_email }}">{{ wg.list_email }}</a>{% if info.prev_list_email %}<br />(previous lists: {% for a in info.prev_list_email %}{{ a }}{% if not forloop.last %}, {% else %}){% endif %}{% endfor %}{% endif %}</td></tr>
|
||||
<tr><td>Mailing list subscribe:</td><td><a href="{{ wg.list_subscribe }}">{{ wg.list_subscribe }}</a>{% if info.prev_list_subscribe %}<br />(previous archives: {% for a in info.prev_list_subscribe %}<a href="{{ a }}">{{ a }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}</td></tr>
|
||||
<tr><td>Mailing list archive:</td><td><a href="{{ wg.list_archive }}">{{ wg.list_archive }}</a>{% if info.prev_list_archive %}<br />(previous archives: {% for a in info.prev_list_archive %}<a href="{{ a }}">{{ a }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}){% endif %}</td></tr>
|
||||
<tr><td>Other web sites:</td><td>{% for a in wg.groupurl_set.all %}<a href="{{ a.url }}">{{ a.url }}</a> {% if a.name %}({{ a.name }}){% endif %}{% if not forloop.last %}<br />{% endif %}{% endfor %}</td></tr>
|
||||
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
<tr><td>WG State:</td><td> {{ wg.state|safe }} </td>
|
||||
{% ifnotequal wg.state_id "conclude" %}<tr><td><a href="/wgcharter/help/state/">Charter State</a>:</td><td> {{ wg.charter.get_state|safe }} {% ifequal wg.state_id "proposed" %}{% ifnotequal wg.charter.get_state_slug "notrev" %}(Initial Chartering){% endifnotequal %}{% else %}{% ifnotequal wg.charter.get_state_slug "approved" %}(Rechartering){% endifnotequal %}{% endifequal %}</td>{% endifnotequal %}
|
||||
{% ifequal wg.state_id "proposed" %}
|
||||
{% if wg.comments %}
|
||||
<tr><td>Reason for chartering:</td><td>{{ wg.comments }}</td></tr>
|
||||
{% endif %}
|
||||
{% endifequal %}
|
||||
{% ifequal wg.state_id "active" %}
|
||||
{% ifnotequal wg.charter.get_state_slug "approved" %}
|
||||
{% if wg.comments %}
|
||||
<tr><td>Reason for rechartering:</td><td>{{ wg.comments }}</td></tr>
|
||||
{% endif %}
|
||||
{% endifnotequal %}
|
||||
{% endifequal %}
|
||||
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
<tr><td>Last updated:</td><td> {{ info.last_update|date:"Y-m-d"|default:"(data missing)" }}</td></tr>
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
{% endif %}{# if not snapshot #}
|
||||
|
||||
{% endblock wg_metatable %}
|
||||
|
||||
{% block wg_metalinks %}
|
||||
{% if not snapshot %}
|
||||
<a href="/feed/wgcomments/{{ wg.acronym }}/">Atom feed</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block charter_text %}
|
||||
{% ifnotequal charter.rev "" %}
|
||||
<p>Other versions: <a href="{{ charter_text_url }}{{charter.name}}-{{rev}}.txt">plain text</a></p>
|
||||
|
||||
<h3>Charter {{ charter.name }}-{{ rev }}</h3>
|
||||
|
||||
<div class="markup_draft">
|
||||
{{ content|fill:"80"|safe|linebreaksbr|keep_spacing|sanitize_html|safe }}
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
<h3>The WG does not yet have a charter</h3>
|
||||
{% endifnotequal %}
|
||||
{% endblock %}{# charter_text #}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
{% extends "wgcharter/wg_main.html" %}
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block tab_content %}
|
||||
{% include "wgcharter/charter_diffs.html" %}
|
||||
<h2 style="margin-top:1em;">WG History</h2>
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
<div style="margin-bottom:8px" id="history_actions">
|
||||
<span id="wg_add_comment_button" class="yui-button yui-link-button" style="margin-left:2px;"><span class="first-child"><a href="{% url wg_add_comment name=wg.acronym %}">Add comment</a></span></span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% include "wgcharter/wg_history.html" %}
|
||||
{% endblock tab_content %}
|
|
@ -1,52 +0,0 @@
|
|||
{% extends "wgcharter/wg_main.html" %}
|
||||
{% comment %}
|
||||
Copyright The IETF Trust 2011, All Rights Reserved
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
{% block tab_content %}
|
||||
<h3>WG Review Announcement</h3>
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
<div style="background:#E0E0FF">
|
||||
<p align=right>
|
||||
<span id="wg_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
|
||||
<a href="{% url wg_announcement_text name=wg.acronym ann="review" %}">Edit WG Review Announcement</a>
|
||||
</span></span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<pre>
|
||||
{{ info.review_text|escape|urlize }}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<h3>WG Action Announcement</h3>
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
<div style="background:#E0E0FF">
|
||||
<p align=right>
|
||||
<span id="wg_edit_announce_button" class="yui-button yui-link-button"><span class="first-child">
|
||||
<a href="{% url wg_announcement_text name=wg.acronym ann="action" %}">Edit WG Action Announcement</a>
|
||||
</span></span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<pre>
|
||||
{{ info.action_text|escape|urlize }}
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
|
||||
<h3>Ballot Announcement</h3>
|
||||
{% if user|in_group:"Area_Director,Secretariat" %}
|
||||
<div style="background:#E0E0FF">
|
||||
<p align=right>
|
||||
<span id="wg_edit_ballot_button" class="yui-button yui-link-button"><span class="first-child">
|
||||
<a href="{% url wg_ballot_writeupnotes name=wg.acronym %}">Edit Ballot Announcement</a>
|
||||
</span></span>
|
||||
</p>
|
||||
{% endif %}
|
||||
<pre>
|
||||
{{ info.ballot_text|escape|urlize }}
|
||||
</pre>
|
||||
|
||||
</div>
|
||||
{% endblock tab_content %}
|
|
@ -1 +0,0 @@
|
|||
{{ wg.name }} ({{wg.acronym}})
|
|
@ -11,7 +11,7 @@
|
|||
{% for s in charter_states %}{% if not forloop.first %}, {% if forloop.last %}or {% endif %}{% endif %}<i>{{ s.name }}</i>{% endfor %}.</p>
|
||||
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
<p><a href="{% url wg_create %}">Start new WG charter effort</a></p>
|
||||
<p><a href="{% url wg_create %}">Start chartering new WG</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if not groups %}
|
||||
|
|
|
@ -9,7 +9,7 @@ from ietf.idtracker.feeds import DocumentComments, InLastCall
|
|||
from ietf.ipr.feeds import LatestIprDisclosures
|
||||
from ietf.proceedings.feeds import LatestWgProceedingsActivity
|
||||
from ietf.liaisons.feeds import Liaisons
|
||||
from ietf.wgcharter.feeds import GroupComments
|
||||
from ietf.wgcharter.feeds import GroupEvents
|
||||
|
||||
from ietf.idtracker.sitemaps import IDTrackerMap, DraftMap
|
||||
from ietf.liaisons.sitemaps import LiaisonMap
|
||||
|
@ -25,7 +25,7 @@ feeds = {
|
|||
'iesg-agenda': IESGAgenda,
|
||||
'last-call': InLastCall,
|
||||
'comments': DocumentComments,
|
||||
'wgcomments': GroupComments,
|
||||
'wg': GroupEvents,
|
||||
'ipr': LatestIprDisclosures,
|
||||
'liaison': Liaisons,
|
||||
'wg-proceedings' : LatestWgProceedingsActivity
|
||||
|
|
|
@ -264,11 +264,12 @@ def make_test_data():
|
|||
)
|
||||
|
||||
# draft has only one event
|
||||
DocEvent.objects.create(
|
||||
type="started_iesg_process",
|
||||
BallotDocEvent.objects.create(
|
||||
type="created_ballot",
|
||||
ballot_type=BallotType.objects.get(doc_type="draft", slug="approve"),
|
||||
by=ad,
|
||||
doc=draft,
|
||||
desc="Added draft",
|
||||
desc="Created ballot",
|
||||
)
|
||||
|
||||
# IPR
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
|
||||
import datetime, re, os
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.syndication.feeds import Feed, FeedDoesNotExist
|
||||
from django.utils.feedgenerator import Atom1Feed
|
||||
|
@ -8,12 +10,53 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from ietf.utils.history import find_history_active_at
|
||||
|
||||
from ietf.group.models import Group
|
||||
from ietf.wgcharter.views import _get_history, _get_html
|
||||
from ietf.wgcharter import markup_txt
|
||||
import datetime
|
||||
import re, os
|
||||
|
||||
class GroupComments(Feed):
|
||||
def _get_history(wg, versions=None):
|
||||
results = []
|
||||
for e in wg.charter.docevent_set.all().order_by('-time'):
|
||||
info = {}
|
||||
charter_history = find_history_active_at(wg.charter, e.time)
|
||||
info['version'] = charter_history.rev if charter_history else wg.charter.rev
|
||||
info['text'] = e.desc
|
||||
info['by'] = e.by.plain_name()
|
||||
info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25)
|
||||
info['snipped'] = info['textSnippet'][-3:] == "..."
|
||||
if e.type == "new_revision":
|
||||
if charter_history:
|
||||
charter = get_charter_for_revision(wg.charter, charter_history.rev)
|
||||
group = get_group_for_revision(wg, charter_history.rev)
|
||||
else:
|
||||
charter = get_charter_for_revision(wg.charter, wg.charter.rev)
|
||||
group = get_group_for_revision(wg, wg.charter.rev)
|
||||
|
||||
if versions:
|
||||
vl = [x['rev'] for x in versions]
|
||||
if vl:
|
||||
prev_charter = get_charter_for_revision(wg.charter, vl[vl.index(charter.rev) - 1])
|
||||
else:
|
||||
prev_charter = get_charter_for_revision(wg.charter, prev_revision(charter.rev))
|
||||
prev_group = get_group_for_revision(wg, prev_revision(charter.rev))
|
||||
results.append({'comment':e, 'info':info, 'date':e.time, 'group': group,
|
||||
'charter': charter, 'prev_charter': prev_charter,
|
||||
'prev_group': prev_group,
|
||||
'txt_url': settings.CHARTER_TXT_URL,
|
||||
'is_rev':True})
|
||||
else:
|
||||
results.append({'comment':e, 'info':info, 'date':e.time, 'group': wg, 'is_com':True})
|
||||
|
||||
# convert plain dates to datetimes (required for sorting)
|
||||
for x in results:
|
||||
if not isinstance(x['date'], datetime):
|
||||
if x['date']:
|
||||
x['date'] = datetime.combine(x['date'], time(0,0,0))
|
||||
else:
|
||||
x['date'] = datetime(1970,1,1)
|
||||
|
||||
results.sort(key=lambda x: x['date'])
|
||||
results.reverse()
|
||||
return results
|
||||
|
||||
class GroupEvents(Feed):
|
||||
feed_type = Atom1Feed
|
||||
title_template = "feeds/wg_charter_title.html"
|
||||
description_template = "feeds/wg_charter_description.html"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# generation of mails
|
||||
|
||||
import textwrap
|
||||
from datetime import datetime, date, time, timedelta
|
||||
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.html import strip_tags
|
||||
|
@ -11,7 +10,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from ietf.utils.mail import send_mail, send_mail_text
|
||||
from ietf.idtracker.models import *
|
||||
from ietf.ipr.search import iprs_from_docs
|
||||
from ietf.doc.models import WriteupDocEvent, DocAlias, GroupBallotPositionDocEvent
|
||||
from ietf.doc.models import WriteupDocEvent, DocAlias
|
||||
from ietf.person.models import Person
|
||||
|
||||
def email_secretariat(request, wg, type, text):
|
||||
|
@ -33,7 +32,10 @@ def email_secretariat(request, wg, type, text):
|
|||
send_mail(request, to, None, subject,
|
||||
"wgcharter/email_secretariat.txt",
|
||||
dict(text=text,
|
||||
url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=wg.acronym))))
|
||||
wg_url=settings.IDTRACKER_BASE_URL + urlreverse('wg_charter', kwargs=dict(acronym=wg.acronym)),
|
||||
charter_url=settings.IDTRACKER_BASE_URL + urlreverse('doc_view', kwargs=dict(name=wg.charter.name)),
|
||||
)
|
||||
)
|
||||
|
||||
def generate_ballot_writeup(request, doc):
|
||||
e = WriteupDocEvent()
|
||||
|
@ -47,6 +49,7 @@ def generate_ballot_writeup(request, doc):
|
|||
return e
|
||||
|
||||
def generate_issue_ballot_mail(request, charter):
|
||||
raise NotImplemented
|
||||
active_ads = Person.objects.filter(email__role__name="ad", email__role__group__state="active").distinct()
|
||||
|
||||
e = charter.latest_event(type="started_iesg_process")
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
||||
# All rights reserved. Contact: Pasi Eronen <pasi.eronen@nokia.com>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
#
|
||||
# * Neither the name of the Nokia Corporation and/or its
|
||||
# subsidiary(-ies) nor the names of its contributors may be used
|
||||
# to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from django.utils.html import escape
|
||||
import string
|
||||
import re
|
||||
|
||||
def markup(content):
|
||||
# normalize line endings to LF only
|
||||
content = content.replace("\r\n", "\n")
|
||||
content = content.replace("\r", "\n")
|
||||
|
||||
# at this point, "content" is normal string
|
||||
# fix most common non-ASCII characters
|
||||
t1 = string.maketrans("\x91\x92\x93\x94\x95\x96\x97\xc6\xe8\xe9", "\'\'\"\"o--\'ee")
|
||||
# map everything except printable ASCII, TAB, LF, FF to "?"
|
||||
t2 = string.maketrans('','')
|
||||
t3 = "?"*9 + "\t\n?\f" + "?"*19 + t2[32:127] + "?"*129
|
||||
t4 = t1.translate(t3)
|
||||
content = content.translate(t4)
|
||||
|
||||
# remove leading white space
|
||||
content = content.lstrip()
|
||||
# remove runs of blank lines
|
||||
content = re.sub("\n\n\n+", "\n\n", content)
|
||||
|
||||
# expand tabs + escape
|
||||
content = escape(content.expandtabs())
|
||||
|
||||
content = re.sub("\n(.+\[Page \d+\])\n\f\n(.+)\n", """\n<span class="m_ftr">\g<1></span>\n<span class="m_hdr">\g<2></span>\n""", content)
|
||||
content = re.sub("\n(.+\[Page \d+\])\n\s*$", """\n<span class="m_ftr">\g<1></span>\n""", content)
|
||||
# remove remaining FFs (to be valid XHTML)
|
||||
content = content.replace("\f","\n")
|
||||
|
||||
content = re.sub("\n\n([0-9]+\\.|[A-Z]\\.[0-9]|Appendix|Status of|Abstract|Table of|Full Copyright|Copyright|Intellectual Property|Acknowled|Author|Index)(.*)(?=\n\n)", """\n\n<span class="m_h">\g<1>\g<2></span>""", content)
|
||||
|
||||
return "<pre>"+content+"</pre>\n"
|
0
ietf/wgcharter/models.py
Normal file
0
ietf/wgcharter/models.py
Normal file
|
@ -58,28 +58,28 @@ class EditCharterTestCase(django.test.TestCase):
|
|||
self.assertEquals(charter.get_state(), first_state)
|
||||
|
||||
# change state
|
||||
for slug in ("intrev", "extrev", "iesgrev", "approved"):
|
||||
for slug in ("intrev", "extrev", "iesgrev"):
|
||||
s = State.objects.get(type="charter", slug=slug)
|
||||
events_before = charter.docevent_set.count()
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
r = self.client.post(url, dict(state="active", charter_state=s.pk, message="test message"))
|
||||
r = self.client.post(url, dict(charter_state=str(s.pk), message="test message"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
charter = Document.objects.get(name="charter-ietf-%s" % group.acronym)
|
||||
self.assertEquals(charter.get_state_slug(), slug)
|
||||
self.assertEquals(charter.docevent_set.count(), events_before + 1)
|
||||
self.assertTrue("State changed" in charter.docevent_set.all()[0].desc)
|
||||
self.assertTrue(charter.docevent_set.count() > events_before)
|
||||
if slug in ("intrev", "iesgrev"):
|
||||
self.assertEquals(charter.docevent_set.all()[0].type, "created_ballot")
|
||||
self.assertTrue("State changed" in charter.docevent_set.all()[1].desc)
|
||||
else:
|
||||
self.assertTrue("State changed" in charter.docevent_set.all()[0].desc)
|
||||
if slug == "extrev":
|
||||
self.assertEquals(len(outbox), mailbox_before + 2)
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("State changed" in outbox[-1]['Subject'])
|
||||
self.assertTrue("State changed" in outbox[-2]['Subject'])
|
||||
else:
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
if slug == "approved":
|
||||
self.assertTrue("Charter approved" in outbox[-1]['Subject'])
|
||||
else:
|
||||
self.assertTrue("State changed" in outbox[-1]['Subject'])
|
||||
self.assertTrue("State changed" in outbox[-1]['Subject'])
|
||||
|
||||
def test_edit_telechat_date(self):
|
||||
make_test_data()
|
||||
|
@ -145,158 +145,6 @@ class EditCharterTestCase(django.test.TestCase):
|
|||
self.assertEquals(charter.rev, next_revision(prev_rev))
|
||||
self.assertTrue("new_revision" in charter.latest_event().type)
|
||||
|
||||
class CharterPositionTestCase(django.test.TestCase):
|
||||
fixtures = ['names', 'ballot']
|
||||
|
||||
def test_edit_position(self):
|
||||
make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
charter = group.charter
|
||||
|
||||
url = urlreverse('wg_edit_position', kwargs=dict(name=group.acronym))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
p = Person.objects.get(name="Aread Irector")
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = p
|
||||
e.doc = charter
|
||||
e.desc = "IESG process started"
|
||||
e.save()
|
||||
|
||||
charter.set_state(State.objects.get(type="charter", slug="iesgrev"))
|
||||
charter.save()
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form input[name=position]')) > 0)
|
||||
self.assertEquals(len(q('form textarea[name=comment]')), 1)
|
||||
|
||||
# vote
|
||||
pos_before = charter.docevent_set.filter(type="changed_ballot_position").count()
|
||||
self.assertTrue(not charter.docevent_set.filter(type="changed_ballot_position", by__name="Aread Irector"))
|
||||
|
||||
r = self.client.post(url, dict(position="block",
|
||||
block_comment="This is a blocking test.",
|
||||
comment="This is a test."))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(charter.docevent_set.filter(type="changed_ballot_position").count(), pos_before + 1)
|
||||
e = charter.latest_event(GroupBallotPositionDocEvent)
|
||||
self.assertTrue("This is a blocking test." in e.block_comment)
|
||||
self.assertTrue("This is a test." in e.comment)
|
||||
self.assertTrue(e.pos_id, "block")
|
||||
|
||||
# recast vote
|
||||
pos_before = charter.docevent_set.filter(type="changed_ballot_position").count()
|
||||
|
||||
r = self.client.post(url, dict(position="yes"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(charter.docevent_set.filter(type="changed_ballot_position").count(), pos_before + 1)
|
||||
e = charter.latest_event(GroupBallotPositionDocEvent)
|
||||
self.assertTrue(e.pos_id, "yes")
|
||||
|
||||
# clear vote
|
||||
pos_before = charter.docevent_set.filter(type="changed_ballot_position").count()
|
||||
|
||||
r = self.client.post(url, dict(position="norecord"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(charter.docevent_set.filter(type="changed_ballot_position").count(), pos_before + 1)
|
||||
e = charter.latest_event(GroupBallotPositionDocEvent)
|
||||
self.assertTrue(e.pos_id, "norecord")
|
||||
|
||||
def test_edit_position_as_secretary(self):
|
||||
make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
charter = group.charter
|
||||
|
||||
url = urlreverse('wg_edit_position', kwargs=dict(name=group.acronym))
|
||||
p = Person.objects.get(name="Aread Irector")
|
||||
url += "?ad=%d" % p.id
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = p
|
||||
e.doc = charter
|
||||
e.desc = "IESG process started"
|
||||
e.save()
|
||||
|
||||
charter.set_state(State.objects.get(type="charter", slug="iesgrev"))
|
||||
charter.save()
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form input[name=position]')) > 0)
|
||||
|
||||
# vote for AD
|
||||
pos_before = charter.docevent_set.filter(type="changed_ballot_position").count()
|
||||
self.assertTrue(not charter.docevent_set.filter(type="changed_ballot_position", by__name="Sec Retary"))
|
||||
|
||||
r = self.client.post(url, dict(position="no"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(charter.docevent_set.filter(type="changed_ballot_position").count(), pos_before + 1)
|
||||
e = charter.latest_event(GroupBallotPositionDocEvent)
|
||||
self.assertTrue(e.pos_id, "no")
|
||||
|
||||
def test_send_ballot_comment(self):
|
||||
make_test_data()
|
||||
|
||||
group = Group.objects.get(acronym="mars")
|
||||
charter = group.charter
|
||||
|
||||
url = urlreverse('wg_send_ballot_comment', kwargs=dict(name=group.acronym))
|
||||
login_testing_unauthorized(self, "ad", url)
|
||||
|
||||
p = Person.objects.get(name="Aread Irector")
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = p
|
||||
e.doc = charter
|
||||
e.desc = "IESG process started"
|
||||
e.save()
|
||||
|
||||
charter.set_state(State.objects.get(type="charter", slug="iesgrev"))
|
||||
charter.save()
|
||||
|
||||
GroupBallotPositionDocEvent.objects.create(
|
||||
doc=charter,
|
||||
by=p,
|
||||
type="changed_ballot_position",
|
||||
pos=GroupBallotPositionName.objects.get(slug="block"),
|
||||
ad=p,
|
||||
block_comment="This is a block test",
|
||||
comment="This is a test",
|
||||
)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(len(q('form input[name="cc"]')) > 0)
|
||||
|
||||
# send
|
||||
p = Person.objects.get(name="Aread Irector")
|
||||
mailbox_before = len(outbox)
|
||||
|
||||
r = self.client.post(url, dict(cc="test@example.com", cc_state_change="1"))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
self.assertEquals(len(outbox), mailbox_before + 1)
|
||||
self.assertTrue("BLOCKING COMMENT" in outbox[-1]['Subject'])
|
||||
self.assertTrue("COMMENT" in outbox[-1]['Subject'])
|
||||
|
||||
class CharterApproveBallotTestCase(django.test.TestCase):
|
||||
fixtures = ['names']
|
||||
|
||||
|
|
|
@ -1,23 +1,18 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
|
||||
from django.conf.urls.defaults import patterns, url
|
||||
from ietf.wgcharter import views, views_edit, views_ballot, views_submit
|
||||
from ietf.doc.models import State
|
||||
|
||||
urlpatterns = patterns('django.views.generic.simple',
|
||||
url(r'^help/state/$', 'direct_to_template', { 'template': 'wgcharter/states.html', 'extra_context': { 'states': State.objects.filter(type="charter") } }, name='help_charter_states'),
|
||||
)
|
||||
urlpatterns += patterns('',
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/((?P<rev>[0-9][0-9](-[0-9][0-9])?)/)?((?P<tab>ballot|writeup|history)/)?$', views.wg_main, name="wg_view"),
|
||||
(r'^(?P<name>[A-Za-z0-9._+-]+)/_ballot.data$', views.wg_ballot),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', views_edit.change_state, name='wg_change_state'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/(?P<option>initcharter|recharter|abandon)/$', views_edit.change_state, name='wg_startstop_process'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', views_edit.telechat_date, name='charter_telechat_date'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/(?P<ann>action|review)/$', views_ballot.announcement_text, name='wg_announcement_text'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/position/$', views_ballot.edit_position, name='wg_edit_position'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/sendballotcomment/$', views_ballot.send_ballot_comment, name='wg_send_ballot_comment'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotwriteupnotes/$', views_ballot.ballot_writeupnotes, name='wg_ballot_writeupnotes'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', views_ballot.approve_ballot, name='wg_approve_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/submit/$', views_submit.submit, name='wg_submit'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/state/$', "ietf.wgcharter.views.change_state", name='wg_change_state'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/(?P<option>initcharter|recharter|abandon)/$', "ietf.wgcharter.views.change_state", name='wg_startstop_process'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/telechat/$', "ietf.wgcharter.views.telechat_date", name='charter_telechat_date'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/(?P<ann>action|review)/$', "ietf.wgcharter.views.announcement_text", name='wg_announcement_text'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/ballotwriteupnotes/$', "ietf.wgcharter.views.ballot_writeupnotes", name='wg_ballot_writeupnotes'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/edit/approveballot/$', "ietf.wgcharter.views.approve_ballot", name='wg_approve_ballot'),
|
||||
url(r'^(?P<name>[A-Za-z0-9._+-]+)/submit/$', "ietf.wgcharter.views.submit", name='wg_submit'),
|
||||
|
||||
)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.conf import settings
|
||||
import re
|
||||
import re, datetime
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
from datetime import datetime
|
||||
from ietf.group.models import GroupEvent, ChangeStateGroupEvent
|
||||
from ietf.doc.models import Document, DocAlias, DocHistory, RelatedDocument, DocumentAuthor, DocEvent
|
||||
from ietf.utils.history import find_history_active_at
|
||||
|
@ -12,7 +12,7 @@ def set_or_create_charter(wg):
|
|||
except Document.DoesNotExist:
|
||||
charter = Document.objects.create(
|
||||
name="charter-ietf-" + wg.acronym,
|
||||
time=datetime.now(),
|
||||
time=datetime.datetime.now(),
|
||||
type_id="charter",
|
||||
title=wg.name,
|
||||
group=wg,
|
||||
|
@ -29,16 +29,6 @@ def set_or_create_charter(wg):
|
|||
wg.save()
|
||||
return charter
|
||||
|
||||
def add_wg_comment(request, wg, text, ballot=None):
|
||||
if request:
|
||||
login = request.user.get_profile()
|
||||
else:
|
||||
login = None
|
||||
|
||||
e = GroupEvent(group=wg, type="added_comment", by=login)
|
||||
e.desc = text
|
||||
e.save()
|
||||
|
||||
def log_state_changed(request, doc, by, prev_state):
|
||||
e = DocEvent(doc=doc, by=by)
|
||||
e.type = "changed_document"
|
||||
|
@ -48,20 +38,6 @@ def log_state_changed(request, doc, by, prev_state):
|
|||
e.save()
|
||||
return e
|
||||
|
||||
def log_group_state_changed(request, wg, by, note=''):
|
||||
e = ChangeStateGroupEvent(group=wg, by=by, type="changed_state")
|
||||
e.state = wg.state
|
||||
e.desc = { 'active': "Started group",
|
||||
'propose': "Proposed group",
|
||||
'conclude': "Concluded group",
|
||||
}[wg.state_id]
|
||||
|
||||
if note:
|
||||
e.desc += "<br>%s" % note
|
||||
|
||||
e.save()
|
||||
return e
|
||||
|
||||
def get_charter_for_revision(charter, r):
|
||||
if r == None:
|
||||
return None
|
||||
|
|
|
@ -1,245 +1,605 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
import re, os, string, datetime
|
||||
|
||||
import re, os
|
||||
from datetime import datetime, time
|
||||
|
||||
from django.http import HttpResponse, Http404
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import RequestContext
|
||||
from django.template.defaultfilters import truncatewords_html
|
||||
from django.utils import simplejson as json
|
||||
from django.utils.decorators import decorator_from_middleware
|
||||
from django.middleware.gzip import GZipMiddleware
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django import forms
|
||||
from django.forms.util import ErrorList
|
||||
from django.utils import simplejson
|
||||
from django.utils.html import strip_tags
|
||||
from django.conf import settings
|
||||
from ietf.doc.models import GroupBallotPositionDocEvent, WriteupDocEvent
|
||||
from ietf.group.models import Group, GroupHistory
|
||||
from ietf.person.models import Person
|
||||
from ietf.wgcharter import markup_txt
|
||||
|
||||
from ietf.utils.mail import send_mail_text, send_mail_preformatted
|
||||
from ietf.ietfauth.decorators import has_role, role_required
|
||||
from ietf.iesg.models import TelechatDate
|
||||
from ietf.doc.models import *
|
||||
from ietf.name.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.group.models import *
|
||||
from ietf.group.utils import save_group_in_history
|
||||
from ietf.wgcharter.mails import *
|
||||
from ietf.wgcharter.utils import *
|
||||
from ietf.utils.history import find_history_active_at
|
||||
from ietf.idtracker.templatetags.ietf_filters import format_textarea, fill
|
||||
|
||||
# FIXME: delete
|
||||
def _get_html(key, filename):
|
||||
f = None
|
||||
try:
|
||||
f = open(filename, 'rb')
|
||||
raw_content = f.read()
|
||||
except IOError:
|
||||
return "Error; cannot read ("+key+")"
|
||||
finally:
|
||||
if f:
|
||||
f.close()
|
||||
content = markup_txt.markup(raw_content)
|
||||
return content
|
||||
|
||||
@decorator_from_middleware(GZipMiddleware)
|
||||
def wg_main(request, name, rev, tab):
|
||||
if tab is None:
|
||||
tab = "charter"
|
||||
|
||||
class ChangeStateForm(forms.Form):
|
||||
charter_state = forms.ModelChoiceField(State.objects.filter(type="charter", slug__in=["infrev", "intrev", "extrev", "iesgrev", "approved"]), label="Charter state", empty_label=None, required=False)
|
||||
initial_time = forms.IntegerField(initial=0, label="Review time", help_text="(in weeks)", required=False)
|
||||
message = forms.CharField(widget=forms.Textarea, help_text="Optional message to the Secretariat", required=False)
|
||||
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the charter history", required=False)
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.hide = kwargs.pop('hide', None)
|
||||
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 WG and charter, notifying parties as necessary
|
||||
and logging the change as a comment."""
|
||||
# Get WG by acronym, redirecting if there's a newer acronym
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_view', name=wglist[0].group.acronym)
|
||||
except Group.DoesNotExist:
|
||||
old = GroupHistory.objects.filter(acronym=name)
|
||||
if old:
|
||||
return redirect('wg_change_state', name=old[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
raise Http404()
|
||||
|
||||
if not wg.charter:
|
||||
set_or_create_charter(wg)
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
if rev != None:
|
||||
ch = get_charter_for_revision(wg.charter, rev)
|
||||
gh = get_group_for_revision(wg, rev)
|
||||
initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
|
||||
if charter.get_state_slug() != "infrev" or (initial_review and initial_review.expires < datetime.datetime.now()):
|
||||
initial_review = None
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST)
|
||||
if form.is_valid():
|
||||
clean = form.cleaned_data
|
||||
if option == "initcharter" or option == "recharter":
|
||||
charter_state = State.objects.get(type="charter", slug="infrev")
|
||||
charter_rev = charter.rev
|
||||
elif option == "abandon":
|
||||
if wg.state_id == "proposed":
|
||||
charter_state = State.objects.get(type="charter", slug="notrev")
|
||||
else:
|
||||
charter_state = State.objects.get(type="charter", slug="approved")
|
||||
charter_rev = approved_revision(charter.rev)
|
||||
else:
|
||||
charter_state = clean['charter_state']
|
||||
charter_rev = charter.rev
|
||||
|
||||
comment = clean['comment'].rstrip()
|
||||
message = clean['message']
|
||||
|
||||
if charter_state != charter.get_state():
|
||||
# Charter state changed
|
||||
save_document_in_history(charter)
|
||||
|
||||
prev = charter.get_state()
|
||||
charter.set_state(charter_state)
|
||||
charter.rev = charter_rev
|
||||
|
||||
if option != "abandon":
|
||||
log_state_changed(request, charter, login, prev)
|
||||
else:
|
||||
# Special log for abandoned efforts
|
||||
e = DocEvent(type="changed_document", doc=charter, by=login)
|
||||
e.desc = "IESG has abandoned the chartering effort"
|
||||
e.save()
|
||||
|
||||
if comment:
|
||||
c = DocEvent(type="added_comment", doc=charter, by=login)
|
||||
c.desc = comment
|
||||
c.save()
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
|
||||
if message:
|
||||
email_secretariat(request, wg, "state-%s" % charter_state.slug, message)
|
||||
|
||||
if charter_state.slug == "intrev" and not charter.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug="r-extrev"):
|
||||
e = BallotDocEvent(type="created_ballot", by=login, doc=charter)
|
||||
e.ballot_type = BallotType.objects.get(doc_type=charter.type, slug="r-extrev")
|
||||
e.desc = u"Created ballot for approving charter for external review"
|
||||
e.save()
|
||||
elif charter_state.slug == "iesgrev" and not charter.latest_event(BallotDocEvent, type="created_ballot", ballot_type__slug="approve"):
|
||||
e = BallotDocEvent(type="created_ballot", by=login, doc=charter)
|
||||
e.ballot_type = BallotType.objects.get(doc_type=charter.type, slug="approve")
|
||||
e.desc = u"Created ballot for approving charter"
|
||||
e.save()
|
||||
|
||||
if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
|
||||
e = InitialReviewDocEvent(type="initial_review", by=login, doc=charter)
|
||||
e.expires = datetime.datetime.now() + datetime.timedelta(weeks=clean["initial_time"])
|
||||
e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
|
||||
e.save()
|
||||
|
||||
return redirect('doc_view', name=charter.name)
|
||||
else:
|
||||
ch = get_charter_for_revision(wg.charter, wg.charter.rev)
|
||||
gh = get_group_for_revision(wg, wg.charter.rev)
|
||||
if option == "recharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message="%s has initiated a recharter effort on the WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
elif option == "initcharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message="%s has initiated chartering of the proposed WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
elif option == "abandon":
|
||||
hide = ['initial_time', 'charter_state']
|
||||
init = dict(message="%s has abandoned the chartering effort on the WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
else:
|
||||
hide = ['initial_time']
|
||||
s = charter.get_state()
|
||||
init = dict(charter_state=s.pk if s else None)
|
||||
form = ChangeStateForm(hide=hide, initial=init)
|
||||
|
||||
prev_charter_state = None
|
||||
charter_hists = DocHistory.objects.filter(doc=charter).exclude(states__type="charter", states__slug=charter.get_state_slug()).order_by("-time")[:1]
|
||||
if charter_hists:
|
||||
prev_charter_state = charter_hists[0].get_state()
|
||||
|
||||
info = {}
|
||||
title = {
|
||||
"initcharter": "Initiate chartering of WG %s" % wg.acronym,
|
||||
"recharter": "Recharter WG %s" % wg.acronym,
|
||||
"abandon": "Abandon effort on WG %s" % wg.acronym,
|
||||
}.get(option)
|
||||
if not title:
|
||||
title = "Change state of WG %s" % wg.acronym
|
||||
|
||||
info['prev_acronyms'] = list(set([x.acronym for x in wg.history_set.exclude(acronym=wg.acronym)]))
|
||||
prev_list_email = list(set([x.list_email for x in wg.history_set.exclude(list_email=wg.list_email) if x.list_email != u'']))
|
||||
if prev_list_email != [u'']:
|
||||
info['prev_list_email'] = prev_list_email
|
||||
prev_list_subscribe = list(set([x.list_subscribe for x in wg.history_set.exclude(list_subscribe=wg.list_subscribe) if x.list_subscribe != u'']))
|
||||
if prev_list_subscribe != [u'']:
|
||||
info['prev_list_subscribe'] = prev_list_subscribe
|
||||
prev_list_archive = list(set([x.list_archive for x in wg.history_set.exclude(list_archive=wg.list_archive) if x.list_archive != u'']))
|
||||
if prev_list_archive != [u'']:
|
||||
info['prev_list_archive'] = prev_list_archive
|
||||
info['chairs'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="chair")]
|
||||
if hasattr(gh, 'rolehistory_set'):
|
||||
info['history_chairs'] = [x.person.plain_name() for x in gh.rolehistory_set.filter(name__slug="chair")]
|
||||
else:
|
||||
info['history_chairs'] = [x.person.plain_name() for x in gh.role_set.filter(name__slug="chair")]
|
||||
info['secr'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="secr")]
|
||||
info['techadv'] = [x.person.plain_name() for x in wg.role_set.filter(name__slug="techadv")]
|
||||
def state_pk(slug):
|
||||
return State.objects.get(type="charter", slug=slug).pk
|
||||
|
||||
if ch:
|
||||
file_path = wg.charter.get_file_path() # Get from wg.charter
|
||||
content = _get_html(
|
||||
"charter-ietf-"+str(gh.acronym)+"-"+str(ch.rev)+".txt",
|
||||
os.path.join(file_path, "charter-ietf-"+gh.acronym+"-"+ch.rev+".txt"))
|
||||
active_ads = Person.objects.filter(email__role__name="ad", email__role__group__state="active").distinct()
|
||||
started_process = datetime.min
|
||||
e = wg.charter.latest_event(type="started_iesg_process")
|
||||
if e:
|
||||
started_process = e.time
|
||||
seen = []
|
||||
latest_positions = []
|
||||
for p in GroupBallotPositionDocEvent.objects.filter(doc=wg.charter, type="changed_ballot_position", time__gte=started_process).order_by("-time", '-id').select_related('ad'):
|
||||
if p.ad not in seen:
|
||||
latest_positions.append(p)
|
||||
seen.append(p.ad)
|
||||
no_record = []
|
||||
old_ads = []
|
||||
for p in latest_positions:
|
||||
if p.ad not in active_ads:
|
||||
old_ads.append(p.ad)
|
||||
for ad in active_ads:
|
||||
has_no_record = True
|
||||
for p in latest_positions:
|
||||
if p.ad == ad:
|
||||
has_no_record = False
|
||||
if has_no_record:
|
||||
no_record.append(ad)
|
||||
messages = {
|
||||
state_pk("infrev"): "The WG %s (%s) has been set to Informal IESG review by %s." % (wg.name, wg.acronym, login.plain_name()),
|
||||
state_pk("intrev"): "The WG %s (%s) has been set to Internal review by %s. Please place it on the next IESG telechat and inform the IAB." % (wg.name, wg.acronym, login.plain_name()),
|
||||
state_pk("extrev"): "The WG %s (%s) has been set to External review by %s. Please send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: " % (wg.name, wg.acronym, login.plain_name()),
|
||||
}
|
||||
|
||||
info['old_ads'] = old_ads
|
||||
info['positions'] = latest_positions
|
||||
info['pos_yes'] = filter(lambda x: x.pos_id == "yes", latest_positions)
|
||||
info['pos_no'] = filter(lambda x: x.pos_id == "no", latest_positions)
|
||||
info['pos_block'] = filter(lambda x: x.pos_id == "block", latest_positions)
|
||||
info['pos_abstain'] = filter(lambda x: x.pos_id == "abstain", latest_positions)
|
||||
info['pos_no_record'] = no_record + [x.ad for x in latest_positions if x.pos_id == "norecord"]
|
||||
|
||||
# Get announcement texts
|
||||
review_ann = wg.charter.latest_event(WriteupDocEvent, type="changed_review_announcement")
|
||||
info['review_text'] = review_ann.text if review_ann else ""
|
||||
action_ann = wg.charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
info['action_text'] = action_ann.text if action_ann else ""
|
||||
ballot_ann = wg.charter.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||
info['ballot_text'] = ballot_ann.text if ballot_ann else ""
|
||||
else:
|
||||
content = ""
|
||||
|
||||
versions = _get_versions(wg.charter) # Important: wg.charter not ch
|
||||
history = _get_history(wg, versions)
|
||||
|
||||
if history:
|
||||
info['last_update'] = history[0]['date']
|
||||
|
||||
template = "wgcharter/wg_tab_%s" % tab
|
||||
return render_to_response(template + ".html",
|
||||
{'content':content,
|
||||
'charter':ch,
|
||||
'info':info,
|
||||
'wg':wg,
|
||||
'tab':tab,
|
||||
'rev': rev if rev else ch.rev,
|
||||
'gh': gh,
|
||||
'snapshot': rev,
|
||||
'charter_text_url': settings.CHARTER_TXT_URL,
|
||||
'history': history, 'versions': versions,
|
||||
},
|
||||
return render_to_response('wgcharter/change_state.html',
|
||||
dict(form=form,
|
||||
wg=wg,
|
||||
login=login,
|
||||
option=option,
|
||||
prev_charter_state=prev_charter_state,
|
||||
title=title,
|
||||
initial_review=initial_review,
|
||||
messages=simplejson.dumps(messages)),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def _get_history(wg, versions=None):
|
||||
results = []
|
||||
for e in wg.charter.docevent_set.all().order_by('-time'):
|
||||
info = {}
|
||||
charter_history = find_history_active_at(wg.charter, e.time)
|
||||
info['version'] = charter_history.rev if charter_history else wg.charter.rev
|
||||
info['text'] = e.desc
|
||||
info['by'] = e.by.plain_name()
|
||||
info['textSnippet'] = truncatewords_html(format_textarea(fill(info['text'], 80)), 25)
|
||||
info['snipped'] = info['textSnippet'][-3:] == "..."
|
||||
if e.type == "new_revision":
|
||||
if charter_history:
|
||||
charter = get_charter_for_revision(wg.charter, charter_history.rev)
|
||||
group = get_group_for_revision(wg, charter_history.rev)
|
||||
else:
|
||||
charter = get_charter_for_revision(wg.charter, wg.charter.rev)
|
||||
group = get_group_for_revision(wg, wg.charter.rev)
|
||||
class TelechatForm(forms.Form):
|
||||
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, required=False)
|
||||
|
||||
if versions:
|
||||
vl = [x['rev'] for x in versions]
|
||||
if vl:
|
||||
prev_charter = get_charter_for_revision(wg.charter, vl[vl.index(charter.rev) - 1])
|
||||
else:
|
||||
prev_charter = get_charter_for_revision(wg.charter, prev_revision(charter.rev))
|
||||
prev_group = get_group_for_revision(wg, prev_revision(charter.rev))
|
||||
results.append({'comment':e, 'info':info, 'date':e.time, 'group': group,
|
||||
'charter': charter, 'prev_charter': prev_charter,
|
||||
'prev_group': prev_group,
|
||||
'txt_url': settings.CHARTER_TXT_URL,
|
||||
'is_rev':True})
|
||||
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):
|
||||
wg = get_object_or_404(Group, acronym=name)
|
||||
doc = set_or_create_charter(wg)
|
||||
login = request.user.get_profile()
|
||||
|
||||
e = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
|
||||
initial = dict(telechat_date=e.telechat_date if e else None)
|
||||
if request.method == "POST":
|
||||
form = TelechatForm(request.POST, initial=initial)
|
||||
|
||||
if form.is_valid():
|
||||
update_telechat(request, doc, login, form.cleaned_data['telechat_date'])
|
||||
return redirect("doc_view", name=doc.name)
|
||||
else:
|
||||
form = TelechatForm(initial=initial)
|
||||
|
||||
return render_to_response('wgcharter/edit_telechat_date.html',
|
||||
dict(doc=doc,
|
||||
form=form,
|
||||
user=request.user,
|
||||
login=login),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
content = forms.CharField(widget=forms.Textarea, label="Charter text", help_text="Edit the charter text", required=False)
|
||||
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 save(self, wg, rev):
|
||||
fd = self.cleaned_data['txt']
|
||||
filename = os.path.join(settings.CHARTER_PATH, 'charter-ietf-%s-%s.txt' % (wg.acronym, rev))
|
||||
if fd:
|
||||
# A file was specified. Save it.
|
||||
destination = open(filename, 'wb+')
|
||||
for chunk in fd.chunks():
|
||||
destination.write(chunk)
|
||||
destination.close()
|
||||
else:
|
||||
results.append({'comment':e, 'info':info, 'date':e.time, 'group': wg, 'is_com':True})
|
||||
# No file, save content
|
||||
destination = open(filename, 'wb+')
|
||||
content = self.cleaned_data['content']
|
||||
destination.write(content)
|
||||
destination.close()
|
||||
|
||||
# convert plain dates to datetimes (required for sorting)
|
||||
for x in results:
|
||||
if not isinstance(x['date'], datetime):
|
||||
if x['date']:
|
||||
x['date'] = datetime.combine(x['date'], time(0,0,0))
|
||||
else:
|
||||
x['date'] = datetime(1970,1,1)
|
||||
|
||||
results.sort(key=lambda x: x['date'])
|
||||
results.reverse()
|
||||
return results
|
||||
|
||||
def _get_versions(charter, include_replaced=True):
|
||||
ov = []
|
||||
prev = ""
|
||||
for r in charter.history_set.order_by('time'):
|
||||
if r.rev != prev:
|
||||
d = get_charter_for_revision(charter, r.rev)
|
||||
g = get_group_for_revision(charter.chartered_group, r.rev)
|
||||
ov.append({"name": "charter-ietf-%s" % g.acronym, "rev":d.rev, "date":d.time})
|
||||
prev = r.rev
|
||||
if charter.rev != "" and (not ov or ov[-1]['rev'] != charter.rev):
|
||||
d = get_charter_for_revision(charter, charter.rev)
|
||||
g = get_group_for_revision(charter.chartered_group, charter.rev)
|
||||
ov.append({"name": "charter-ietf-%s" % g.acronym, "rev": d.rev, "date":d.time})
|
||||
return ov
|
||||
|
||||
def wg_ballot(request, name):
|
||||
@role_required('Area Director','Secretariat')
|
||||
def submit(request, name):
|
||||
# Get WG by acronym, redirecting if there's a newer acronym
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
except Group.DoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_view', name=wglist[0].group.acronym)
|
||||
return redirect('charter_submit', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404()
|
||||
# Get charter
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = UploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
save_document_in_history(charter)
|
||||
# Also save group history so we can search for it
|
||||
save_group_in_history(wg)
|
||||
|
||||
# Search history for possible collisions with abandoned efforts
|
||||
rev_list = list(charter.history_set.order_by('-time').values_list('rev', flat=True))
|
||||
next_rev = next_revision(charter.rev)
|
||||
while next_rev in rev_list:
|
||||
next_rev = next_revision(next_rev)
|
||||
|
||||
charter.rev = next_rev
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "new_revision"
|
||||
e.by = login
|
||||
e.doc = charter
|
||||
e.desc = "New version available: <b>charter-ietf-%s-%s.txt</b>" % (wg.acronym, charter.rev)
|
||||
e.save()
|
||||
|
||||
# Save file on disk
|
||||
form.save(wg, charter.rev)
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
|
||||
return HttpResponseRedirect(reverse('doc_view', kwargs={'name': charter.name}))
|
||||
else:
|
||||
filename = os.path.join(settings.CHARTER_PATH, 'charter-ietf-%s-%s.txt' % (wg.acronym, wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
init = dict(content=charter_text.read())
|
||||
except IOError:
|
||||
init = {}
|
||||
form = UploadForm(initial = init)
|
||||
return render_to_response('wgcharter/submit.html',
|
||||
{'form': form,
|
||||
'next_rev': next_revision(wg.charter.rev),
|
||||
'wg': wg},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
def default_action_text(wg, charter, user, action):
|
||||
e = WriteupDocEvent(doc=charter, by=user)
|
||||
e.by = user
|
||||
e.type = "changed_action_announcement"
|
||||
e.desc = "WG action text was changed"
|
||||
|
||||
info = {}
|
||||
info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")]
|
||||
info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")]
|
||||
info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")]
|
||||
info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None,
|
||||
info['list'] = wg.list_email if wg.list_email else None,
|
||||
info['list_subscribe'] = str(wg.list_subscribe) if wg.list_subscribe else None,
|
||||
info['list_archive'] = str(wg.list_archive) if wg.list_archive else None,
|
||||
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (wg.charter.canonical_name(), wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
info['charter_txt'] = charter_text.read()
|
||||
except IOError:
|
||||
info['charter_txt'] = "Error: couldn't read charter text"
|
||||
|
||||
e.text = render_to_string("wgcharter/action_text.txt",
|
||||
dict(wg=wg,
|
||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||
action_type=action,
|
||||
info=info,
|
||||
))
|
||||
|
||||
e.save()
|
||||
return e
|
||||
|
||||
def default_review_text(wg, charter, user):
|
||||
e = WriteupDocEvent(doc=charter, by=user)
|
||||
e.by = user
|
||||
e.type = "changed_review_announcement"
|
||||
e.desc = "WG review text was changed"
|
||||
info = {}
|
||||
info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")]
|
||||
info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")]
|
||||
info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")]
|
||||
info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None,
|
||||
info['list'] = wg.list_email if wg.list_email else None,
|
||||
info['list_subscribe'] = wg.list_subscribe if wg.list_subscribe else None,
|
||||
info['list_archive'] = wg.list_archive if wg.list_archive else None,
|
||||
|
||||
info['bydate'] = (date.today() + timedelta(weeks=1)).isoformat()
|
||||
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (wg.charter.canonical_name(), wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
info['charter_txt'] = charter_text.read()
|
||||
except IOError:
|
||||
info['charter_txt'] = "Error: couldn't read charter text"
|
||||
|
||||
e.text = render_to_string("wgcharter/review_text.txt",
|
||||
dict(wg=wg,
|
||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||
info=info,
|
||||
review_type="new" if wg.state_id == "proposed" else "recharter",
|
||||
)
|
||||
)
|
||||
e.save()
|
||||
return e
|
||||
|
||||
class AnnouncementTextForm(forms.Form):
|
||||
announcement_text = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
def clean_announcement_text(self):
|
||||
return self.cleaned_data["announcement_text"].replace("\r", "")
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def announcement_text(request, name, ann):
|
||||
"""Editing of announcement text"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except Group.DoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_announcement_text', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
doc = set_or_create_charter(wg)
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
if not doc:
|
||||
raise Http404
|
||||
login = request.user.get_profile()
|
||||
|
||||
active_ads = list(Person.objects.filter(email__role__name="ad",
|
||||
email__role__group__type="area",
|
||||
email__role__group__state="active").distinct())
|
||||
started_process = doc.latest_event(type="started_iesg_process")
|
||||
latest_positions = []
|
||||
no_record = []
|
||||
for p in active_ads:
|
||||
p_pos = list(GroupBallotPositionDocEvent.objects.filter(doc=wg.charter, ad=p).order_by("-time"))
|
||||
if p_pos != []:
|
||||
latest_positions.append(p_pos[0])
|
||||
if ann == "action":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
elif ann == "review":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_review_announcement")
|
||||
if not existing:
|
||||
if ann == "action":
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
existing = default_action_text(wg, charter, login, "Formed")
|
||||
else:
|
||||
existing = default_action_text(wg, charter, login, "Rechartered")
|
||||
elif ann == "review":
|
||||
existing = default_review_text(wg, charter, login)
|
||||
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=existing.text))
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AnnouncementTextForm(request.POST)
|
||||
if "save_text" in request.POST and form.is_valid():
|
||||
t = form.cleaned_data['announcement_text']
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_%s_announcement" % ann
|
||||
e.desc = "WG %s text was changed" % ann
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
if "regenerate_text" in request.POST:
|
||||
if ann == "action":
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
e = default_action_text(wg, charter, login, "Formed")
|
||||
else:
|
||||
e = default_action_text(wg, charter, login, "Rechartered")
|
||||
elif ann == "review":
|
||||
e = default_review_text(wg, charter, login)
|
||||
# make sure form has the updated text
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=e.text))
|
||||
|
||||
if "send_text" in request.POST and form.is_valid():
|
||||
msg = form.cleaned_data['announcement_text']
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
||||
send_mail_text(request, parsed_msg["To"],
|
||||
parsed_msg["From"], parsed_msg["Subject"],
|
||||
parsed_msg.get_payload())
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
return render_to_response('wgcharter/announcement_text.html',
|
||||
dict(charter=charter,
|
||||
announcement=ann,
|
||||
back_url=charter.get_absolute_url(),
|
||||
announcement_text_form=form,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class BallotWriteupForm(forms.Form):
|
||||
ballot_writeup = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
def clean_ballot_writeup(self):
|
||||
return self.cleaned_data["ballot_writeup"].replace("\r", "")
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def ballot_writeupnotes(request, name):
|
||||
"""Editing of ballot write-up and notes"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except Group.DoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_ballot_writeupnotes', name=wglist[0].group.acronym)
|
||||
else:
|
||||
no_record.append(p)
|
||||
info = {}
|
||||
info['positions'] = latest_positions
|
||||
info['pos_yes'] = filter(lambda x: x.pos_id == "yes", latest_positions)
|
||||
info['pos_no'] = filter(lambda x: x.pos_id == "no", latest_positions)
|
||||
info['pos_block'] = filter(lambda x: x.pos_id == "block", latest_positions)
|
||||
info['pos_abstain'] = filter(lambda x: x.pos_id == "abstain", latest_positions)
|
||||
info['pos_no_record'] = no_record
|
||||
return render_to_response('wgcharter/wg_ballot.html', {'info':info, 'wg':wg, 'doc': doc}, context_instance=RequestContext(request))
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
started_process = charter.latest_event(type="started_iesg_process")
|
||||
if not started_process:
|
||||
raise Http404()
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
approval = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||
if not existing:
|
||||
existing = generate_ballot_writeup(request, charter)
|
||||
|
||||
reissue = charter.latest_event(DocEvent, type="sent_ballot_announcement")
|
||||
|
||||
form = BallotWriteupForm(initial=dict(ballot_writeup=existing.text))
|
||||
|
||||
if request.method == 'POST' and "save_ballot_writeup" in request.POST or "issue_ballot" in request.POST:
|
||||
form = BallotWriteupForm(request.POST)
|
||||
if form.is_valid():
|
||||
t = form.cleaned_data["ballot_writeup"]
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.desc = "Ballot writeup was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
if "issue_ballot" in request.POST and approval:
|
||||
if has_role(request.user, "Area Director") and not charter.latest_event(GroupBallotPositionDocEvent, ad=login, time__gte=started_process.time):
|
||||
# sending the ballot counts as a yes
|
||||
pos = GroupBallotPositionDocEvent(doc=charter, by=login)
|
||||
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()
|
||||
|
||||
msg = generate_issue_ballot_mail(request, charter)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "sent_ballot_announcement"
|
||||
e.desc = "Ballot has been issued"
|
||||
e.save()
|
||||
|
||||
return render_to_response('wgcharter/ballot_issued.html',
|
||||
dict(charter=charter,
|
||||
back_url=charter.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
return render_to_response('wgcharter/ballot_writeupnotes.html',
|
||||
dict(charter=charter,
|
||||
back_url=charter.get_absolute_url(),
|
||||
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
||||
ballot_writeup_form=form,
|
||||
reissue=reissue,
|
||||
approval=approval,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required("Secretariat")
|
||||
def approve_ballot(request, name):
|
||||
"""Approve ballot, changing state, copying charter"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except Group.DoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_approve_ballot', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
e = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
if not e:
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
announcement = default_action_text(wg, charter, login, "Formed").text
|
||||
else:
|
||||
announcement = default_action_text(wg, charter, login, "Rechartered").text
|
||||
else:
|
||||
announcement = e.text
|
||||
|
||||
if request.method == 'POST':
|
||||
new_state = GroupStateName.objects.get(slug="active")
|
||||
new_charter_state = State.objects.get(type="charter", slug="approved")
|
||||
|
||||
save_document_in_history(charter)
|
||||
save_group_in_history(wg)
|
||||
|
||||
prev_state = wg.state
|
||||
prev_charter_state = charter.get_state()
|
||||
wg.state = new_state
|
||||
charter.set_state(new_charter_state)
|
||||
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the charter"
|
||||
e.save()
|
||||
|
||||
change_description = e.desc + " and WG state has been changed to %s" % new_state.name
|
||||
|
||||
e = log_state_changed(request, charter, login, prev_state)
|
||||
|
||||
wg.time = e.time
|
||||
wg.save()
|
||||
|
||||
ch = get_charter_for_revision(wg.charter, wg.charter.rev)
|
||||
|
||||
filename = os.path.join(charter.get_file_path(), ch.name+"-"+ch.rev+".txt")
|
||||
try:
|
||||
source = open(filename, 'rb')
|
||||
raw_content = source.read()
|
||||
|
||||
new_filename = os.path.join(charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (wg.acronym, next_approved_revision(ch.rev)))
|
||||
destination = open(new_filename, 'wb+')
|
||||
destination.write(raw_content)
|
||||
destination.close()
|
||||
except IOError:
|
||||
raise Http404("Charter text %s" % filename)
|
||||
|
||||
charter.rev = next_approved_revision(charter.rev)
|
||||
charter.save()
|
||||
|
||||
email_secretariat(request, wg, "state-%s" % new_charter_state.slug, change_description)
|
||||
|
||||
# send announcement
|
||||
send_mail_preformatted(request, announcement)
|
||||
|
||||
return HttpResponseRedirect(charter.get_absolute_url())
|
||||
|
||||
return render_to_response('wgcharter/approve_ballot.html',
|
||||
dict(charter=charter,
|
||||
announcement=announcement,
|
||||
wg=wg),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
|
|
@ -1,572 +0,0 @@
|
|||
# ballot management (voting, commenting, writeups, ...) for Area
|
||||
# Directors and Secretariat
|
||||
|
||||
import re, os
|
||||
from datetime import datetime, date, time, timedelta
|
||||
from django.http import HttpResponse, HttpResponseRedirect, Http404
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.template.loader import render_to_string
|
||||
from django.template import RequestContext
|
||||
from django import forms
|
||||
from django.utils.html import strip_tags
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
|
||||
from ietf.utils.mail import send_mail_text, send_mail_preformatted
|
||||
from ietf.ietfauth.decorators import has_role, role_required
|
||||
from ietf.wgcharter.mails import email_secretariat, generate_ballot_writeup, generate_issue_ballot_mail
|
||||
from ietf.wgcharter.utils import *
|
||||
from ietf.group.models import Group, GroupHistory, GroupEvent
|
||||
from ietf.group.utils import save_group_in_history
|
||||
from ietf.name.models import GroupBallotPositionName, GroupStateName
|
||||
from ietf.doc.models import *
|
||||
|
||||
def default_action_text(wg, charter, user, action):
|
||||
e = WriteupDocEvent(doc=charter, by=user)
|
||||
e.by = user
|
||||
e.type = "changed_action_announcement"
|
||||
e.desc = "WG action text was changed"
|
||||
|
||||
info = {}
|
||||
info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")]
|
||||
info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")]
|
||||
info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")]
|
||||
info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None,
|
||||
info['list'] = wg.list_email if wg.list_email else None,
|
||||
info['list_subscribe'] = str(wg.list_subscribe) if wg.list_subscribe else None,
|
||||
info['list_archive'] = str(wg.list_archive) if wg.list_archive else None,
|
||||
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (wg.charter.canonical_name(), wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
info['charter_txt'] = charter_text.read()
|
||||
except IOError:
|
||||
info['charter_txt'] = "Error: couldn't read charter text"
|
||||
|
||||
e.text = render_to_string("wgcharter/action_text.txt",
|
||||
dict(wg=wg,
|
||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||
action_type=action,
|
||||
info=info,
|
||||
))
|
||||
|
||||
e.save()
|
||||
return e
|
||||
|
||||
def default_review_text(wg, charter, user):
|
||||
e = WriteupDocEvent(doc=charter, by=user)
|
||||
e.by = user
|
||||
e.type = "changed_review_announcement"
|
||||
e.desc = "WG review text was changed"
|
||||
info = {}
|
||||
info['chairs'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Chair")]
|
||||
info['secr'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Secr")]
|
||||
info['techadv'] = [{ 'name': x.person.plain_name(), 'email': x.email.address} for x in wg.role_set.filter(name="Techadv")]
|
||||
info['ad'] = {'name': wg.ad.plain_name(), 'email': wg.ad.role_email("ad").address } if wg.ad else None,
|
||||
info['list'] = wg.list_email if wg.list_email else None,
|
||||
info['list_subscribe'] = wg.list_subscribe if wg.list_subscribe else None,
|
||||
info['list_archive'] = wg.list_archive if wg.list_archive else None,
|
||||
|
||||
info['bydate'] = (date.today() + timedelta(weeks=1)).isoformat()
|
||||
|
||||
filename = os.path.join(settings.CHARTER_PATH, '%s-%s.txt' % (wg.charter.canonical_name(), wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
info['charter_txt'] = charter_text.read()
|
||||
except IOError:
|
||||
info['charter_txt'] = "Error: couldn't read charter text"
|
||||
|
||||
e.text = render_to_string("wgcharter/review_text.txt",
|
||||
dict(wg=wg,
|
||||
charter_url=settings.IDTRACKER_BASE_URL + charter.get_absolute_url(),
|
||||
info=info,
|
||||
review_type="new" if wg.state_id == "proposed" else "recharter",
|
||||
)
|
||||
)
|
||||
e.save()
|
||||
return e
|
||||
|
||||
BALLOT_CHOICES = (("yes", "Yes"),
|
||||
("no", "No"),
|
||||
("block", "Block"),
|
||||
("abstain", "Abstain"),
|
||||
("", "No Record"),
|
||||
)
|
||||
|
||||
def position_to_ballot_choice(position):
|
||||
for v, label in BALLOT_CHOICES:
|
||||
if v and getattr(position, v):
|
||||
return v
|
||||
return ""
|
||||
|
||||
def position_label(position_value):
|
||||
return dict(BALLOT_CHOICES).get(position_value, "")
|
||||
|
||||
class EditPositionForm(forms.Form):
|
||||
position = forms.ModelChoiceField(queryset=GroupBallotPositionName.objects.all(), widget=forms.RadioSelect, initial="norecord", required=True)
|
||||
block_comment = forms.CharField(required=False, label="Blocking comment", widget=forms.Textarea)
|
||||
comment = forms.CharField(required=False, widget=forms.Textarea)
|
||||
return_to_url = forms.CharField(required=False, widget=forms.HiddenInput)
|
||||
|
||||
def clean_blocking(self):
|
||||
entered_blocking = self.cleaned_data["block_comment"]
|
||||
entered_pos = self.cleaned_data["position"]
|
||||
if entered_pos.slug == "block" and not entered_blocking:
|
||||
raise forms.ValidationError("You must enter a non-empty blocking comment")
|
||||
return entered_blocking
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def edit_position(request, name):
|
||||
"""Vote and edit comments on Charter as Area Director."""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_edit_position', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
started_process = charter.latest_event(type="started_iesg_process")
|
||||
if not started_process:
|
||||
raise Http404
|
||||
|
||||
ad = login = request.user.get_profile()
|
||||
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
return_to_url = request.META['HTTP_REFERER']
|
||||
else:
|
||||
return_to_url = charter.get_absolute_url()
|
||||
|
||||
# if we're in the Secretariat, we can select an AD to act as stand-in for
|
||||
if not has_role(request.user, "Area Director"):
|
||||
ad_id = request.GET.get('ad')
|
||||
if not ad_id:
|
||||
raise Http404()
|
||||
from ietf.person.models import Person
|
||||
ad = get_object_or_404(Person, pk=ad_id)
|
||||
|
||||
old_pos = charter.latest_event(GroupBallotPositionDocEvent, type="changed_ballot_position", ad=ad, time__gte=started_process.time)
|
||||
|
||||
if request.method == 'POST':
|
||||
form = EditPositionForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
||||
# save the vote
|
||||
clean = form.cleaned_data
|
||||
|
||||
if clean['return_to_url']:
|
||||
return_to_url = clean['return_to_url']
|
||||
|
||||
pos = GroupBallotPositionDocEvent(doc=charter, by=login)
|
||||
pos.type = "changed_ballot_position"
|
||||
pos.ad = ad
|
||||
pos.pos = clean["position"]
|
||||
pos.comment = clean["comment"].strip()
|
||||
pos.comment_time = old_pos.comment_time if old_pos else None
|
||||
pos.block_comment = clean["block_comment"].strip() if pos.pos_id == "block" else ""
|
||||
pos.block_comment_time = old_pos.block_comment_time if old_pos else None
|
||||
|
||||
changes = []
|
||||
added_events = []
|
||||
# possibly add discuss/comment comments to history trail
|
||||
# so it's easy to see
|
||||
old_comment = old_pos.comment if old_pos else ""
|
||||
if pos.comment != old_comment:
|
||||
pos.comment_time = pos.time
|
||||
changes.append("comment")
|
||||
|
||||
if pos.comment:
|
||||
e = DocEvent(doc=charter)
|
||||
e.by = ad # otherwise we can't see who's saying it
|
||||
e.type = "added_comment"
|
||||
e.desc = "[Ballot comment]\n" + pos.comment
|
||||
added_events.append(e)
|
||||
|
||||
old_block_comment = old_pos.block_comment if old_pos else ""
|
||||
if pos.block_comment != old_block_comment:
|
||||
pos.block_comment_time = pos.time
|
||||
changes.append("block_comment")
|
||||
|
||||
if pos.block_comment:
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.by = ad # otherwise we can't see who's saying it
|
||||
e.type = "added_comment"
|
||||
e.desc = "[Ballot blocking comment]\n" + pos.block_comment
|
||||
added_events.append(e)
|
||||
|
||||
# figure out a description
|
||||
if not old_pos and pos.pos.slug != "norecord":
|
||||
pos.desc = u"[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.name)
|
||||
elif old_pos and pos.pos != old_pos.pos:
|
||||
pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % (pos.ad.plain_name(), pos.pos.name, old_pos.pos.name)
|
||||
|
||||
if not pos.desc and changes:
|
||||
pos.desc = u"Ballot %s text updated for %s" % (u" and ".join(changes), ad.plain_name())
|
||||
|
||||
# only add new event if we actually got a change
|
||||
if pos.desc:
|
||||
if login != ad:
|
||||
pos.desc += u" by %s" % login.plain_name()
|
||||
|
||||
pos.save()
|
||||
|
||||
for e in added_events:
|
||||
e.save() # save them after the position is saved to get later id
|
||||
|
||||
charter.time = pos.time
|
||||
charter.save()
|
||||
|
||||
if request.POST.get("send_mail"):
|
||||
qstr = "?return_to_url=%s" % return_to_url
|
||||
if request.GET.get('ad'):
|
||||
qstr += "&ad=%s" % request.GET.get('ad')
|
||||
return HttpResponseRedirect(urlreverse("wg_send_ballot_comment", kwargs=dict(name=wg.acronym)) + qstr)
|
||||
else:
|
||||
return HttpResponseRedirect(return_to_url)
|
||||
else:
|
||||
initial = {}
|
||||
if old_pos:
|
||||
initial['position'] = old_pos.pos.slug
|
||||
initial['block_comment'] = old_pos.block_comment
|
||||
initial['comment'] = old_pos.comment
|
||||
|
||||
if return_to_url:
|
||||
initial['return_to_url'] = return_to_url
|
||||
|
||||
form = EditPositionForm(initial=initial)
|
||||
|
||||
return render_to_response('wgcharter/edit_position.html',
|
||||
dict(charter=charter,
|
||||
wg=wg,
|
||||
form=form,
|
||||
ad=ad,
|
||||
return_to_url=return_to_url,
|
||||
old_pos=old_pos,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def send_ballot_comment(request, name):
|
||||
"""Email Charter ballot comment for area director."""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_send_ballot_comment', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
started_process = charter.latest_event(type="started_iesg_process")
|
||||
if not started_process:
|
||||
raise Http404()
|
||||
|
||||
ad = login = request.user.get_profile()
|
||||
|
||||
return_to_url = request.GET.get('return_to_url')
|
||||
if not return_to_url:
|
||||
return_to_url = charter.get_absolute_url()
|
||||
|
||||
if 'HTTP_REFERER' in request.META:
|
||||
back_url = request.META['HTTP_REFERER']
|
||||
else:
|
||||
back_url = charter.get_absolute_url()
|
||||
|
||||
# if we're in the Secretariat, we can select an AD to act as stand-in for
|
||||
if not has_role(request.user, "Area Director"):
|
||||
ad_id = request.GET.get('ad')
|
||||
if not ad_id:
|
||||
raise Http404()
|
||||
from ietf.person.models import Person
|
||||
ad = get_object_or_404(Person, pk=ad_id)
|
||||
|
||||
pos = charter.latest_event(GroupBallotPositionDocEvent, type="changed_ballot_position", ad=ad, time__gte=started_process.time)
|
||||
if not pos:
|
||||
raise Http404()
|
||||
|
||||
subj = []
|
||||
d = ""
|
||||
if pos.pos_id == "block" and pos.block_comment:
|
||||
d = pos.block_comment
|
||||
subj.append("BLOCKING COMMENT")
|
||||
c = ""
|
||||
if pos.comment:
|
||||
c = pos.comment
|
||||
subj.append("COMMENT")
|
||||
|
||||
ad_name_genitive = ad.plain_name() + "'" if ad.plain_name().endswith('s') else ad.plain_name() + "'s"
|
||||
subject = "%s %s on %s" % (ad_name_genitive, pos.pos.name if pos.pos else "No Position", charter.name + "-" + charter.rev)
|
||||
if subj:
|
||||
subject += ": (with %s)" % " and ".join(subj)
|
||||
|
||||
body = render_to_string("wgcharter/ballot_comment_mail.txt",
|
||||
dict(block_comment=d, comment=c, ad=ad.plain_name(), charter=charter, pos=pos.pos))
|
||||
frm = ad.formatted_email()
|
||||
to = "The IESG <iesg@ietf.org>"
|
||||
|
||||
if request.method == 'POST':
|
||||
cc = [x.strip() for x in request.POST.get("cc", "").split(',') if x.strip()]
|
||||
send_mail_text(request, to, frm, subject, body, cc=", ".join(cc))
|
||||
|
||||
return HttpResponseRedirect(return_to_url)
|
||||
|
||||
return render_to_response('wgcharter/send_ballot_comment.html',
|
||||
dict(charter=charter,
|
||||
subject=subject,
|
||||
body=body,
|
||||
frm=frm,
|
||||
to=to,
|
||||
ad=ad,
|
||||
can_send=d or c,
|
||||
back_url=back_url,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class AnnouncementTextForm(forms.Form):
|
||||
announcement_text = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
def clean_announcement_text(self):
|
||||
return self.cleaned_data["announcement_text"].replace("\r", "")
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def announcement_text(request, name, ann):
|
||||
"""Editing of announcement text"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_announcement_text', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if ann == "action":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
elif ann == "review":
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_review_announcement")
|
||||
if not existing:
|
||||
if ann == "action":
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
existing = default_action_text(wg, charter, login, "Formed")
|
||||
else:
|
||||
existing = default_action_text(wg, charter, login, "Rechartered")
|
||||
elif ann == "review":
|
||||
existing = default_review_text(wg, charter, login)
|
||||
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=existing.text))
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AnnouncementTextForm(request.POST)
|
||||
if "save_text" in request.POST and form.is_valid():
|
||||
t = form.cleaned_data['announcement_text']
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_%s_announcement" % ann
|
||||
e.desc = "WG %s text was changed" % ann
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
if "regenerate_text" in request.POST:
|
||||
if ann == "action":
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
e = default_action_text(wg, charter, login, "Formed")
|
||||
else:
|
||||
e = default_action_text(wg, charter, login, "Rechartered")
|
||||
elif ann == "review":
|
||||
e = default_review_text(wg, charter, login)
|
||||
# make sure form has the updated text
|
||||
form = AnnouncementTextForm(initial=dict(announcement_text=e.text))
|
||||
|
||||
if "send_text" in request.POST and form.is_valid():
|
||||
msg = form.cleaned_data['announcement_text']
|
||||
import email
|
||||
parsed_msg = email.message_from_string(msg.encode("utf-8"))
|
||||
|
||||
send_mail_text(request, parsed_msg["To"],
|
||||
parsed_msg["From"], parsed_msg["Subject"],
|
||||
parsed_msg.get_payload())
|
||||
return redirect('doc_writeup', name=charter.name)
|
||||
|
||||
return render_to_response('wgcharter/announcement_text.html',
|
||||
dict(charter=charter,
|
||||
announcement=ann,
|
||||
back_url=charter.get_absolute_url(),
|
||||
announcement_text_form=form,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class BallotWriteupForm(forms.Form):
|
||||
ballot_writeup = forms.CharField(widget=forms.Textarea, required=True)
|
||||
|
||||
def clean_ballot_writeup(self):
|
||||
return self.cleaned_data["ballot_writeup"].replace("\r", "")
|
||||
|
||||
@role_required('Area Director','Secretariat')
|
||||
def ballot_writeupnotes(request, name):
|
||||
"""Editing of ballot write-up and notes"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_ballot_writeupnotes', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
started_process = charter.latest_event(type="started_iesg_process")
|
||||
if not started_process:
|
||||
raise Http404()
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
approval = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
|
||||
existing = charter.latest_event(WriteupDocEvent, type="changed_ballot_writeup_text")
|
||||
if not existing:
|
||||
existing = generate_ballot_writeup(request, charter)
|
||||
|
||||
reissue = charter.latest_event(DocEvent, type="sent_ballot_announcement")
|
||||
|
||||
form = BallotWriteupForm(initial=dict(ballot_writeup=existing.text))
|
||||
|
||||
if request.method == 'POST' and "save_ballot_writeup" in request.POST or "issue_ballot" in request.POST:
|
||||
form = BallotWriteupForm(request.POST)
|
||||
if form.is_valid():
|
||||
t = form.cleaned_data["ballot_writeup"]
|
||||
if t != existing.text:
|
||||
e = WriteupDocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "changed_ballot_writeup_text"
|
||||
e.desc = "Ballot writeup was changed"
|
||||
e.text = t
|
||||
e.save()
|
||||
|
||||
if "issue_ballot" in request.POST and approval:
|
||||
if has_role(request.user, "Area Director") and not charter.latest_event(GroupBallotPositionDocEvent, ad=login, time__gte=started_process.time):
|
||||
# sending the ballot counts as a yes
|
||||
pos = GroupBallotPositionDocEvent(doc=charter, by=login)
|
||||
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()
|
||||
|
||||
msg = generate_issue_ballot_mail(request, charter)
|
||||
send_mail_preformatted(request, msg)
|
||||
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.by = login
|
||||
e.type = "sent_ballot_announcement"
|
||||
e.desc = "Ballot has been issued"
|
||||
e.save()
|
||||
|
||||
return render_to_response('wgcharter/ballot_issued.html',
|
||||
dict(charter=charter,
|
||||
back_url=charter.get_absolute_url()),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
|
||||
return render_to_response('wgcharter/ballot_writeupnotes.html',
|
||||
dict(charter=charter,
|
||||
back_url=charter.get_absolute_url(),
|
||||
ballot_issued=bool(charter.latest_event(type="sent_ballot_announcement")),
|
||||
ballot_writeup_form=form,
|
||||
reissue=reissue,
|
||||
approval=approval,
|
||||
),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
@role_required("Secretariat")
|
||||
def approve_ballot(request, name):
|
||||
"""Approve ballot, changing state, copying charter"""
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except ObjectDoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('wg_approve_ballot', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
e = charter.latest_event(WriteupDocEvent, type="changed_action_announcement")
|
||||
if not e:
|
||||
if next_approved_revision(wg.charter.rev) == "01":
|
||||
announcement = default_action_text(wg, charter, login, "Formed").text
|
||||
else:
|
||||
announcement = default_action_text(wg, charter, login, "Rechartered").text
|
||||
else:
|
||||
announcement = e.text
|
||||
|
||||
if request.method == 'POST':
|
||||
new_state = GroupStateName.objects.get(slug="active")
|
||||
new_charter_state = State.objects.get(type="charter", slug="approved")
|
||||
|
||||
save_document_in_history(charter)
|
||||
save_group_in_history(wg)
|
||||
|
||||
prev_state = wg.state
|
||||
prev_charter_state = charter.get_state()
|
||||
wg.state = new_state
|
||||
charter.set_state(new_charter_state)
|
||||
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.type = "iesg_approved"
|
||||
e.desc = "IESG has approved the charter"
|
||||
e.save()
|
||||
|
||||
change_description = e.desc + " and WG state has been changed to %s" % new_state.name
|
||||
|
||||
e = log_state_changed(request, charter, login, prev_state)
|
||||
|
||||
wg.time = e.time
|
||||
wg.save()
|
||||
|
||||
ch = get_charter_for_revision(wg.charter, wg.charter.rev)
|
||||
|
||||
filename = os.path.join(charter.get_file_path(), ch.name+"-"+ch.rev+".txt")
|
||||
try:
|
||||
source = open(filename, 'rb')
|
||||
raw_content = source.read()
|
||||
|
||||
new_filename = os.path.join(charter.get_file_path(), 'charter-ietf-%s-%s.txt' % (wg.acronym, next_approved_revision(ch.rev)))
|
||||
destination = open(new_filename, 'wb+')
|
||||
destination.write(raw_content)
|
||||
destination.close()
|
||||
except IOError:
|
||||
raise Http404("Charter text %s" % filename)
|
||||
|
||||
charter.rev = next_approved_revision(charter.rev)
|
||||
charter.save()
|
||||
|
||||
email_secretariat(request, wg, "state-%s" % new_charter_state.slug, change_description)
|
||||
|
||||
# send announcement
|
||||
send_mail_preformatted(request, announcement)
|
||||
|
||||
return HttpResponseRedirect(charter.get_absolute_url())
|
||||
|
||||
return render_to_response('wgcharter/approve_ballot.html',
|
||||
dict(charter=charter,
|
||||
announcement=announcement,
|
||||
wg=wg),
|
||||
context_instance=RequestContext(request))
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
|
||||
import re, os, string, datetime
|
||||
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import RequestContext
|
||||
from django import forms
|
||||
from django.forms.util import ErrorList
|
||||
from django.utils import simplejson
|
||||
|
||||
from utils import *
|
||||
from mails import email_secretariat
|
||||
from ietf.ietfauth.decorators import role_required
|
||||
from ietf.iesg.models import TelechatDate
|
||||
|
||||
from ietf.doc.models import *
|
||||
from ietf.name.models import *
|
||||
from ietf.person.models import *
|
||||
from ietf.group.models import *
|
||||
from ietf.group.utils import save_group_in_history
|
||||
|
||||
class ChangeStateForm(forms.Form):
|
||||
charter_state = forms.ModelChoiceField(State.objects.filter(type="charter"), label="Charter state", empty_label=None, required=False)
|
||||
confirm_state = forms.BooleanField(widget=forms.HiddenInput, required=False, initial=True)
|
||||
initial_time = forms.IntegerField(initial=0, label="Review time", help_text="(in weeks)", required=False)
|
||||
message = forms.CharField(widget=forms.Textarea, help_text="Message to the Secretariat", required=False)
|
||||
comment = forms.CharField(widget=forms.Textarea, help_text="Optional comment for the charter history", required=False)
|
||||
def __init__(self, *args, **kwargs):
|
||||
qs = kwargs.pop('queryset', None)
|
||||
self.hide = kwargs.pop('hide', None)
|
||||
super(ChangeStateForm, self).__init__(*args, **kwargs)
|
||||
if qs:
|
||||
self.fields['charter_state'].queryset = qs
|
||||
# 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 WG and charter, notifying parties as necessary
|
||||
and logging the change as a comment."""
|
||||
# Get WG by acronym, redirecting if there's a newer acronym
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except Group.DoesNotExist:
|
||||
old = GroupHistory.objects.filter(acronym=name)
|
||||
if old:
|
||||
return redirect('wg_change_state', name=old[0].group.acronym)
|
||||
else:
|
||||
raise Http404()
|
||||
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
initial_review = charter.latest_event(InitialReviewDocEvent, type="initial_review")
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ChangeStateForm(request.POST)
|
||||
if form.is_valid():
|
||||
clean = form.cleaned_data
|
||||
if (initial_review and clean['charter_state'] and clean['charter_state'].slug != "infrev"
|
||||
and initial_review.expires > datetime.datetime.now() and not clean['confirm_state']):
|
||||
form._errors['charter_state'] = "warning"
|
||||
else:
|
||||
if option == "initcharter" or option == "recharter":
|
||||
charter_state = State.objects.get(type="charter", slug="infrev")
|
||||
charter_rev = charter.rev
|
||||
elif option == "abandon":
|
||||
if wg.state_id == "proposed":
|
||||
charter_state = State.objects.get(type="charter", slug="notrev")
|
||||
else:
|
||||
charter_state = State.objects.get(type="charter", slug="approved")
|
||||
charter_rev = approved_revision(charter.rev)
|
||||
else:
|
||||
charter_state = clean['charter_state']
|
||||
charter_rev = charter.rev
|
||||
|
||||
comment = clean['comment'].rstrip()
|
||||
message = clean['message']
|
||||
|
||||
change = False
|
||||
if charter:
|
||||
# The WG has a charter
|
||||
if charter_state != charter.get_state():
|
||||
# Charter state changed
|
||||
change = True
|
||||
save_document_in_history(charter)
|
||||
|
||||
prev = charter.get_state()
|
||||
charter.set_state(charter_state)
|
||||
charter.rev = charter_rev
|
||||
|
||||
if option != "abandon":
|
||||
e = log_state_changed(request, charter, login, prev)
|
||||
else:
|
||||
# Special log for abandoned efforts
|
||||
e = DocEvent(type="changed_document", doc=charter, by=login)
|
||||
e.desc = "IESG has abandoned the chartering effort"
|
||||
e.save()
|
||||
|
||||
if comment:
|
||||
c = DocEvent(type="added_comment", doc=charter, by=login)
|
||||
c.desc = comment
|
||||
c.save()
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
else:
|
||||
# WG does not yet have a charter
|
||||
if charter_state != "infrev":
|
||||
# This is an error
|
||||
raise Http404()
|
||||
|
||||
if change and charter:
|
||||
messages = {}
|
||||
messages['extrev'] = "The WG has been set to External review by %s. Please schedule discussion for the next IESG telechat." % login.plain_name()
|
||||
|
||||
if message:
|
||||
email_secretariat(request, wg, "state-%s" % charter_state.slug, message)
|
||||
if charter_state.slug == "extrev":
|
||||
email_secretariat(request, wg, "state-%s" % charter_state.slug, messages['extrev'])
|
||||
|
||||
if charter_state.slug == "infrev":
|
||||
e = DocEvent()
|
||||
e.type = "started_iesg_process"
|
||||
e.by = login
|
||||
e.doc = charter
|
||||
e.desc = "IESG process started in state <b>%s</b>" % charter_state.name
|
||||
e.save()
|
||||
|
||||
if charter_state.slug == "infrev" and clean["initial_time"] and clean["initial_time"] != 0:
|
||||
e = InitialReviewDocEvent()
|
||||
e.type = "initial_review"
|
||||
e.by = login
|
||||
e.doc = charter
|
||||
e.expires = datetime.datetime.now() + datetime.timedelta(weeks=clean["initial_time"])
|
||||
e.desc = "Initial review time expires %s" % e.expires.strftime("%Y-%m-%d")
|
||||
e.save()
|
||||
|
||||
return redirect('doc_view', name=charter.name)
|
||||
else:
|
||||
if option == "recharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message="%s has initiated a recharter effort on the WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
elif option == "initcharter":
|
||||
hide = ['charter_state']
|
||||
init = dict(initial_time=1, message="%s has initiated chartering of the proposed WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
elif option == "abandon":
|
||||
hide = ['initial_time', 'charter_state']
|
||||
init = dict(message="%s has abandoned the chartering effort on the WG %s (%s)" % (login.plain_name(), wg.name, wg.acronym))
|
||||
else:
|
||||
hide = ['initial_time']
|
||||
init = dict(charter_state=wg.charter.get_state_slug(), state=wg.state_id)
|
||||
states = State.objects.filter(type="charter", slug__in=["infrev", "intrev", "extrev", "iesgrev"])
|
||||
form = ChangeStateForm(queryset=states, hide=hide, initial=init)
|
||||
|
||||
prev_charter_state = None
|
||||
charter_hists = DocHistory.objects.filter(doc=charter).exclude(states__type="charter", states__slug=charter.get_state_slug()).order_by("-time")[:1]
|
||||
if charter_hists:
|
||||
prev_charter_state = charter_hists[0].get_state()
|
||||
|
||||
title = {
|
||||
"initcharter": "Initiate chartering of WG %s" % wg.acronym,
|
||||
"recharter": "Recharter WG %s" % wg.acronym,
|
||||
"abandon": "Abandon effort on WG %s" % wg.acronym,
|
||||
}.get(option)
|
||||
if not title:
|
||||
title = "Change state of WG %s" % wg.acronym
|
||||
|
||||
def charter_pk(slug):
|
||||
return State.objects.get(type="charter", slug=slug).pk
|
||||
|
||||
messages = {
|
||||
charter_pk("infrev"): "The WG %s (%s) has been set to Informal IESG review by %s." % (wg.name, wg.acronym, login.plain_name()),
|
||||
charter_pk("intrev"): "The WG %s (%s) has been set to Internal review by %s. Please place it on the next IESG telechat and inform the IAB." % (wg.name, wg.acronym, login.plain_name()),
|
||||
charter_pk("extrev"): "The WG %s (%s) has been set to External review by %s. Please send out the external review announcement to the appropriate lists.\n\nSend the announcement to other SDOs: Yes\nAdditional recipients of the announcement: " % (wg.name, wg.acronym, login.plain_name()),
|
||||
}
|
||||
|
||||
return render_to_response('wgcharter/change_state.html',
|
||||
dict(form=form,
|
||||
wg=wg,
|
||||
login=login,
|
||||
option=option,
|
||||
prev_charter_state=prev_charter_state,
|
||||
title=title,
|
||||
messages=simplejson.dumps(messages)),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class TelechatForm(forms.Form):
|
||||
telechat_date = forms.TypedChoiceField(coerce=lambda x: datetime.datetime.strptime(x, '%Y-%m-%d').date(), empty_value=None, 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):
|
||||
wg = get_object_or_404(Group, acronym=name)
|
||||
doc = set_or_create_charter(wg)
|
||||
login = request.user.get_profile()
|
||||
|
||||
e = doc.latest_event(TelechatDocEvent, type="scheduled_for_telechat")
|
||||
|
||||
initial = dict(telechat_date=e.telechat_date if e else None)
|
||||
if request.method == "POST":
|
||||
form = TelechatForm(request.POST, initial=initial)
|
||||
|
||||
if form.is_valid():
|
||||
update_telechat(request, doc, login, form.cleaned_data['telechat_date'])
|
||||
return redirect("doc_view", name=doc.name)
|
||||
else:
|
||||
form = TelechatForm(initial=initial)
|
||||
|
||||
return render_to_response('wgcharter/edit_telechat_date.html',
|
||||
dict(doc=doc,
|
||||
form=form,
|
||||
user=request.user,
|
||||
login=login),
|
||||
context_instance=RequestContext(request))
|
|
@ -1,98 +0,0 @@
|
|||
# Copyright The IETF Trust 2011, All Rights Reserved
|
||||
import os, datetime
|
||||
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django import forms
|
||||
from django.shortcuts import render_to_response, get_object_or_404, redirect
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.template import RequestContext
|
||||
from django.conf import settings
|
||||
|
||||
from ietf.ietfauth.decorators import group_required
|
||||
from ietf.group.models import Group
|
||||
from ietf.doc.models import Document, DocHistory, DocEvent, save_document_in_history
|
||||
from ietf.group.utils import save_group_in_history
|
||||
|
||||
from utils import next_revision, set_or_create_charter
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
content = forms.CharField(widget=forms.Textarea, label="Charter text", help_text="Edit the charter 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 save(self, wg, rev):
|
||||
fd = self.cleaned_data['txt']
|
||||
filename = os.path.join(settings.CHARTER_PATH, 'charter-ietf-%s-%s.txt' % (wg.acronym, rev))
|
||||
if fd:
|
||||
# A file was specified. Save it.
|
||||
destination = open(filename, 'wb+')
|
||||
for chunk in fd.chunks():
|
||||
destination.write(chunk)
|
||||
destination.close()
|
||||
else:
|
||||
# No file, save content
|
||||
destination = open(filename, 'wb+')
|
||||
content = self.cleaned_data['content']
|
||||
destination.write(content)
|
||||
destination.close()
|
||||
|
||||
@group_required('Area_Director','Secretariat')
|
||||
def submit(request, name):
|
||||
# Get WG by acronym, redirecting if there's a newer acronym
|
||||
try:
|
||||
wg = Group.objects.get(acronym=name)
|
||||
except Group.DoesNotExist:
|
||||
wglist = GroupHistory.objects.filter(acronym=name)
|
||||
if wglist:
|
||||
return redirect('charter_submit', name=wglist[0].group.acronym)
|
||||
else:
|
||||
raise Http404()
|
||||
# Get charter
|
||||
charter = set_or_create_charter(wg)
|
||||
|
||||
login = request.user.get_profile()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = UploadForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
save_document_in_history(charter)
|
||||
# Also save group history so we can search for it
|
||||
save_group_in_history(wg)
|
||||
|
||||
# Search history for possible collisions with abandoned efforts
|
||||
rev_list = list(charter.history_set.order_by('-time').values_list('rev', flat=True))
|
||||
next_rev = next_revision(charter.rev)
|
||||
while next_rev in rev_list:
|
||||
next_rev = next_revision(next_rev)
|
||||
|
||||
charter.rev = next_rev
|
||||
|
||||
e = DocEvent()
|
||||
e.type = "new_revision"
|
||||
e.by = login
|
||||
e.doc = charter
|
||||
e.desc = "New version available: <b>charter-ietf-%s-%s.txt</b>" % (wg.acronym, charter.rev)
|
||||
e.save()
|
||||
|
||||
# Save file on disk
|
||||
form.save(wg, charter.rev)
|
||||
|
||||
charter.time = datetime.datetime.now()
|
||||
charter.save()
|
||||
|
||||
return HttpResponseRedirect(reverse('wg_view', kwargs={'name': wg.acronym}))
|
||||
else:
|
||||
filename = os.path.join(settings.CHARTER_PATH, 'charter-ietf-%s-%s.txt' % (wg.acronym, wg.charter.rev))
|
||||
try:
|
||||
charter_text = open(filename, 'r')
|
||||
init = dict(content=charter_text.read())
|
||||
except IOError:
|
||||
init = {}
|
||||
form = UploadForm(initial = init)
|
||||
return render_to_response('wgcharter/submit.html',
|
||||
{'form': form,
|
||||
'next_rev': next_revision(wg.charter.rev),
|
||||
'wg': wg},
|
||||
context_instance=RequestContext(request))
|
|
@ -171,6 +171,7 @@ form table .help {
|
|||
.big { font-size: 109.5%; margin: 0; padding: 0; }
|
||||
.large { font-size: 120%; margin: 0; padding: 0; }
|
||||
.huge { font-size: 144%; margin: 0; padding: 0; }
|
||||
.warning { color: #a00; }
|
||||
|
||||
.position-discuss,
|
||||
.position-block { background-color: #c00000;}
|
||||
|
@ -188,5 +189,9 @@ form table .help {
|
|||
.ballot-sidebar .position-group .was { padding-left: 10px; font-size:85%; }
|
||||
.ballot-sidebar .position-group:last-child { margin-bottom: 0; }
|
||||
|
||||
h2.ad-ballot-comment { background: #2647A0; color: #fff; padding: 2px 4px; font-size: 108%; margin-top: 0;}
|
||||
.ballot-content { margin-left: 15em; }
|
||||
.ballot-content .other-ballots { margin: 1em 0 2em 0; }
|
||||
.ballot-content .other-ballots a { display: inline-block; margin-right: 0.5em; }
|
||||
|
||||
.ballot-content h2.ad-ballot-comment { background: #2647A0; color: #fff; padding: 2px 4px; font-size: 108%; margin-top: 0;}
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
jQuery(function () {
|
||||
jQuery(".emails-field").each(function () {
|
||||
var e = jQuery(this);
|
||||
var pre = [];
|
||||
if (e.val())
|
||||
pre = JSON.parse(e.val());
|
||||
e.tokenInput(e.data("ajax-url"), {
|
||||
hintText: "",
|
||||
preventDuplicates: true,
|
||||
prePopulate: JSON.parse(e.val())
|
||||
prePopulate: pre
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue