Liasion Manager:
* Patch from Yaco to avoid resetting the From field when changing other items on the form * Gave the secretariat the ability to find/approve any unapproved liaisons * Changed all the email code to use ietf.mail.utils (and removed the fake-mail concept) Charter documents and the Agenda pages: * Added charter documents to iesg/agenda and iesg/agenda/documents * Synced the ordering of drafts on iesg/agenda and iesg/agenda/documents * Allow setting a responsible AD for charter documents * Changed the UI of the charter page to use editlink for changing attributes and buttons for actions (to align with drafts and conflict-reviews) Moderator package: * Refactor: Simplified access to the current BallotDocEvent from a Document * Added functions to BallotDocEvents? to faciliate access to BallotPositionDocEvents?, both for all positions, and current AD postions. * Updated the moderator package to use the Documents from _agenda_data. * Added a filter to assist with rendering the moderator package. * Fixed a bug where different functions in idrfc/views_ballot were using log_state_changed expecting different implementations (a cleanup task should reconcile the _three_ implementations in the codebase of that function). Cleanup from codesprint: * Removed some duplication between doc/util and doc/models by moving things into doc/models * Do not show non-empty discuss text when the ballot position is not blocking * Added a migration to update non-blocking ballot positions that have non-empty discuss text DEPLOYMENT NOTES Please be aware that migration step will take a few minutes to complete. Fixes bug 865 - Legacy-Id: 4772
This commit is contained in:
commit
e5c3a5adc5
372
ietf/doc/migrations/0004_clean_stale_discusses.py
Normal file
372
ietf/doc/migrations/0004_clean_stale_discusses.py
Normal file
|
@ -0,0 +1,372 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
|
||||
from person.models import Person
|
||||
from doc.models import BallotPositionDocEvent
|
||||
import sys
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
system_user = Person.objects.get(name="(System)")
|
||||
change_count=0
|
||||
progress=0
|
||||
print "starting"
|
||||
docset = set([e.doc for e in BallotPositionDocEvent.objects.exclude(pos__blocking=True).exclude(discuss="")])
|
||||
print "updating non-blocking positions with non-empty discusses on",len(docset),"documents"
|
||||
for doc in docset:
|
||||
ballot_positions = BallotPositionDocEvent.objects.filter(doc=doc,type="changed_ballot_position")
|
||||
for ad in set([e.ad for e in ballot_positions]):
|
||||
e = ballot_positions.filter(ad=ad).order_by("-time")[0]
|
||||
if e.discuss and not e.pos.blocking:
|
||||
# time and discuss are intentionally not part of what update gets initialized with
|
||||
update = BallotPositionDocEvent(doc=e.doc,type=e.type,by=e.by,ballot=e.ballot,ad=e.ad,pos=e.pos,discuss_time=e.discuss_time,comment=e.comment,comment_time=e.comment_time)
|
||||
update.by=system_user
|
||||
update.desc="post-migration administrative database adjustment to the "+e.pos.name+" position for "+e.ad.plain_name()
|
||||
update.save()
|
||||
change_count += 1
|
||||
progress +=1
|
||||
if not (progress % 100):
|
||||
print str(progress)+",",
|
||||
sys.stdout.flush()
|
||||
print
|
||||
print "Updated",change_count,"positions"
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
pass
|
||||
|
||||
models = {
|
||||
'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'auth.permission': {
|
||||
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'})
|
||||
},
|
||||
'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'doc.ballotdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ballot_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.BallotType']"}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.ballotpositiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'BallotPositionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'ballot': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['doc.BallotDocEvent']", 'null': 'True'}),
|
||||
'comment': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'comment_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'discuss': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'discuss_time': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'pos': ('django.db.models.fields.related.ForeignKey', [], {'default': "'norecord'", 'to': "orm['name.BallotPositionName']"})
|
||||
},
|
||||
'doc.ballottype': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotType'},
|
||||
'doc_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'positions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.BallotPositionName']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'question': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.docalias': {
|
||||
'Meta': {'object_name': 'DocAlias'},
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
|
||||
},
|
||||
'doc.docevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'DocEvent'},
|
||||
'by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']"}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
'doc.dochistory': {
|
||||
'Meta': {'object_name': 'DocHistory'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocHistoryAuthor']", 'blank': 'True'}),
|
||||
'doc': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'history_set'", 'to': "orm['doc.Document']"}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.DocAlias']", 'symmetrical': 'False', 'through': "orm['doc.RelatedDocHistory']", 'blank': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_dochistory_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.dochistoryauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocHistoryAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {})
|
||||
},
|
||||
'doc.docreminder': {
|
||||
'Meta': {'object_name': 'DocReminder'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'due': ('django.db.models.fields.DateTimeField', [], {}),
|
||||
'event': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocEvent']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocReminderTypeName']"})
|
||||
},
|
||||
'doc.document': {
|
||||
'Meta': {'object_name': 'Document'},
|
||||
'abstract': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'ad_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['person.Email']", 'symmetrical': 'False', 'through': "orm['doc.DocumentAuthor']", 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'external_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'intended_std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.IntendedStdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'internal_comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'primary_key': 'True'}),
|
||||
'note': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'notify': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1', 'blank': 'True'}),
|
||||
'pages': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'related': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'reversely_related_document_set'", 'blank': 'True', 'through': "orm['doc.RelatedDocument']", 'to': "orm['doc.DocAlias']"}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
|
||||
'shepherd': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'shepherd_document_set'", 'null': 'True', 'to': "orm['person.Person']"}),
|
||||
'states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'std_level': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StdLevelName']", 'null': 'True', 'blank': 'True'}),
|
||||
'stream': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.StreamName']", 'null': 'True', 'blank': 'True'}),
|
||||
'tags': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['name.DocTagName']", 'null': 'True', 'blank': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocTypeName']", 'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.documentauthor': {
|
||||
'Meta': {'ordering': "['document', 'order']", 'object_name': 'DocumentAuthor'},
|
||||
'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Email']"}),
|
||||
'document': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '1'})
|
||||
},
|
||||
'doc.initialreviewdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'InitialReviewDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.lastcalldocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'LastCallDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.newrevisiondocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'NewRevisionDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'rev': ('django.db.models.fields.CharField', [], {'max_length': '16'})
|
||||
},
|
||||
'doc.relateddochistory': {
|
||||
'Meta': {'object_name': 'RelatedDocHistory'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocHistory']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reversely_related_document_history_set'", 'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.relateddocument': {
|
||||
'Meta': {'object_name': 'RelatedDocument'},
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'relationship': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.DocRelationshipName']"}),
|
||||
'source': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.Document']"}),
|
||||
'target': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.DocAlias']"})
|
||||
},
|
||||
'doc.state': {
|
||||
'Meta': {'ordering': "['type', 'order']", 'object_name': 'State'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'next_states': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'previous_states'", 'symmetrical': 'False', 'to': "orm['doc.State']"}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['doc.StateType']"}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'doc.statetype': {
|
||||
'Meta': {'object_name': 'StateType'},
|
||||
'label': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '30', 'primary_key': 'True'})
|
||||
},
|
||||
'doc.telechatdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'TelechatDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'returning_item': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'telechat_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'doc.writeupdocevent': {
|
||||
'Meta': {'ordering': "['-time', '-id']", 'object_name': 'WriteupDocEvent', '_ormbases': ['doc.DocEvent']},
|
||||
'docevent_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['doc.DocEvent']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'text': ('django.db.models.fields.TextField', [], {'blank': 'True'})
|
||||
},
|
||||
'group.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
'acronym': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '40', 'db_index': 'True'}),
|
||||
'ad': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True', 'blank': 'True'}),
|
||||
'charter': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'chartered_group'", 'unique': 'True', 'null': 'True', 'to': "orm['doc.Document']"}),
|
||||
'comments': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'list_archive': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'list_email': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
|
||||
'list_subscribe': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group.Group']", 'null': 'True', 'blank': 'True'}),
|
||||
'state': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupStateName']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['name.GroupTypeName']", 'null': 'True'}),
|
||||
'unused_states': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['doc.State']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'unused_tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['name.DocTagName']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'name.ballotpositionname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'BallotPositionName'},
|
||||
'blocking': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docrelationshipname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocRelationshipName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.docremindertypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocReminderTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctagname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTagName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.doctypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'DocTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.groupstatename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupStateName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.grouptypename': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'GroupTypeName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.intendedstdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'IntendedStdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.stdlevelname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StdLevelName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'name.streamname': {
|
||||
'Meta': {'ordering': "['order']", 'object_name': 'StreamName'},
|
||||
'desc': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'slug': ('django.db.models.fields.CharField', [], {'max_length': '8', 'primary_key': 'True'}),
|
||||
'used': ('django.db.models.fields.BooleanField', [], {'default': 'True'})
|
||||
},
|
||||
'person.email': {
|
||||
'Meta': {'object_name': 'Email'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'address': ('django.db.models.fields.CharField', [], {'max_length': '64', 'primary_key': 'True'}),
|
||||
'person': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['person.Person']", 'null': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'})
|
||||
},
|
||||
'person.person': {
|
||||
'Meta': {'object_name': 'Person'},
|
||||
'address': ('django.db.models.fields.TextField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'affiliation': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
|
||||
'ascii': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'ascii_short': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
|
||||
'time': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True', 'null': 'True', 'blank': 'True'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['doc']
|
|
@ -259,29 +259,21 @@ class Document(DocumentInfo):
|
|||
return self.latest_event(type="changed_document", desc__startswith="State changed to <b>IESG Evaluation - Defer</b>")
|
||||
return None
|
||||
|
||||
def active_ballot(self):
|
||||
ballot = self.latest_event(BallotDocEvent, type="created_ballot")
|
||||
e = self.latest_event(BallotDocEvent, ballot_type__slug=ballot.ballot_type.slug) if ballot else None
|
||||
open = e and not e.type == "closed_ballot"
|
||||
return ballot.ballot_type if open else None
|
||||
# This, and several other ballot related functions here, assume that there is only one active ballot for a document at any point in time.
|
||||
# If that assumption is violated, they will only expose the most recently created ballot
|
||||
def ballot_open(self, ballot_type_slug):
|
||||
e = self.latest_event(BallotDocEvent, ballot_type__slug=ballot_type_slug)
|
||||
return e and not e.type == "closed_ballot"
|
||||
|
||||
def active_ballot_positions(self):
|
||||
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
|
||||
res = {}
|
||||
|
||||
def active_ballot(self):
|
||||
"""Returns the most recently created ballot if it isn't closed."""
|
||||
ballot = self.latest_event(BallotDocEvent, type="created_ballot")
|
||||
positions = BallotPositionDocEvent.objects.filter(doc=self, type="changed_ballot_position", ad__in=active_ads, ballot=ballot).select_related('ad', 'pos').order_by("-time", "-id")
|
||||
|
||||
for pos in positions:
|
||||
if pos.ad not in res:
|
||||
res[pos.ad] = pos
|
||||
|
||||
for ad in active_ads:
|
||||
if ad not in res:
|
||||
res[ad] = None
|
||||
|
||||
return res.values()
|
||||
open = self.ballot_open(ballot.ballot_type.slug) if ballot else False
|
||||
return ballot if open else None
|
||||
|
||||
def most_recent_ietflc(self):
|
||||
"""Returns the most recent IETF LastCallDocEvent for this document"""
|
||||
return self.latest_event(LastCallDocEvent,type="sent_last_call")
|
||||
|
||||
def displayname_with_link(self):
|
||||
return '<a href="%s">%s-%s</a>' % (self.get_absolute_url(), self.name , self.rev)
|
||||
|
@ -526,6 +518,59 @@ class BallotType(models.Model):
|
|||
class BallotDocEvent(DocEvent):
|
||||
ballot_type = models.ForeignKey(BallotType)
|
||||
|
||||
def active_ad_positions(self):
|
||||
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
|
||||
res = {}
|
||||
|
||||
if self.doc.latest_event(BallotDocEvent, type="created_ballot") == self:
|
||||
|
||||
positions = BallotPositionDocEvent.objects.filter(type="changed_ballot_position",ad__in=active_ads, ballot=self).select_related('ad', 'pos').order_by("-time", "-id")
|
||||
|
||||
for pos in positions:
|
||||
if pos.ad not in res:
|
||||
res[pos.ad] = pos
|
||||
|
||||
for ad in active_ads:
|
||||
if ad not in res:
|
||||
res[ad] = None
|
||||
return res
|
||||
|
||||
def all_positions(self):
|
||||
"""Return array holding the current and past positions per AD"""
|
||||
|
||||
positions = []
|
||||
seen = {}
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
|
||||
for e in BallotPositionDocEvent.objects.filter(type="changed_ballot_position", ballot=self).select_related('ad', 'pos').order_by("-time", '-id'):
|
||||
if e.ad not in seen:
|
||||
e.old_ad = e.ad not in active_ads
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
seen[e.ad] = e
|
||||
else:
|
||||
latest = seen[e.ad]
|
||||
if latest.old_positions:
|
||||
prev = latest.old_positions[-1]
|
||||
else:
|
||||
prev = latest.pos
|
||||
|
||||
if e.pos != prev:
|
||||
latest.old_positions.append(e.pos)
|
||||
|
||||
# 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=self.doc, ad=ad)
|
||||
e.pos = norecord
|
||||
e.old_ad = False
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
|
||||
positions.sort(key=lambda p: (p.old_ad, p.ad.last_name()))
|
||||
return positions
|
||||
|
||||
class BallotPositionDocEvent(DocEvent):
|
||||
ballot = models.ForeignKey(BallotDocEvent, null=True, default=None) # default=None is a temporary migration period fix, should be removed when charter branch is live
|
||||
ad = models.ForeignKey(Person)
|
||||
|
|
|
@ -550,10 +550,9 @@ class InternetDraft(Document):
|
|||
def active_positions(self):
|
||||
"""Returns a list of dicts, with AD and Position tuples"""
|
||||
from ietf.person.proxy import IESGLogin as IESGLoginProxy
|
||||
from ietf.doc.utils import active_ballot_positions
|
||||
|
||||
res = []
|
||||
for ad, pos in active_ballot_positions(self).iteritems():
|
||||
for ad, pos in self.active_ballot().active_ad_positions().iteritems():
|
||||
res.append(dict(ad=IESGLoginProxy().from_object(ad), pos=Position().from_object(pos) if pos else None))
|
||||
|
||||
res.sort(key=lambda x: x["ad"].last_name)
|
||||
|
|
|
@ -13,7 +13,7 @@ from django.core.urlresolvers import reverse as urlreverse
|
|||
from ietf.utils.test_utils import login_testing_unauthorized
|
||||
from ietf.utils.test_data import make_test_data
|
||||
from ietf.utils.mail import outbox
|
||||
from ietf.doc.utils import active_ballot, create_ballot_if_not_open, ballot_open
|
||||
from ietf.doc.utils import create_ballot_if_not_open
|
||||
from ietf.doc.views_conflict_review import default_approval_text
|
||||
|
||||
from ietf.doc.models import Document,DocEvent,NewRevisionDocEvent,BallotPositionDocEvent,TelechatDocEvent,DocAlias,State
|
||||
|
@ -105,7 +105,7 @@ class ConflictReviewTestCase(django.test.TestCase):
|
|||
review_doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
self.assertEquals(review_doc.get_state('conflrev').slug,'adrev')
|
||||
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith('RDNK84ZD'))
|
||||
self.assertFalse(active_ballot(review_doc))
|
||||
self.assertFalse(review_doc.active_ballot())
|
||||
|
||||
# successful change to IESG Evaluation
|
||||
iesgeval_pk = str(State.objects.get(slug='iesgeval',type__slug='conflrev').pk)
|
||||
|
@ -114,7 +114,7 @@ class ConflictReviewTestCase(django.test.TestCase):
|
|||
review_doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
self.assertEquals(review_doc.get_state('conflrev').slug,'iesgeval')
|
||||
self.assertTrue(review_doc.latest_event(DocEvent,type="added_comment").desc.startswith('TGmZtEjt'))
|
||||
self.assertTrue(active_ballot(review_doc))
|
||||
self.assertTrue(review_doc.active_ballot())
|
||||
self.assertEquals(review_doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position").pos_id,'yes')
|
||||
|
||||
|
||||
|
@ -234,7 +234,7 @@ class ConflictReviewTestCase(django.test.TestCase):
|
|||
|
||||
doc = Document.objects.get(name='conflict-review-imaginary-irtf-submission')
|
||||
self.assertEquals(doc.get_state_slug(),approve_type+'-sent')
|
||||
self.assertFalse(ballot_open(doc, "conflrev"))
|
||||
self.assertFalse(doc.ballot_open("conflrev"))
|
||||
|
||||
self.assertEquals(len(outbox), messages_before + 1)
|
||||
self.assertTrue('Results of IETF-conflict review' in outbox[-1]['Subject'])
|
||||
|
|
|
@ -36,34 +36,6 @@ def get_tags_for_stream_id(stream_id):
|
|||
else:
|
||||
return []
|
||||
|
||||
# This, and several other utilities here, assume that there is only one active ballot for a document at any point in time.
|
||||
# If that assumption is violated, they will only expose the most recently created ballot
|
||||
def active_ballot(doc):
|
||||
"""Returns the most recently created ballot if it isn't closed."""
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
|
||||
open = ballot_open(doc,ballot.ballot_type.slug) if ballot else False
|
||||
return ballot if open else None
|
||||
|
||||
|
||||
def active_ballot_positions(doc, ballot=None):
|
||||
"""Return dict mapping each active AD to a current ballot position (or None if they haven't voted)."""
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active"))
|
||||
res = {}
|
||||
|
||||
if not ballot:
|
||||
ballot = doc.latest_event(BallotDocEvent, type="created_ballot")
|
||||
positions = BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ad__in=active_ads, ballot=ballot).select_related('ad', 'pos').order_by("-time", "-id")
|
||||
|
||||
for pos in positions:
|
||||
if pos.ad not in res:
|
||||
res[pos.ad] = pos
|
||||
|
||||
for ad in active_ads:
|
||||
if ad not in res:
|
||||
res[ad] = None
|
||||
|
||||
return res
|
||||
|
||||
def needed_ballot_positions(doc, active_positions):
|
||||
'''Returns text answering the question "what does this document
|
||||
need to pass?". The return value is only useful if the document
|
||||
|
@ -102,12 +74,8 @@ def needed_ballot_positions(doc, active_positions):
|
|||
|
||||
return " ".join(answer)
|
||||
|
||||
def ballot_open(doc, ballot_type_slug):
|
||||
e = doc.latest_event(BallotDocEvent, ballot_type__slug=ballot_type_slug)
|
||||
return e and not e.type == "closed_ballot"
|
||||
|
||||
def create_ballot_if_not_open(doc, by, ballot_type_slug):
|
||||
if not ballot_open(doc, ballot_type_slug):
|
||||
if not doc.ballot_open(ballot_type_slug):
|
||||
e = BallotDocEvent(type="created_ballot", by=by, doc=doc)
|
||||
e.ballot_type = BallotType.objects.get(doc_type=doc.type, slug=ballot_type_slug)
|
||||
e.desc = u'Created "%s" ballot' % e.ballot_type.name
|
||||
|
@ -115,7 +83,7 @@ def create_ballot_if_not_open(doc, by, ballot_type_slug):
|
|||
|
||||
def close_open_ballots(doc, by):
|
||||
for t in BallotType.objects.filter(doc_type=doc.type_id):
|
||||
if ballot_open(doc, t.slug):
|
||||
if doc.ballot_open(t.slug):
|
||||
e = BallotDocEvent(type="closed_ballot", doc=doc, by=by)
|
||||
e.ballot_type = t
|
||||
e.desc = 'Closed "%s" ballot' % t.name
|
||||
|
|
|
@ -37,7 +37,6 @@ from ietf.idtracker.models import IDInternal, BallotInfo
|
|||
from ietf.idrfc.idrfc_wrapper import position_to_string, BALLOT_ACTIVE_STATES
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group, timesince_days
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
from ietf.doc.utils import active_ballot_positions
|
||||
from ietf.doc.models import BallotDocEvent
|
||||
|
||||
register = template.Library()
|
||||
|
@ -83,7 +82,7 @@ def render_ballot_icon(user, doc):
|
|||
else:
|
||||
return (1, pos.pos.order)
|
||||
|
||||
positions = list(active_ballot_positions(doc, ballot).items())
|
||||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
|
|
|
@ -38,7 +38,6 @@ from ietf.idtracker.models import IDInternal, BallotInfo
|
|||
from ietf.idrfc.idrfc_wrapper import position_to_string, BALLOT_ACTIVE_STATES
|
||||
from ietf.idtracker.templatetags.ietf_filters import in_group, timesince_days
|
||||
from ietf.ietfauth.decorators import has_role
|
||||
from ietf.doc.utils import active_ballot_positions, active_ballot
|
||||
from ietf.doc.models import BallotDocEvent, BallotPositionDocEvent
|
||||
|
||||
from datetime import date
|
||||
|
@ -90,7 +89,7 @@ def render_ballot_icon(user, doc):
|
|||
else:
|
||||
return (1, pos.pos.order)
|
||||
|
||||
positions = list(active_ballot_positions(doc, ballot).items())
|
||||
positions = list(doc.active_ballot().active_ad_positions().items())
|
||||
positions.sort(key=sort_key)
|
||||
|
||||
cm = ""
|
||||
|
@ -144,7 +143,7 @@ def my_position(doc, user):
|
|||
return None
|
||||
if not in_group(user, "Area_Director"):
|
||||
return None
|
||||
ballot = active_ballot(doc)
|
||||
ballot = doc.active_ballot()
|
||||
pos = "No Record"
|
||||
if ballot:
|
||||
changed_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad__name=user_name, ballot=ballot)
|
||||
|
|
|
@ -35,7 +35,8 @@ from ietf.name.models import BallotPositionName
|
|||
from ietf.message.utils import infer_message
|
||||
from ietf.person.models import Person
|
||||
|
||||
from ietf.doc.utils import log_state_changed
|
||||
from ietf.doc.utils import log_state_changed as docutil_log_state_changed
|
||||
from ietf.idrfc.utils import log_state_changed as idrfcutil_log_state_changed
|
||||
|
||||
BALLOT_CHOICES = (("yes", "Yes"),
|
||||
("noobj", "No Objection"),
|
||||
|
@ -431,7 +432,7 @@ def defer_ballotREDESIGN(request, name):
|
|||
elif doc.type_id == 'conflrev':
|
||||
doc.set_state(State.objects.get(type='conflrev', slug='defer'))
|
||||
|
||||
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -481,7 +482,7 @@ def undefer_ballotREDESIGN(request, name):
|
|||
elif doc.type_id == 'conflrev':
|
||||
doc.set_state(State.objects.get(type='conflrev',slug='iesgeval'))
|
||||
|
||||
e = log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
e = docutil_log_state_changed(request, doc, login, doc.friendly_state(), prev_state)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -557,7 +558,7 @@ def lastcalltext(request, name):
|
|||
if "send_last_call_request" in request.POST:
|
||||
doc.idinternal.change_state(IDState.objects.get(document_state_id=IDState.LAST_CALL_REQUESTED), None)
|
||||
|
||||
change = log_state_changed(request, doc, login)
|
||||
change = idrfcutil_log_state_changed(request, doc, login)
|
||||
email_owner(request, doc, doc.idinternal.job_owner, login, change)
|
||||
request_last_call(request, doc)
|
||||
|
||||
|
@ -646,7 +647,7 @@ def lastcalltextREDESIGN(request, name):
|
|||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -1093,7 +1094,7 @@ def approve_ballotREDESIGN(request, name):
|
|||
|
||||
change_description = e.desc + " and state has been changed to %s" % doc.get_state("draft-iesg").name
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
@ -1153,7 +1154,7 @@ def make_last_call(request, name):
|
|||
doc.idinternal.event_date = date.today()
|
||||
doc.idinternal.save()
|
||||
|
||||
log_state_changed(request, doc, login)
|
||||
idrfcutil_log_state_changed(request, doc, login)
|
||||
|
||||
doc.lc_sent_date = form.cleaned_data['last_call_sent_date']
|
||||
doc.lc_expiration_date = form.cleaned_data['last_call_expiration_date']
|
||||
|
@ -1216,7 +1217,7 @@ def make_last_callREDESIGN(request, name):
|
|||
if prev_tag:
|
||||
doc.tags.remove(prev_tag)
|
||||
|
||||
e = log_state_changed(request, doc, login, prev, prev_tag)
|
||||
e = idrfcutil_log_state_changed(request, doc, login, prev, prev_tag)
|
||||
|
||||
doc.time = e.time
|
||||
doc.save()
|
||||
|
|
|
@ -143,7 +143,7 @@ def document_main(request, name, rev=None):
|
|||
|
||||
ballot_summary = None
|
||||
if doc.get_state_slug() in ("intrev", "iesgrev"):
|
||||
ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
|
||||
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
|
||||
|
||||
return render_to_response("idrfc/document_charter.html",
|
||||
dict(doc=doc,
|
||||
|
@ -171,7 +171,7 @@ def document_main(request, name, rev=None):
|
|||
|
||||
ballot_summary = None
|
||||
if doc.get_state_slug() in ("iesgeval"):
|
||||
ballot_summary = needed_ballot_positions(doc, active_ballot_positions(doc).values())
|
||||
ballot_summary = needed_ballot_positions(doc, doc.active_ballot().active_ad_positions().values())
|
||||
|
||||
return render_to_response("idrfc/document_conflict_review.html",
|
||||
dict(doc=doc,
|
||||
|
@ -292,36 +292,7 @@ def document_ballot_content(request, doc, ballot_id, editable=True):
|
|||
|
||||
deferred = doc.active_defer_event()
|
||||
|
||||
# collect positions
|
||||
active_ads = list(Person.objects.filter(role__name="ad", role__group__state="active").distinct())
|
||||
|
||||
positions = []
|
||||
seen = {}
|
||||
for e in BallotPositionDocEvent.objects.filter(doc=doc, type="changed_ballot_position", ballot=ballot).select_related('ad', 'pos').order_by("-time", '-id'):
|
||||
if e.ad not in seen:
|
||||
e.old_ad = e.ad not in active_ads
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
seen[e.ad] = e
|
||||
else:
|
||||
latest = seen[e.ad]
|
||||
if latest.old_positions:
|
||||
prev = latest.old_positions[-1]
|
||||
else:
|
||||
prev = latest.pos.name
|
||||
|
||||
if e.pos.name != prev:
|
||||
latest.old_positions.append(e.pos.name)
|
||||
|
||||
# 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 = norecord
|
||||
e.old_ad = False
|
||||
e.old_positions = []
|
||||
positions.append(e)
|
||||
positions = doc.active_ballot().all_positions() if doc.active_ballot() else []
|
||||
|
||||
# put into position groups
|
||||
position_groups = []
|
||||
|
|
|
@ -146,6 +146,15 @@ def square_brackets(value):
|
|||
else:
|
||||
return "[ ]"
|
||||
|
||||
@register.filter(name='bracketpos')
|
||||
def bracketpos(pos,posslug):
|
||||
if pos.pos.slug==posslug:
|
||||
return "[ X ]"
|
||||
elif posslug in [x.slug for x in pos.old_positions]:
|
||||
return "[ . ]"
|
||||
else:
|
||||
return "[ ]"
|
||||
|
||||
@register.filter(name='fill')
|
||||
def fill(text, width):
|
||||
"""Wraps each paragraph in text (a string) so every line
|
||||
|
|
|
@ -207,6 +207,9 @@ def agenda_docs(date, next_agenda):
|
|||
m.balloting_started = e.time if e else datetime.datetime.min
|
||||
|
||||
docmatches.append(m)
|
||||
|
||||
# Be careful to keep this the same as what's used in agenda_documents
|
||||
docmatches.sort(key=lambda d: d.balloting_started)
|
||||
|
||||
res = dict(("s%s%s%s" % (i, j, k), []) for i in range(2, 5) for j in range (1, 4) for k in range(1, 4))
|
||||
for id in docmatches:
|
||||
|
@ -232,7 +235,8 @@ def agenda_wg_actions(date):
|
|||
section_key = "s" + get_wg_section(c.group)
|
||||
if section_key not in res:
|
||||
res[section_key] = []
|
||||
res[section_key].append({'obj': c.group})
|
||||
# Cleanup - Older view code wants obj, newer wants doc. Older code should be moved forward
|
||||
res[section_key].append({'obj': c.group, 'doc': c})
|
||||
return res
|
||||
|
||||
def agenda_management_issues(date):
|
||||
|
@ -370,6 +374,7 @@ def _agenda_data(request, date=None):
|
|||
def agenda(request, date=None):
|
||||
data = _agenda_data(request, date)
|
||||
data['private'] = 'private' in request.REQUEST
|
||||
data['settings'] = settings
|
||||
return render_to_response("iesg/agenda.html", data, context_instance=RequestContext(request))
|
||||
|
||||
def agenda_txt(request):
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# coding: latin-1
|
||||
|
||||
from types import ModuleType
|
||||
import urls, models, views, forms, accounts, admin, utils, widgets, mail, decorators, sitemaps, feeds
|
||||
import urls, models, views, forms, accounts, admin, utils, widgets, decorators, sitemaps, feeds
|
||||
|
||||
# These people will be sent a stack trace if there's an uncaught exception in
|
||||
# code any of the modules imported above:
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
from django.core.mail import EmailMessage
|
||||
|
||||
# FIXME: this is not using the ietf mail stuff, which it really should
|
||||
# - this code should be DELETED
|
||||
|
||||
class IETFEmailMessage(EmailMessage):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
cc = kwargs.pop('cc', [])
|
||||
if cc:
|
||||
assert isinstance(cc, (list, tuple)), '"cc" argument must be a list or tuple'
|
||||
self.cc = list(cc)
|
||||
else:
|
||||
self.cc = []
|
||||
super(IETFEmailMessage, self).__init__(*args, **kwargs)
|
||||
|
||||
def message(self):
|
||||
msg = super(IETFEmailMessage, self).message()
|
||||
if self.cc:
|
||||
msg['Cc'] = ', '.join(self.cc)
|
||||
if self.bcc:
|
||||
msg['Bcc'] = ', '.join(self.bcc)
|
||||
return msg
|
||||
|
||||
def recipients(self):
|
||||
return self.to + self.cc + self.bcc
|
|
@ -26,17 +26,6 @@ def send_liaison_by_email(request, liaison, fake=False):
|
|||
url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.pk)),
|
||||
referenced_url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.related_to.pk)) if liaison.related_to else None,
|
||||
))
|
||||
if fake:
|
||||
# rather than this fake stuff, it's probably better to start a
|
||||
# debug SMTP server as explained in the Django docs
|
||||
from ietf.liaisons.mail import IETFEmailMessage
|
||||
mail = IETFEmailMessage(subject=subject,
|
||||
to=to_email,
|
||||
from_email=from_email,
|
||||
cc = cc,
|
||||
bcc = bcc,
|
||||
body = body)
|
||||
return mail
|
||||
|
||||
send_mail_text(request, to_email, from_email, subject, body, cc=", ".join(cc), bcc=", ".join(bcc))
|
||||
|
||||
|
@ -56,12 +45,6 @@ def notify_pending_by_email(request, liaison, fake):
|
|||
url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk)),
|
||||
referenced_url=settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.related_to.pk)) if liaison.related_to else None,
|
||||
))
|
||||
if fake:
|
||||
mail = IETFEmailMessage(subject=subject,
|
||||
to=to_email,
|
||||
from_email=from_email,
|
||||
body = body)
|
||||
return mail
|
||||
send_mail_text(request, to_email, from_email, subject, body)
|
||||
|
||||
def send_sdo_reminder(sdo):
|
||||
|
|
|
@ -6,7 +6,8 @@ from django.template.loader import render_to_string
|
|||
from django.core.urlresolvers import reverse as urlreverse
|
||||
|
||||
from ietf.liaisons.models import LiaisonDetail
|
||||
from ietf.liaisons.mail import IETFEmailMessage
|
||||
#from ietf.liaisons.mail import IETFEmailMessage
|
||||
from ietf.utils.mail import send_mail_text
|
||||
|
||||
|
||||
PREVIOUS_DAYS = {
|
||||
|
@ -44,17 +45,20 @@ class Command(BaseCommand):
|
|||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=liaison.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=liaison.related_to.pk)) if liaison.related_to else None,
|
||||
})
|
||||
mail = IETFEmailMessage(subject=subject,
|
||||
to=to_email,
|
||||
from_email=from_email,
|
||||
cc=cc,
|
||||
bcc=bcc,
|
||||
body=body)
|
||||
if not settings.DEBUG:
|
||||
mail.send()
|
||||
print 'Liaison %05s#: Deadline reminder Sent!' % liaison.pk
|
||||
else:
|
||||
print 'Liaison %05s#: Deadline reminder Not Sent because in DEBUG mode!' % liaison.pk
|
||||
send_mail_text(context=None,to=to_email,frm=from_email,cc=cc,subject=subject,bcc=bcc,txt=body)
|
||||
print 'Liaison %05s#: Deadline reminder Sent!' % liaison.pk
|
||||
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# cc=cc,
|
||||
# bcc=bcc,
|
||||
# body=body)
|
||||
#if not settings.DEBUG:
|
||||
# mail.send()
|
||||
# print 'Liaison %05s#: Deadline reminder Sent!' % liaison.pk
|
||||
#else:
|
||||
# print 'Liaison %05s#: Deadline reminder Not Sent because in DEBUG mode!' % liaison.pk
|
||||
|
||||
def handle(self, *args, **options):
|
||||
today = datetime.date.today()
|
||||
|
|
|
@ -7,7 +7,8 @@ from django.template.loader import render_to_string
|
|||
from django.contrib.auth.models import User
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from ietf.idtracker.models import Acronym, PersonOrOrgInfo, Area, IESGLogin
|
||||
from ietf.liaisons.mail import IETFEmailMessage
|
||||
#from ietf.liaisons.mail import IETFEmailMessage
|
||||
from ietf.utils.mail import send_mail_text
|
||||
from ietf.ietfauth.models import LegacyLiaisonUser
|
||||
from ietf.utils.admin import admin_link
|
||||
|
||||
|
@ -147,13 +148,14 @@ class LiaisonDetail(models.Model):
|
|||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_approval_detail", kwargs=dict(object_id=self.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.related_to.pk)) if self.related_to else None,
|
||||
})
|
||||
mail = IETFEmailMessage(subject=subject,
|
||||
to=to_email,
|
||||
from_email=from_email,
|
||||
body = body)
|
||||
if not fake:
|
||||
mail.send()
|
||||
return mail
|
||||
send_mail_text(context=None, to=to_email, frm=from_email, subject=subject, txt = body)
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# body = body)
|
||||
#if not fake:
|
||||
# mail.send()
|
||||
#return mail
|
||||
|
||||
def send_by_email(self, fake=False):
|
||||
if self.is_pending():
|
||||
|
@ -172,15 +174,16 @@ class LiaisonDetail(models.Model):
|
|||
'url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.pk)),
|
||||
'referenced_url': settings.IDTRACKER_BASE_URL + urlreverse("liaison_detail", kwargs=dict(object_id=self.related_to.pk)) if self.related_to else None,
|
||||
})
|
||||
mail = IETFEmailMessage(subject=subject,
|
||||
to=to_email,
|
||||
from_email=from_email,
|
||||
cc = cc,
|
||||
bcc = bcc,
|
||||
body = body)
|
||||
if not fake:
|
||||
mail.send()
|
||||
return mail
|
||||
send_mail_text(context=None,to=to_email,frm=from_email,subject=subject,txt=body,cc=cc,bcc=bcc)
|
||||
#mail = IETFEmailMessage(subject=subject,
|
||||
# to=to_email,
|
||||
# from_email=from_email,
|
||||
# cc = cc,
|
||||
# bcc = bcc,
|
||||
# body = body)
|
||||
#if not fake:
|
||||
# mail.send()
|
||||
#return mail
|
||||
|
||||
def is_pending(self):
|
||||
return bool(self.approval and not self.approval.approved)
|
||||
|
|
|
@ -33,10 +33,7 @@ def add_liaison(request, liaison=None):
|
|||
if form.is_valid():
|
||||
liaison = form.save()
|
||||
if request.POST.get('send', None):
|
||||
if not settings.DEBUG:
|
||||
liaison.send_by_email()
|
||||
else:
|
||||
return _fake_email_view(request, liaison)
|
||||
liaison.send_by_email()
|
||||
return HttpResponseRedirect(reverse('liaison_list'))
|
||||
else:
|
||||
form = liaison_form_factory(request, liaison=liaison)
|
||||
|
@ -89,14 +86,6 @@ def get_info(request):
|
|||
return HttpResponse(json_result, mimetype='text/javascript')
|
||||
|
||||
|
||||
def _fake_email_view(request, liaison):
|
||||
mail = liaison.send_by_email(fake=True)
|
||||
return render_to_response('liaisons/liaison_mail_detail.html',
|
||||
{'mail': mail,
|
||||
'message': mail.message(),
|
||||
'liaison': liaison},
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
def approvable_liaison_statements(group_codes):
|
||||
# this is a bit complicated because IETFHM encodes the
|
||||
|
@ -160,12 +149,15 @@ def liaison_list(request):
|
|||
|
||||
@can_submit_liaison
|
||||
def liaison_approval_list(request):
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
to_approve = approvable_liaison_statements(approval_codes).order_by("-submitted")
|
||||
if is_secretariat(request.user):
|
||||
to_approve = LiaisonDetail.objects.filter(approved=None).order_by("-submitted")
|
||||
else:
|
||||
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
to_approve = approvable_liaison_statements(approval_codes).order_by("-submitted")
|
||||
else:
|
||||
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
|
||||
|
||||
return object_list(request, to_approve,
|
||||
allow_empty=True,
|
||||
|
@ -175,12 +167,15 @@ def liaison_approval_list(request):
|
|||
|
||||
@can_submit_liaison
|
||||
def liaison_approval_detail(request, object_id):
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
to_approve = approvable_liaison_statements(approval_codes).order_by("-submitted")
|
||||
if is_secretariat(request.user):
|
||||
to_approve = LiaisonDetail.objects.filter(approved=None).order_by("-submitted")
|
||||
else:
|
||||
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
|
||||
person = get_person_for_user(request.user)
|
||||
approval_codes = IETFHM.get_all_can_approve_codes(person)
|
||||
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||
to_approve = approvable_liaison_statements(approval_codes).order_by("-submitted")
|
||||
else:
|
||||
to_approve = LiaisonDetail.objects.filter(approval__isnull=False, approval__approved=False, from_raw_code__in=approval_codes).order_by("-submitted_date")
|
||||
|
||||
if request.method=='POST' and request.POST.get('do_approval', False):
|
||||
try:
|
||||
|
@ -197,10 +192,7 @@ def liaison_approval_detail(request, object_id):
|
|||
else:
|
||||
approval.approved=True
|
||||
approval.save()
|
||||
if not settings.DEBUG:
|
||||
liaison.send_by_email()
|
||||
else:
|
||||
return _fake_email_view(request, liaison)
|
||||
liaison.send_by_email()
|
||||
except LiaisonDetail.DoesNotExist:
|
||||
pass
|
||||
return HttpResponseRedirect(reverse('liaison_list'))
|
||||
|
|
|
@ -17,7 +17,6 @@ from ietf.ietfauth.decorators import has_role
|
|||
|
||||
from ietf.doc.models import *
|
||||
from ietf.person.models import Person, Alias, Email
|
||||
from ietf.doc.utils import active_ballot_positions
|
||||
from ietf.message.models import Message
|
||||
|
||||
# Some useful states
|
||||
|
@ -262,7 +261,7 @@ def announce_new_versionREDESIGN(request, submission, draft, state_change_msg):
|
|||
if draft.ad:
|
||||
to_email.append(draft.ad.role_email("ad").address)
|
||||
|
||||
for ad, pos in active_ballot_positions(draft).iteritems():
|
||||
for ad, pos in draft.active_ballot().active_ad_positions().iteritems():
|
||||
if pos and pos.pos_id == "discuss":
|
||||
to_email.append(ad.role_email("ad").address)
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
{% for p in text_positions %}
|
||||
<h2 id="{{ p.ad.plain_name|slugify }}" class="ad-ballot-comment">{% if p.old_ad %}[{% endif %}{{ p.ad.plain_name }}{% if p.old_ad %}]{% endif %}</h2>
|
||||
|
||||
{% if p.discuss %}
|
||||
{% if p.pos.blocking and p.discuss %}
|
||||
<p><b>{{ p.pos.name }} ({{ p.discuss_time|date:"Y-m-d" }})</b> <img src="/images/comment.png" width="14" height="12" alt=""/></p>
|
||||
<pre>{{ p.discuss|wrap_text:80|escape }}</pre>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
{% extends "base.html" %}
|
||||
{% extends "idrfc/doc_main.html" %}
|
||||
{% comment extends "base.html" %}
|
||||
{% endcomment %}
|
||||
|
||||
{% load ietf_filters %}
|
||||
|
||||
|
@ -37,37 +39,25 @@
|
|||
<td><a href="/doc/help/state/charter/">Charter State</a>:</td>
|
||||
<td>
|
||||
<div>
|
||||
<a title="{{ doc.get_state.desc }}"{% if not snapshot and user|has_role:"Area Director,Secretariat" %} href="{% url charter_change_state name=doc.name %}"{% endif %}>{{ doc.get_state.name }}</a>
|
||||
{% if chartering == "initial" %}(Initial Chartering){% endif %}
|
||||
{% if chartering == "rechartering" %}(Rechartering){% endif %}
|
||||
<a title="{{ doc.get_state.desc }}"
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
|
||||
class="editlink" href="{% url charter_change_state name=doc.name %}"
|
||||
{% endif %}>
|
||||
{{ doc.get_state.name }}
|
||||
</a>
|
||||
{% if chartering == "initial" %} - (Initial Chartering){% endif %}
|
||||
{% if chartering == "rechartering" %} - (Rechartering){% endif %}
|
||||
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
|
||||
|
||||
|
||||
{% if chartering %}
|
||||
- <a href="{% url charter_startstop_process name=doc.name option='abandon' %}">Abandon effort</a>
|
||||
|
||||
{% if request.user|has_role:"Secretariat" %}
|
||||
- <a href="{% url charter_approve name=doc.name %}">Approve charter</a>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if group.state_id == "proposed" or group.state_id == "bof" %}
|
||||
- <a href="{% url charter_submit name=doc.name option='initcharter' %}">Start chartering</a>
|
||||
{% else %}
|
||||
- <a href="{% url charter_submit name=doc.name option='recharter' %}">Recharter</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not snapshot and chartering %}
|
||||
<div class="telechat">
|
||||
{% if not telechat %}Not on agenda of IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% endif %}
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
- <a href="{% url charter_telechat_date name=doc.name %}">Change</a>
|
||||
{% endif %}
|
||||
<a
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
class="editlink" href="{% url charter_telechat_date name=doc.name %}"
|
||||
{% endif %}>
|
||||
{% if not telechat %}Not on agenda of IESG telechat{% else %}On agenda of {{ telechat.telechat_date|date:"Y-m-d" }} IESG telechat{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% if ballot_summary %}
|
||||
|
@ -88,14 +78,20 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>Responsible AD:</td>
|
||||
<td><a {% if request.user|has_role:"Area Director,Secretariat" %}class="editlink" href="{% url charter_edit_ad name=doc.name %}"{% endif %}>{{ doc.ad|default:"none" }}</a> </td>
|
||||
</tr>
|
||||
|
||||
<tr><td colspan='2'><hr size='1' noshade /></td></tr>
|
||||
|
||||
<tr>
|
||||
<td>Send notices to:</td>
|
||||
<td>{{ doc.notify|default:"none" }}
|
||||
{% if user|has_role:"Area Director,Secretariat" %}
|
||||
- <a href="{% url charter_edit_notify name=doc.name %}">Change</a>
|
||||
{% endif %}
|
||||
<td><a {% if user|has_role:"Area Director,Secretariat" %}
|
||||
class="editlink" href="{% url charter_edit_notify name=doc.name %}"
|
||||
{% endif %}>
|
||||
{{ doc.notify|default:"none" }}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
@ -107,6 +103,26 @@
|
|||
<div class="actions">
|
||||
<a href="/feed/group-changes/{{ group.acronym }}/">Atom feed</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{% if not snapshot and user|has_role:"Area Director,Secretariat" %}
|
||||
{% if chartering %}
|
||||
<span id="charter_abandon_effort_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_startstop_process name=doc.name option='abandon' as abandon_url %}{% if abandon_url %}<span class="first-child"><a href="{{abandon_url}}">Abandon Effort</a></span>{% endif %}</span>
|
||||
|
||||
{% if request.user|has_role:"Secretariat" %}
|
||||
<span id="charter_approve_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_approve name=doc.name as approve_url %}{% if approve_url %}<span class="first-child"><a href="{{approve_url}}">Approve Charter</a></span>{% endif %}</span>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
{% if group.state_id == "proposed" or group.state_id == "bof" %}
|
||||
<span id="charter_start_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_submit name=doc.name option='initcharter' as start_url %}{% if start_url %}<span class="first-child"><a href="{{start_url}}">Start Chartering</a></span>{% endif %}</span>
|
||||
{% else %}
|
||||
<span id="charter_recharter_button" class="yui-button yui-link-button" style="margin-left:2px;margin-top:2px">{% url charter_submit name=doc.name option='recharter' as recharter_url %}{% if recharter_url %}<span class="first-child"><a href="{{recharter_url}}">Recharter</a></span>{% endif %}</span>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Other versions: <a href="{{ txt_url }}">plain text</a></p>
|
||||
|
|
|
@ -46,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #}
|
|||
.agenda blockquote { margin-left: 30px; width: 70ex; font-style:italic;}
|
||||
table.agenda-doc { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
|
||||
table.agenda-doc > tbody > tr { vertical-align:top; }
|
||||
div.agenda-wg { margin-left: 30px; margin-top:0.5em; margin-bottom: 0.5em; width: 95%; }
|
||||
{% endblock morecss %}
|
||||
|
||||
{% block pagehead %}
|
||||
|
|
|
@ -131,6 +131,22 @@ font-size:80%; font-style:italic;
|
|||
{% if t.docs.s333 %}<tr class="header"><td colspan="6">3.3.3 For Action</td></tr>{% endif %}
|
||||
{% for doc in t.docs.s333 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
|
||||
|
||||
<tr class="header"><td colspan="6">4. Working Group Actions</td></tr>
|
||||
|
||||
{% if t.docs.s411 or t.docs.s412%}<tr class="header"><td colspan="6">4.1 WG Creation</td></tr>{% endif %}
|
||||
|
||||
{% if t.docs.s411 %}<tr class="header"><td colspan="6">4.1.1 Proposed for IETF Review</td></tr>{% endif %}
|
||||
{% for doc in t.docs.s411 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
|
||||
{% if t.docs.s412 %}<tr class="header"><td colspan="6">4.1.2 Proposed for Approval</td></tr>{% endif %}
|
||||
{% for doc in t.docs.s412 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
|
||||
|
||||
{% if t.docs.s421 or t.docs.s422 %}<tr class="header"><td colspan="6">4.2 WG Rechartering</td></tr>{% endif %}
|
||||
|
||||
{% if t.docs.s421 %}<tr class="header"><td colspan="6">4.2.1 Under Evaluation for IETF Review</td></tr>{% endif %}
|
||||
{% for doc in t.docs.s421 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
|
||||
{% if t.docs.s422 %}<tr class="header"><td colspan="6">4.2.2 Proposed for Approval</td></tr>{% endif %}
|
||||
{% for doc in t.docs.s422 %}{% include "iesg/agenda_documents_row_redesign.html" %}{%endfor%}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
|
|
|
@ -39,6 +39,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
<tr
|
||||
{% if user|in_group:"Area_Director" %}
|
||||
{% if doc|my_position:user|equal:"Discuss" %}style="background:#ffa0a0;"{% endif %}
|
||||
{% if doc|my_position:user|equal:"Block" %}style="background:#ffa0a0;"{% endif %}
|
||||
{% if doc|my_position:user|equal:"Abstain" %}style="background:#ffff00;"{% endif %}
|
||||
{% if doc|my_position:user|equal:"Yes" or doc|my_position:user|slugify|equal:"no-objection" %}style="background:#a0ffa0;"{% endif %}
|
||||
{% if doc|my_position:user|equal:"Recuse" %}style="background:#c0c0c0;"{% endif %}
|
||||
|
|
|
@ -31,30 +31,24 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
{% endcomment %}
|
||||
{% load ballot_icon_redesign %}
|
||||
{% if title2_first %}{% if title1_first %}<h2>{{ title1 }}</h2>
|
||||
{% endif %}
|
||||
<h3>{{ title2 }}</h3>
|
||||
{% endif %}<h4>{{ title3 }}</h4>
|
||||
|
||||
{% for wg in section_wgs %}
|
||||
{% if forloop.first %}
|
||||
<table>
|
||||
<tr><th>Area</th><th>Date</th><th></th></tr>
|
||||
{% endif %}
|
||||
|
||||
<tr>
|
||||
<td>{{ wg.obj.parent.acronym|upper }}</td>
|
||||
<td>{{ wg.obj.time|date:"M d"}}</td>
|
||||
<td>
|
||||
<a href="{{ wg.obj.txt_link }}">
|
||||
{{ wg.obj.name|escape }} ({{wg.obj.acronym}})
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{% if forloop.last %}
|
||||
</table>
|
||||
{% endif %}
|
||||
<div class="agenda-wg">
|
||||
<span width="30%" style="float:right;">
|
||||
{% ballot_icon wg.doc %}
|
||||
</span>
|
||||
<span width="30%">
|
||||
<div> <a href="{{ wg.doc.get_absolute_url }}">{{ wg.doc.name}}-({{wg.doc.rev}})</a> <a href="{{ settings.CHARTER_TXT_URL }}{{ wg.doc.filename_with_rev }}">[txt]</a> </div>
|
||||
<div>{{ wg.doc.group.name|escape }} ({{wg.doc.group.acronym}})</div>
|
||||
<div>Area: {{ wg.doc.group.parent.acronym|upper }} ({{ wg.doc.ad|default:"Sponsoring AD not assigned" }})</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% empty %}
|
||||
<p>NONE</p>
|
||||
|
|
|
@ -40,19 +40,21 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
{{ title2 }}<br>
|
||||
{{ title3 }} ({{ forloop.counter }} of {{ section_docs|length }})</h3>
|
||||
|
||||
<p><b>{{doc.obj.document.filename}}{% if not doc.obj.rfc_flag %}-{{doc.obj.document.revision}}{% endif %}</b><br>
|
||||
<i>({{ doc.obj.document.title|escape }})</i><br>
|
||||
<b>Intended status: {{ doc.obj.document.intended_status }}<br>
|
||||
Token: {{ doc.obj.token_name|escape }}<br>
|
||||
Last call ends: {{ doc.obj.document.lc_expiration_date|default:"(none)" }}</b></p>
|
||||
<p><b>{{doc.obj.name}}-{{doc.obj.rev}}</b><br>
|
||||
<i>({{ doc.obj.title|escape }})</i><br>
|
||||
<b>Intended status: {{ doc.obj.intended_std_level }}<br>
|
||||
Token: {{ doc.obj.ad.plain_name|escape }}<br>
|
||||
{% if doc.obj.type.slug == "draft" %}
|
||||
Last call ends: {{ doc.obj.most_recent_ietflc.expires.date|default:"(none)" }}
|
||||
{% if doc.obj.most_recent_ietflc.expires.date|timesince_days < 3 %}!!!{% endif %}
|
||||
{% endif %}</b></p>
|
||||
|
||||
{% if doc.obj.ballot.active %}
|
||||
{% filter linebreaks_crlf %}<small><pre>
|
||||
Yes No-Objection Discuss Abstain
|
||||
{% for curpos in doc.obj.ballot.active_positions %}{{ curpos.ad|ljust:"20" }} {{ curpos.pos.yes|bracket }} {{ curpos.pos.noobj|bracket }} {{ curpos.pos.discuss|bracket }} {{ curpos.pos.abstain_ind|bracket }}
|
||||
{% if doc.obj.active_ballot %}
|
||||
<small><pre>
|
||||
Yes No-Objection Discuss Abstain Recuse
|
||||
{% for pos in doc.obj.active_ballot.all_positions %}{% if pos.old_ad %}{{pos.ad.plain_name|bracket|ljust:"22"}}{%else%}{{pos.ad.plain_name|ljust:"22"}}{%endif%} {{pos|bracketpos:"yes"}} {{pos|bracketpos:"noobj"}} {{pos|bracketpos:"discuss"}} {{pos|bracketpos:"abstain"}} {{pos|bracketpos:"recuse"}}
|
||||
{% endfor %}
|
||||
{% for position in doc.obj.ballot.positions.all|dictsort:"ad.last_name" %}{% if not position.ad.is_current_ad %}{{ position.ad|ljust:"20" }} {{ position.yes|bracket }} {{ position.noobj|bracket }} {{ position.discuss|bracket }} {{ position.abstain_ind|bracket }}
|
||||
{% endif %}{% endfor %}</pre></small>{% endfilter %}
|
||||
</pre></small>
|
||||
|
||||
{% if title1|startswith:"2." %}
|
||||
<p>____ open positions<br>
|
||||
|
@ -67,16 +69,16 @@ Last call ends: {{ doc.obj.document.lc_expiration_date|default:"(none)" }}</b></
|
|||
{% endif %}
|
||||
|
||||
{% if title2|startswith:"3.1" or title2|startswith:"3.2" %}
|
||||
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.document.intended_status }} RFC?</p>
|
||||
<p>Does anyone have an[y further] objection to this document being published as an {{ doc.obj.intended_std_level }} RFC?</p>
|
||||
{% endif %}
|
||||
{% if title3|startswith:"3.3.1" or title3|startswith:"3.3.2" %}
|
||||
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.document.intended_status }} RFC?</p>
|
||||
<p>Does anyone have an objection to the RFC Editor publishing this document as an {{ doc.obj.intended_std_level }} RFC?</p>
|
||||
{% endif %}
|
||||
{% if title3|startswith:"3.3.3" %}
|
||||
<p>Who will do the review of this document?</p>
|
||||
{% endif %}
|
||||
|
||||
<p>Current State: {{ doc.obj.cur_state }}, sub state: {{ doc.obj.cur_sub_state|default:"(none)" }}<br>
|
||||
<p>Current State: {{ doc.obj.friendly_state }}<br>
|
||||
Next State:<br>
|
||||
Sub State: </p>
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ teleconference. The Secretariat will post them in the public archive.</p>
|
|||
{{ minutes }}
|
||||
</pre>{% endfilter %}
|
||||
|
||||
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telehat</h3>
|
||||
<h3>1. Administrivia<br>1.4 List of Remaining Action Items from Last Telechat</h3>
|
||||
|
||||
{% filter linebreaks_crlf %}<pre>
|
||||
{{ action_items }}
|
||||
|
|
|
@ -65,7 +65,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
{% if doc.obj.active_ballot %}
|
||||
<br/><b>Discusses/comments</b> <a href="http://datatracker.ietf.org/idtracker/ballot/{{doc.obj.canonical_name}}/">[ballot]</a>:
|
||||
<ul>
|
||||
{% for p in doc.obj.active_ballot_positions %}
|
||||
{% for p in doc.obj.active_ballot.active_ad_positions.values %}
|
||||
{% if p.pos %}
|
||||
{% if p.discuss %}
|
||||
<li>
|
||||
|
|
|
@ -40,7 +40,7 @@ Some parts Copyright (c) 2009 The IETF Trust, all rights reserved.
|
|||
|
||||
{% if doc.obj.active_ballot %}
|
||||
<ul>
|
||||
{% for p in doc.obj.active_ballot_positions %}
|
||||
{% for p in doc.obj.active_ballot.active_ad_positions.values %}
|
||||
{% if p.pos and p.discuss %}
|
||||
<li>
|
||||
<a name="{{doc.obj.name}}+{{p.ad|slugify}}+discuss">{{ p.ad }}: Discuss [{{ p.discuss_time }}]</a>:
|
||||
|
|
39
ietf/templates/wgcharter/change_ad.html
Normal file
39
ietf/templates/wgcharter/change_ad.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block morecss %}
|
||||
.warning {
|
||||
font-weight: bold;
|
||||
color: #a00;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
Change the responsible AD for {{ charter.canonical_name }}-{{ charter.rev }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Change the responsible AD for {{ charter.canonical_name }}-{{ charter.rev }}</h1>
|
||||
|
||||
<form class="edit-info" action="" enctype="multipart/form-data" method="POST">
|
||||
<table>
|
||||
{% for field in form.visible_fields %}
|
||||
<tr>
|
||||
<th>{{ field.label_tag }}:</th>
|
||||
<td>
|
||||
{{ field }}
|
||||
{% if field.help_text %}<div class="help">{{ field.help_text }}</div>{% endif %}
|
||||
{{ field.errors }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="actions">
|
||||
<a href="{% url doc_view name=charter.canonical_name %}">Back</a>
|
||||
<input type="submit" value="Submit"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -132,6 +132,29 @@ class EditCharterTestCase(django.test.TestCase):
|
|||
charter = Document.objects.get(name=charter.name)
|
||||
self.assertEquals(charter.notify, "someone@example.com, someoneelse@example.com")
|
||||
|
||||
def test_edit_ad(self):
|
||||
make_test_data()
|
||||
|
||||
charter = Group.objects.get(acronym="mars").charter
|
||||
|
||||
url = urlreverse('charter_edit_ad', kwargs=dict(name=charter.name))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
# normal get
|
||||
r = self.client.get(url)
|
||||
self.assertEquals(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEquals(len(q('select[name=ad]')),1)
|
||||
|
||||
# post
|
||||
self.assertTrue(not charter.ad)
|
||||
ad2 = Person.objects.get(name='Ad No2')
|
||||
r = self.client.post(url,dict(ad=str(ad2.pk)))
|
||||
self.assertEquals(r.status_code, 302)
|
||||
|
||||
charter = Document.objects.get(name=charter.name)
|
||||
self.assertEquals(charter.ad, ad2)
|
||||
|
||||
def test_submit_charter(self):
|
||||
make_test_data()
|
||||
|
||||
|
@ -224,7 +247,7 @@ class CharterApproveBallotTestCase(django.test.TestCase):
|
|||
|
||||
charter = Document.objects.get(name=charter.name)
|
||||
self.assertEquals(charter.get_state_slug(), "approved")
|
||||
self.assertTrue(not ballot_open(charter, "approve"))
|
||||
self.assertTrue(not charter.ballot_open("approve"))
|
||||
|
||||
self.assertEquals(charter.rev, "01")
|
||||
self.assertTrue(os.path.exists(os.path.join(self.charter_dir, "charter-ietf-%s-%s.txt" % (group.acronym, charter.rev))))
|
||||
|
|
|
@ -7,6 +7,7 @@ urlpatterns = patterns('',
|
|||
url(r'^(?P<option>initcharter|recharter|abandon)/$', "ietf.wgcharter.views.change_state", name='charter_startstop_process'),
|
||||
url(r'^telechat/$', "ietf.wgcharter.views.telechat_date", name='charter_telechat_date'),
|
||||
url(r'^notify/$', "ietf.wgcharter.views.edit_notify", name='charter_edit_notify'),
|
||||
url(r'^ad/$', "ietf.wgcharter.views.edit_ad", name='charter_edit_ad'),
|
||||
url(r'^(?P<ann>action|review)/$', "ietf.wgcharter.views.announcement_text", name="charter_edit_announcement"),
|
||||
url(r'^ballotwriteupnotes/$', "ietf.wgcharter.views.ballot_writeupnotes"),
|
||||
url(r'^approve/$', "ietf.wgcharter.views.approve", name='charter_approve'),
|
||||
|
|
|
@ -267,6 +267,53 @@ def edit_notify(request, name):
|
|||
login=login),
|
||||
context_instance=RequestContext(request))
|
||||
|
||||
class AdForm(forms.Form):
|
||||
ad = forms.ModelChoiceField(Person.objects.filter(role__name="ad", role__group__state="active").order_by('name'),
|
||||
label="Responsible AD", empty_label="(None)", required=True)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
|
||||
# if previous AD is now ex-AD, append that person to the list
|
||||
ad_pk = self.initial.get('ad')
|
||||
choices = self.fields['ad'].choices
|
||||
if ad_pk and ad_pk not in [pk for pk, name in choices]:
|
||||
self.fields['ad'].choices = list(choices) + [("", "-------"), (ad_pk, Person.objects.get(pk=ad_pk).plain_name())]
|
||||
|
||||
@role_required("Area Director", "Secretariat")
|
||||
def edit_ad(request, name):
|
||||
"""Change the responsible Area Director for this charter."""
|
||||
|
||||
charter = get_object_or_404(Document, type="charter", name=name)
|
||||
login = request.user.get_profile()
|
||||
|
||||
if request.method == 'POST':
|
||||
form = AdForm(request.POST)
|
||||
if form.is_valid():
|
||||
new_ad = form.cleaned_data['ad']
|
||||
if new_ad != charter.ad:
|
||||
save_document_in_history(charter)
|
||||
e = DocEvent(doc=charter, by=login)
|
||||
e.desc = "Responsible AD changed to %s" % new_ad.plain_name()
|
||||
if charter.ad:
|
||||
e.desc += " from %s" % charter.ad.plain_name()
|
||||
e.type = "changed_document"
|
||||
e.save()
|
||||
charter.ad = new_ad
|
||||
charter.time = e.time
|
||||
charter.save()
|
||||
|
||||
return HttpResponseRedirect(reverse('doc_view', kwargs={'name': charter.name}))
|
||||
else:
|
||||
init = { "ad" : charter.ad_id }
|
||||
form = AdForm(initial=init)
|
||||
|
||||
return render_to_response('wgcharter/change_ad.html',
|
||||
{'form': form,
|
||||
'charter': charter,
|
||||
},
|
||||
context_instance = RequestContext(request))
|
||||
|
||||
|
||||
class UploadForm(forms.Form):
|
||||
content = forms.CharField(widget=forms.Textarea, label="Charter text", help_text="Edit the charter text", required=False)
|
||||
|
|
|
@ -209,7 +209,7 @@
|
|||
updateReplyTo();
|
||||
};
|
||||
|
||||
var updateInfo = function(first_time) {
|
||||
var updateInfo = function(first_time, sender) {
|
||||
var entity = organization;
|
||||
var to_entity = from;
|
||||
if (!entity.is('select') || !to_entity.is('select')) {
|
||||
|
@ -232,7 +232,9 @@
|
|||
render_mails_into(poc, response.poc, true);
|
||||
toggleApproval(response.needs_approval);
|
||||
checkPostOnly(response.post_only);
|
||||
userSelect(response.full_list);
|
||||
if (sender == 'from') {
|
||||
userSelect(response.full_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -330,7 +332,7 @@
|
|||
var checkFrom = function(first_time) {
|
||||
var reduce_options = form.find('.reducedToOptions');
|
||||
if (!reduce_options.length) {
|
||||
updateInfo(first_time);
|
||||
updateInfo(first_time, 'from');
|
||||
return;
|
||||
}
|
||||
var to_select = organization;
|
||||
|
@ -351,7 +353,7 @@
|
|||
to_select.find('optgroup').show();
|
||||
to_select.find('option').show();
|
||||
}
|
||||
updateInfo(first_time);
|
||||
updateInfo(first_time, 'from');
|
||||
};
|
||||
|
||||
var checkSubmissionDate = function() {
|
||||
|
@ -366,7 +368,7 @@
|
|||
};
|
||||
|
||||
var initTriggers = function() {
|
||||
organization.change(function() {updateInfo(false);});
|
||||
organization.change(function() {updateInfo(false, 'to');});
|
||||
organization.change(checkOtherSDO);
|
||||
from.change(function() {checkFrom(false);});
|
||||
reply.keyup(updateFrom);
|
||||
|
|
Loading…
Reference in a new issue